aboutsummaryrefslogtreecommitdiff
path: root/src/opcodes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/opcodes.rs')
-rw-r--r--src/opcodes.rs1276
1 files changed, 651 insertions, 625 deletions
diff --git a/src/opcodes.rs b/src/opcodes.rs
index f238239..2502782 100644
--- a/src/opcodes.rs
+++ b/src/opcodes.rs
@@ -1,825 +1,851 @@
+use crate::serial::Serial;
use crate::state::{flag, reg, GBState, MemError};
// The opcodes functions are returning the number of cycles used.
-pub fn r_16b_from_pc(state: &mut GBState) -> Result<u16, MemError> {
- let p: u16 = state.mem.r(state.cpu.pc)? as u16 | ((state.mem.r(state.cpu.pc + 1)? as u16) << 8);
- state.cpu.pc += 2;
+impl GBState {
+ fn r_16b_from_pc(&mut self) -> Result<u16, MemError> {
+ let p: u16 = self.mem.r(self.cpu.pc)? as u16 | ((self.mem.r(self.cpu.pc + 1)? as u16) << 8);
+ self.cpu.pc += 2;
- Ok(p)
-}
+ Ok(p)
+ }
-pub fn r_8b_from_pc(state: &mut GBState) -> Result<u8, MemError> {
- let p = state.mem.r(state.cpu.pc)?;
- state.cpu.pc += 1;
+ fn r_8b_from_pc(&mut self) -> Result<u8, MemError> {
+ let p = self.mem.r(self.cpu.pc)?;
+ self.cpu.pc += 1;
- Ok(p)
-}
+ Ok(p)
+ }
-pub fn ldrr(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> {
- // Load a register into another register
- // LD r, r
- state.w_reg(n1, state.r_reg(n2)?)
-}
+ fn ldrr(&mut self, n1: u8, n2: u8) -> Result<(), MemError> {
+ // Load a register into another register
+ // LD r, r
+ self.w_reg(n1, self.r_reg(n2)?)
+ }
-pub fn ldr8(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- // Load an raw 8b value into a register
- let p = r_8b_from_pc(state)?;
+ fn ldr8(&mut self, n1: u8) -> Result<u64, MemError> {
+ // Load an raw 8b value into a register
+ let p = self.r_8b_from_pc()?;
- state.w_reg(n1, p)?;
- Ok(8)
-}
+ self.w_reg(n1, p)?;
+ Ok(8)
+ }
-pub fn ldrr16(state: &mut GBState, rr: u8, x: u16) {
- // Load a raw 16b value into a register
- state.cpu.w16(rr, x);
-}
+ fn ldrr16(&mut self, rr: u8, x: u16) {
+ // Load a raw 16b value into a register
+ self.cpu.w16(rr, x);
+ }
-pub fn ldnnsp(state: &mut GBState) -> Result<u64, MemError> {
- // Load SP into an arbitrary position in memory
- let p = r_16b_from_pc(state)?;
+ fn ldnnsp(&mut self) -> Result<u64, MemError> {
+ // Load SP into an arbitrary position in memory
+ let p = self.r_16b_from_pc()?;
- state.mem.w(p, (state.cpu.sp & 0xff) as u8)?;
- state.mem.w(p + 1, (state.cpu.sp >> 8) as u8)?;
- Ok(20)
-}
+ self.mem.w(p, (self.cpu.sp & 0xff) as u8)?;
+ self.mem.w(p + 1, (self.cpu.sp >> 8) as u8)?;
+ Ok(20)
+ }
-pub fn ldsphl(state: &mut GBState) -> u64 {
- state.cpu.sp = state.cpu.r16(reg::HL);
- 8
-}
+ fn ldsphl(&mut self) -> u64 {
+ self.cpu.sp = self.cpu.r16(reg::HL);
+ 8
+ }
-pub fn ldnna(state: &mut GBState, nn: u16) -> Result<(), MemError> {
- // Load A into an arbitrary position in memory
- state.mem.w(nn, state.cpu.r[reg::A as usize])?;
- Ok(())
-}
+ fn ldnna(&mut self, nn: u16) -> Result<(), MemError> {
+ // Load A into an arbitrary position in memory
+ self.mem.w(nn, self.cpu.r[reg::A as usize])?;
+ Ok(())
+ }
-pub fn ldann(state: &mut GBState, nn: u16) -> Result<(), MemError> {
- // Load A from an arbitrary position in memory
- state.cpu.r[reg::A as usize] = state.mem.r(nn)?;
- Ok(())
-}
+ fn ldann(&mut self, nn: u16) -> Result<(), MemError> {
+ // Load A from an arbitrary position in memory
+ self.cpu.r[reg::A as usize] = self.mem.r(nn)?;
+ Ok(())
+ }
-pub fn push(state: &mut GBState, x: u16) -> Result<(), MemError> {
- state.cpu.sp -= 2;
+ pub fn push(&mut self, x: u16) -> Result<(), MemError> {
+ self.cpu.sp -= 2;
- state.mem.w(state.cpu.sp, (x & 0xff) as u8)?;
+ self.mem.w(self.cpu.sp, (x & 0xff) as u8)?;
- state.mem.w(state.cpu.sp + 1, (x >> 8) as u8)?;
+ self.mem.w(self.cpu.sp + 1, (x >> 8) as u8)?;
- Ok(())
-}
+ Ok(())
+ }
-pub fn pop(state: &mut GBState) -> Result<u16, MemError> {
- let res = state.mem.r(state.cpu.sp)? as u16 | ((state.mem.r(state.cpu.sp + 1)? as u16) << 8);
+ fn pop(&mut self) -> Result<u16, MemError> {
+ let res = self.mem.r(self.cpu.sp)? as u16 | ((self.mem.r(self.cpu.sp + 1)? as u16) << 8);
- state.cpu.sp += 2;
+ self.cpu.sp += 2;
- Ok(res)
-}
+ Ok(res)
+ }
-pub fn jr8(state: &mut GBState) -> Result<u64, MemError> {
- // Unconditional relative jump
- let p = r_8b_from_pc(state)?;
+ fn jr8(&mut self) -> Result<u64, MemError> {
+ // Unconditional relative jump
+ let p = self.r_8b_from_pc()?;
- state.cpu.pc = (state.cpu.pc as i16 + p as i8 as i16) as u16;
+ self.cpu.pc = (self.cpu.pc as i16 + p as i8 as i16) as u16;
- Ok(12)
-}
+ Ok(12)
+ }
+
+ fn jrcc8(&mut self, n1: u8) -> Result<u64, MemError> {
+ // Conditional relative jump
+ let p = self.r_8b_from_pc()?;
+ let mut cycles = 8;
-pub fn jrcc8(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- // Conditional relative jump
- let p = r_8b_from_pc(state)?;
- let mut cycles = 8;
+ if self.cpu.check_flag(n1 & 0b11) {
+ cycles += 4;
+ self.cpu.pc = (self.cpu.pc as i16 + p as i8 as i16) as u16;
+ }
- if state.cpu.check_flag(n1 & 0b11) {
- cycles += 4;
- state.cpu.pc = (state.cpu.pc as i16 + p as i8 as i16) as u16;
+ Ok(cycles)
}
- Ok(cycles)
-}
+ fn jp16(&mut self) -> Result<u64, MemError> {
+ // Unconditional absolute jump
+ let p = self.r_16b_from_pc()?;
-pub fn jp16(state: &mut GBState) -> Result<u64, MemError> {
- // Unconditional absolute jump
- let p = r_16b_from_pc(state)?;
+ self.cpu.pc = p;
- state.cpu.pc = p;
+ Ok(16)
+ }
- Ok(16)
-}
+ fn jphl(&mut self) -> u64 {
+ // Unconditional absolute jump to HL
+ self.cpu.pc = self.cpu.r16(reg::HL);
-pub fn jphl(state: &mut GBState) -> u64 {
- // Unconditional absolute jump to HL
- state.cpu.pc = state.cpu.r16(reg::HL);
+ 4
+ }
- 4
-}
+ fn jpcc16(&mut self, n1: u8) -> Result<u64, MemError> {
+ // Conditional absolute jump
+ let p = self.r_16b_from_pc()?;
+ let mut cycles = 8;
-pub fn jpcc16(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- // Conditional absolute jump
- let p = r_16b_from_pc(state)?;
- let mut cycles = 8;
+ if self.cpu.check_flag(n1 & 0b11) {
+ cycles += 4;
+ self.cpu.pc = p;
+ }
- if state.cpu.check_flag(n1 & 0b11) {
- cycles += 4;
- state.cpu.pc = p;
+ Ok(cycles)
}
- Ok(cycles)
-}
+ fn call(&mut self) -> Result<u64, MemError> {
+ // Unconditional function call
+ let p = self.r_16b_from_pc()?;
-pub fn call(state: &mut GBState) -> Result<u64, MemError> {
- // Unconditional function call
- let p = r_16b_from_pc(state)?;
+ self.push(self.cpu.pc)?;
+ self.cpu.pc = p;
- push(state, state.cpu.pc)?;
- state.cpu.pc = p;
+ Ok(24)
+ }
- Ok(24)
-}
+ fn callcc(&mut self, n1: u8) -> Result<u64, MemError> {
+ // Conditional function call
+ let p = self.r_16b_from_pc()?;
+ let mut cycles = 12;
-pub fn callcc(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- // Conditional function call
- let p = r_16b_from_pc(state)?;
- let mut cycles = 12;
+ if self.cpu.check_flag(n1 & 0b11) {
+ cycles += 12;
+ self.push(self.cpu.pc)?;
+ self.cpu.pc = p;
+ }
- if state.cpu.check_flag(n1 & 0b11) {
- cycles += 12;
- push(state, state.cpu.pc)?;
- state.cpu.pc = p;
+ Ok(cycles)
}
- Ok(cycles)
-}
+ fn ret(&mut self) -> Result<u64, MemError> {
+ let res = self.pop()?;
+
+ if res == 0 {
+ println!("DEBUG: {:?}", self.cpu);
+ panic!("RET to start");
+ }
-pub fn ret(state: &mut GBState) -> Result<u64, MemError> {
- let res = pop(state)?;
+ self.cpu.pc = res;
- if res == 0 {
- println!("DEBUG: {:?}", state.cpu);
- panic!("RET to start");
+ Ok(16)
}
- state.cpu.pc = res;
-
- Ok(16)
-}
+ fn retcc(&mut self, n1: u8) -> Result<u64, MemError> {
+ let mut cycles = 8;
+ if self.cpu.check_flag(n1 & 0b11) {
+ cycles += 12;
+ self.cpu.pc = self.pop()?;
+ }
-pub fn retcc(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- let mut cycles = 8;
- if state.cpu.check_flag(n1 & 0b11) {
- cycles += 12;
- state.cpu.pc = pop(state)?;
+ Ok(cycles)
}
- Ok(cycles)
-}
+ fn ld00a(&mut self, n1: u8) -> Result<u64, MemError> {
+ // Load register A into or from memory pointed by rr (BC, DE or HL(+/-))
+ // LD (rr), A
+ // LD A, (rr)
+ let ptr_reg = match n1 & 0b110 {
+ 0b000 => reg::B,
+ 0b010 => reg::C,
+ _ => reg::HL,
+ };
-pub fn ld00a(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- // Load register A into or from memory pointed by rr (BC, DE or HL(+/-))
- // LD (rr), A
- // LD A, (rr)
- let ptr_reg = match n1 & 0b110 {
- 0b000 => reg::B,
- 0b010 => reg::C,
- _ => reg::HL,
- };
+ if n1 & 0b001 == 1 {
+ self.cpu.r[reg::A as usize] = self.mem.r(self.cpu.r16(ptr_reg))?;
+ } else {
+ self.mem
+ .w(self.cpu.r16(ptr_reg), self.cpu.r[reg::A as usize])?;
+ }
- if n1 & 0b001 == 1 {
- state.cpu.r[reg::A as usize] = state.mem.r(state.cpu.r16(ptr_reg))?;
- } else {
- state
- .mem
- .w(state.cpu.r16(ptr_reg), state.cpu.r[reg::A as usize])?;
- }
+ if n1 & 0b110 == 0b100 {
+ self.cpu.w16(reg::HL, self.cpu.r16(reg::HL) + 1); // (HL+)
+ }
- if n1 & 0b110 == 0b100 {
- state.cpu.w16(reg::HL, state.cpu.r16(reg::HL) + 1); // (HL+)
- }
+ if n1 & 0b110 == 0b110 {
+ self.cpu.w16(reg::HL, self.cpu.r16(reg::HL) - 1); // (HL-)
+ }
- if n1 & 0b110 == 0b110 {
- state.cpu.w16(reg::HL, state.cpu.r16(reg::HL) - 1); // (HL-)
+ Ok(8)
}
- Ok(8)
-}
+ fn inc8(&mut self, n1: u8) -> Result<u64, MemError> {
+ // Increment 8 bit register
+ self.w_reg(n1, self.r_reg(n1)? + 1)?;
+ self.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF | flag::H);
+ if self.r_reg(n1)? == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
-pub fn inc8(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- // Increment 8 bit register
- state.w_reg(n1, state.r_reg(n1)? + 1)?;
- state.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF | flag::H);
- if state.r_reg(n1)? == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
- }
+ if self.r_reg(n1)? & 0xf == 0x0 {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
- if state.r_reg(n1)? & 0xf == 0x0 {
- state.cpu.r[reg::F as usize] |= flag::H;
+ Ok(4)
}
- Ok(4)
-}
+ fn dec8(&mut self, n1: u8) -> Result<u64, MemError> {
+ // Decrement 8 bit register
+ self.w_reg(n1, self.r_reg(n1)? - 1)?;
+ self.cpu.r[reg::F as usize] |= flag::N;
+
+ self.cpu.r[reg::F as usize] &= !(flag::ZF | flag::H);
+ if self.r_reg(n1)? == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
-pub fn dec8(state: &mut GBState, n1: u8) -> Result<u64, MemError> {
- // Decrement 8 bit register
- state.w_reg(n1, state.r_reg(n1)? - 1)?;
- state.cpu.r[reg::F as usize] |= flag::N;
+ if self.r_reg(n1)? & 0xf == 0xf {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
- state.cpu.r[reg::F as usize] &= !(flag::ZF | flag::H);
- if state.r_reg(n1)? == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ Ok(4)
}
- if state.r_reg(n1)? & 0xf == 0xf {
- state.cpu.r[reg::F as usize] |= flag::H;
+ fn inc16(&mut self, rr: u8) -> u64 {
+ // Increment 16 bit register
+ self.cpu.w16(rr, self.cpu.r16(rr) + 1);
+ 8
}
- Ok(4)
-}
+ fn dec16(&mut self, rr: u8) -> u64 {
+ // Decrement 16 bit register
+ self.cpu.w16(rr, self.cpu.r16(rr) - 1);
+ 8
+ }
-pub fn inc16(state: &mut GBState, rr: u8) -> u64 {
- // Increment 16 bit register
- state.cpu.w16(rr, state.cpu.r16(rr) + 1);
- 8
-}
+ fn ccf(&mut self) {
+ // Flip carry flag
+ self.cpu.r[reg::F as usize] = (self.cpu.r[reg::F as usize] & 0b10011111) ^ 0b00010000
+ }
-pub fn dec16(state: &mut GBState, rr: u8) -> u64 {
- // Decrement 16 bit register
- state.cpu.w16(rr, state.cpu.r16(rr) - 1);
- 8
-}
+ fn scf(&mut self) {
+ // Set carry flag
+ self.cpu.r[reg::F as usize] = (self.cpu.r[reg::F as usize] & 0b10011111) | 0b00010000
+ }
-pub fn ccf(state: &mut GBState) {
- // Flip carry flag
- state.cpu.r[reg::F as usize] = (state.cpu.r[reg::F as usize] & 0b10011111) ^ 0b00010000
-}
+ fn daa(&mut self) {
+ // Decimal Adjust Accumulator
+ // Adjust the A register after a addition or substraction to keep valid BCD representation
+ let nibble_low = self.cpu.r[reg::A as usize] & 0b1111;
+ let sub_flag = (self.cpu.r[reg::F as usize] & flag::N) != 0;
+ let half_carry_flag = (self.cpu.r[reg::F as usize] & flag::H) != 0;
-pub fn scf(state: &mut GBState) {
- // Set carry flag
- state.cpu.r[reg::F as usize] = (state.cpu.r[reg::F as usize] & 0b10011111) | 0b00010000
-}
+ if (half_carry_flag || nibble_low > 9) && !sub_flag {
+ self.cpu.r[reg::A as usize] += 0x06;
+ }
+ if (half_carry_flag || nibble_low > 9) && sub_flag {
+ self.cpu.r[reg::A as usize] -= 0x06;
+ }
-pub fn daa(state: &mut GBState) {
- // Decimal Adjust Accumulator
- // Adjust the A register after a addition or substraction to keep valid BCD representation
- let nibble_low = state.cpu.r[reg::A as usize] & 0b1111;
- let sub_flag = (state.cpu.r[reg::F as usize] & flag::N) != 0;
- let half_carry_flag = (state.cpu.r[reg::F as usize] & flag::H) != 0;
+ let nibble_high = self.cpu.r[reg::A as usize] >> 4;
- if (half_carry_flag || nibble_low > 9) && !sub_flag {
- state.cpu.r[reg::A as usize] += 0x06;
- }
- if (half_carry_flag || nibble_low > 9) && sub_flag {
- state.cpu.r[reg::A as usize] -= 0x06;
- }
+ self.cpu.r[reg::F as usize] &= !(flag::CY | flag::ZF);
- let nibble_high = state.cpu.r[reg::A as usize] >> 4;
+ if nibble_high > 9 && !sub_flag {
+ self.cpu.r[reg::A as usize] += 0x60;
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
+ if nibble_high > 9 && sub_flag {
+ self.cpu.r[reg::A as usize] -= 0x60;
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
- state.cpu.r[reg::F as usize] &= !(flag::CY | flag::ZF);
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
- if nibble_high > 9 && !sub_flag {
- state.cpu.r[reg::A as usize] += 0x60;
- state.cpu.r[reg::F as usize] |= flag::CY;
- }
- if nibble_high > 9 && sub_flag {
- state.cpu.r[reg::A as usize] -= 0x60;
- state.cpu.r[reg::F as usize] |= flag::CY;
+ self.cpu.r[reg::F as usize] &= !flag::H;
}
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ fn cpl(&mut self) {
+ // Flip all bits in register A
+ self.cpu.r[reg::F as usize] = self.cpu.r[reg::F as usize] | flag::N | flag::H;
+ self.cpu.r[reg::A as usize] ^= 0xff;
}
- state.cpu.r[reg::F as usize] &= !flag::H;
-}
+ fn addsp8(&mut self) -> Result<u64, MemError> {
+ let n = self.r_8b_from_pc()? as i8;
-pub fn cpl(state: &mut GBState) {
- // Flip all bits in register A
- state.cpu.r[reg::F as usize] = state.cpu.r[reg::F as usize] | flag::N | flag::H;
- state.cpu.r[reg::A as usize] ^= 0xff;
-}
-
-pub fn addsp8(state: &mut GBState) -> Result<u64, MemError> {
- let n = r_8b_from_pc(state)? as i8;
+ self.cpu.sp = (self.cpu.sp as i32 + n as i32) as u16;
- state.cpu.sp = (state.cpu.sp as i32 + n as i32) as u16;
+ self.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY);
- state.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY);
+ if (self.cpu.sp & 0xff) as i32 + n as i32 & !0xff != 0 {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
- if (state.cpu.sp & 0xff) as i32 + n as i32 & !0xff != 0 {
- state.cpu.r[reg::F as usize] |= flag::H;
+ if (self.cpu.sp as i32 + n as i32) & !0xffff != 0 {
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
+ Ok(16)
}
- if (state.cpu.sp as i32 + n as i32) & !0xffff != 0 {
- state.cpu.r[reg::F as usize] |= flag::CY;
- }
- Ok(16)
-}
+ fn add(&mut self, x: u8) {
+ // ADD a number to A and store the result in A
+ let res = x as u16 + self.cpu.r[reg::A as usize] as u16;
-pub fn add(state: &mut GBState, x: u8) {
- // ADD a number to A and store the result in A
- let res = x as u16 + state.cpu.r[reg::A as usize] as u16;
+ self.cpu.r[reg::F as usize] = 0;
- state.cpu.r[reg::F as usize] = 0;
+ if (x & 0xf) + (self.cpu.r[reg::A as usize] & 0xf) > 0xf {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
- if (x & 0xf) + (state.cpu.r[reg::A as usize] & 0xf) > 0xf {
- state.cpu.r[reg::F as usize] |= flag::H;
- }
+ if res > 0xff {
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
- if res > 0xff {
- state.cpu.r[reg::F as usize] |= flag::CY;
+ self.cpu.r[reg::A as usize] = res as u8;
+
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
- state.cpu.r[reg::A as usize] = res as u8;
+ fn addhlrr(&mut self, rr: u8) -> u64 {
+ let n = self.cpu.r16(rr);
+ let hl = self.cpu.r16(reg::HL);
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
- }
-}
+ self.cpu.w16(reg::HL, (hl as i32 + n as i32) as u16);
-pub fn addhlrr(state: &mut GBState, rr: u8) -> u64 {
- let n = state.cpu.r16(rr);
- let hl = state.cpu.r16(reg::HL);
+ self.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY);
- state.cpu.w16(reg::HL, (hl as i32 + n as i32) as u16);
+ if (hl & 0xff) as i32 + n as i32 & !0xff != 0 {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
- state.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY);
+ if (hl as i32 + n as i32) & !0xffff != 0 {
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
- if (hl & 0xff) as i32 + n as i32 & !0xff != 0 {
- state.cpu.r[reg::F as usize] |= flag::H;
+ 8
}
- if (hl as i32 + n as i32) & !0xffff != 0 {
- state.cpu.r[reg::F as usize] |= flag::CY;
- }
+ fn adc(&mut self, x: u8) {
+ // ADD a number and the carry flag to A and store the result in A
+ let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4;
+ let res = x as u16 + self.cpu.r[reg::A as usize] as u16 + carry as u16;
- 8
-}
+ self.cpu.r[reg::F as usize] = 0;
-pub fn adc(state: &mut GBState, x: u8) {
- // ADD a number and the carry flag to A and store the result in A
- let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4;
- let res = x as u16 + state.cpu.r[reg::A as usize] as u16 + carry as u16;
+ if (x & 0xf) + ((self.cpu.r[reg::A as usize] & 0xf) + carry) > 0xf {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
- state.cpu.r[reg::F as usize] = 0;
+ if res > 0xff {
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
- if (x & 0xf) + ((state.cpu.r[reg::A as usize] & 0xf) + carry) > 0xf {
- state.cpu.r[reg::F as usize] |= flag::H;
- }
+ self.cpu.r[reg::A as usize] = res as u8;
- if res > 0xff {
- state.cpu.r[reg::F as usize] |= flag::CY;
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
- state.cpu.r[reg::A as usize] = res as u8;
+ fn sub(&mut self, x: u8) {
+ // SUB a number to A and store the result in A
+ self.cpu.r[reg::F as usize] = flag::N;
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
- }
-}
+ if (x & 0xf) > (self.cpu.r[reg::A as usize] & 0xf) {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
+
+ if x > self.cpu.r[reg::A as usize] {
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
-pub fn sub(state: &mut GBState, x: u8) {
- // SUB a number to A and store the result in A
- state.cpu.r[reg::F as usize] = flag::N;
+ self.cpu.r[reg::A as usize] = self.cpu.r[reg::A as usize] - x;
- if (x & 0xf) > (state.cpu.r[reg::A as usize] & 0xf) {
- state.cpu.r[reg::F as usize] |= flag::H;
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
- if x > state.cpu.r[reg::A as usize] {
- state.cpu.r[reg::F as usize] |= flag::CY;
- }
+ fn sbc(&mut self, x: u8) {
+ // SUB a number and the carry flag to A and store the result in A
+ let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4;
+ self.cpu.r[reg::F as usize] = flag::N;
- state.cpu.r[reg::A as usize] = state.cpu.r[reg::A as usize] - x;
+ if (x & 0xf) > (self.cpu.r[reg::A as usize] & 0xf) - carry {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
- }
-}
+ if x as i32 > self.cpu.r[reg::A as usize] as i32 - carry as i32 {
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
-pub fn sbc(state: &mut GBState, x: u8) {
- // SUB a number and the carry flag to A and store the result in A
- let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4;
- state.cpu.r[reg::F as usize] = flag::N;
+ self.cpu.r[reg::A as usize] = self.cpu.r[reg::A as usize] - x - carry;
- if (x & 0xf) > (state.cpu.r[reg::A as usize] & 0xf) - carry {
- state.cpu.r[reg::F as usize] |= flag::H;
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
- if x as i32 > state.cpu.r[reg::A as usize] as i32 - carry as i32 {
- state.cpu.r[reg::F as usize] |= flag::CY;
- }
+ fn and(&mut self, x: u8) {
+ // AND a number to A and store the result in A
+ self.cpu.r[reg::A as usize] &= x;
- state.cpu.r[reg::A as usize] = state.cpu.r[reg::A as usize] - x - carry;
+ self.cpu.r[reg::F as usize] = flag::H;
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
-}
-pub fn and(state: &mut GBState, x: u8) {
- // AND a number to A and store the result in A
- state.cpu.r[reg::A as usize] &= x;
+ fn xor(&mut self, x: u8) {
+ // XOR a number to A and store the result in A
+ self.cpu.r[reg::A as usize] ^= x;
- state.cpu.r[reg::F as usize] = flag::H;
+ self.cpu.r[reg::F as usize] = 0;
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
-}
-pub fn xor(state: &mut GBState, x: u8) {
- // XOR a number to A and store the result in A
- state.cpu.r[reg::A as usize] ^= x;
+ fn or(&mut self, x: u8) {
+ // OR a number to A and store the result in A
+ self.cpu.r[reg::A as usize] |= x;
- state.cpu.r[reg::F as usize] = 0;
+ self.cpu.r[reg::F as usize] = 0;
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ if self.cpu.r[reg::A as usize] == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
-}
-pub fn or(state: &mut GBState, x: u8) {
- // OR a number to A and store the result in A
- state.cpu.r[reg::A as usize] |= x;
+ fn cp(&mut self, x: u8) {
+ // SUB a number to A and update the flags accordingly without updating A
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] = 0;
+ self.cpu.r[reg::F as usize] |= flag::N;
- if state.cpu.r[reg::A as usize] == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
- }
-}
+ if x & 0xf > self.cpu.r[reg::A as usize] & 0xf {
+ self.cpu.r[reg::F as usize] |= flag::H;
+ }
-pub fn cp(state: &mut GBState, x: u8) {
- // SUB a number to A and update the flags accordingly without updating A
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ if x > self.cpu.r[reg::A as usize] {
+ self.cpu.r[reg::F as usize] |= flag::CY;
+ }
- state.cpu.r[reg::F as usize] |= flag::N;
+ let res = self.cpu.r[reg::A as usize] - x;
- if x & 0xf > state.cpu.r[reg::A as usize] & 0xf {
- state.cpu.r[reg::F as usize] |= flag::H;
+ if res == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
}
- if x > state.cpu.r[reg::A as usize] {
- state.cpu.r[reg::F as usize] |= flag::CY;
+ fn rlc(&mut self, r_i: u8) -> Result<(), MemError> {
+ // ROTATE LEFT the input register
+ let mut n = self.r_reg(r_i)?;
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ self.cpu.r[reg::F as usize] |= (n >> 7) << 4;
+ n <<= 1;
+ n |= (self.cpu.r[reg::F as usize] & flag::CY) >> 4;
+ self.w_reg(r_i, n)
}
- let res = state.cpu.r[reg::A as usize] - x;
-
- if res == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ fn rrc(&mut self, r_i: u8) -> Result<(), MemError> {
+ // ROTATE RIGHT the input register
+ let mut n = self.r_reg(r_i)?;
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ self.cpu.r[reg::F as usize] |= (n & 1) << 4;
+ n >>= 1;
+ n |= ((self.cpu.r[reg::F as usize] & flag::CY) >> 4) << 7;
+ self.w_reg(r_i, n)
}
-}
-pub fn rlc(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // ROTATE LEFT the input register
- let mut n = state.r_reg(r_i)?;
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] |= (n >> 7) << 4;
- n <<= 1;
- n |= (state.cpu.r[reg::F as usize] & flag::CY) >> 4;
- state.w_reg(r_i, n)
-}
+ fn rl(&mut self, r_i: u8) -> Result<(), MemError> {
+ // ROTATE LEFT THROUGH CARRY the input register
+ // (RLC IS ROTATE AND RL IS ROTATE THROUGH CARRY ! IT DOESN'T MAKE ANY SENSE !!)
+ let mut n = self.r_reg(r_i)?;
+ let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4;
-pub fn rrc(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // ROTATE RIGHT the input register
- let mut n = state.r_reg(r_i)?;
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] |= (n & 1) << 4;
- n >>= 1;
- n |= ((state.cpu.r[reg::F as usize] & flag::CY) >> 4) << 7;
- state.w_reg(r_i, n)
-}
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ self.cpu.r[reg::F as usize] |= (n >> 7) << 4;
+ n <<= 1;
+ n |= carry;
+ self.w_reg(r_i, n)
+ }
-pub fn rl(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // ROTATE LEFT THROUGH CARRY the input register
- // (RLC IS ROTATE AND RL IS ROTATE THROUGH CARRY ! IT DOESN'T MAKE ANY SENSE !!)
- let mut n = state.r_reg(r_i)?;
- let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4;
-
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] |= (n >> 7) << 4;
- n <<= 1;
- n |= carry;
- state.w_reg(r_i, n)
-}
+ fn rr(&mut self, r_i: u8) -> Result<(), MemError> {
+ // ROTATE RIGHT THROUGH CARRY the input register
+ let mut n = self.r_reg(r_i)?;
+ let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4;
-pub fn rr(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // ROTATE RIGHT THROUGH CARRY the input register
- let mut n = state.r_reg(r_i)?;
- let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4;
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ self.cpu.r[reg::F as usize] |= (n & 1) << 4;
+ n >>= 1;
+ n |= carry << 7;
+ self.w_reg(r_i, n)
+ }
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] |= (n & 1) << 4;
- n >>= 1;
- n |= carry << 7;
- state.w_reg(r_i, n)
-}
+ fn sla(&mut self, r_i: u8) -> Result<(), MemError> {
+ // Shift left Arithmetic (b0=0) the input register
+ let mut n = self.r_reg(r_i)?;
-pub fn sla(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // Shift left Arithmetic (b0=0) the input register
- let mut n = state.r_reg(r_i)?;
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ self.cpu.r[reg::F as usize] |= (n >> 7) << 4;
+ n <<= 1;
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] |= (n >> 7) << 4;
- n <<= 1;
+ if n == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
- if n == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ self.w_reg(r_i, n)
}
- state.w_reg(r_i, n)
-}
+ fn sra(&mut self, r_i: u8) -> Result<(), MemError> {
+ // Shift right Arithmetic (b7=b7) the input register
+ let mut n = self.r_reg(r_i)?;
-pub fn sra(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // Shift right Arithmetic (b7=b7) the input register
- let mut n = state.r_reg(r_i)?;
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ self.cpu.r[reg::F as usize] |= (n & 0b1) << 4;
+ let b7 = n & 0b10000000;
+ n >>= 1;
+ n |= b7;
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] |= (n & 0b1) << 4;
- let b7 = n & 0b10000000;
- n >>= 1;
- n |= b7;
+ if n == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
- if n == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ self.w_reg(r_i, n)
}
- state.w_reg(r_i, n)
-}
+ fn swap(&mut self, r_i: u8) -> Result<(), MemError> {
+ // Swap the high nibble and low nibble
+ let mut n = self.r_reg(r_i)?;
-pub fn swap(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // Swap the high nibble and low nibble
- let mut n = state.r_reg(r_i)?;
+ let nibble_low = n & 0b1111;
+ let nibble_high = n >> 4;
- let nibble_low = n & 0b1111;
- let nibble_high = n >> 4;
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ n = nibble_high | (nibble_low << 4);
- n = nibble_high | (nibble_low << 4);
+ if n == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
- if n == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ self.w_reg(r_i, n)
}
- state.w_reg(r_i, n)
-}
+ fn srl(&mut self, r_i: u8) -> Result<(), MemError> {
+ // Shift right Logical (b7=0) the input register
+ let mut n = self.r_reg(r_i)?;
-pub fn srl(state: &mut GBState, r_i: u8) -> Result<(), MemError> {
- // Shift right Logical (b7=0) the input register
- let mut n = state.r_reg(r_i)?;
+ self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
+ self.cpu.r[reg::F as usize] |= (n & 0b1) << 4;
+ n >>= 1;
- state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY);
- state.cpu.r[reg::F as usize] |= (n & 0b1) << 4;
- n >>= 1;
+ if n == 0 {
+ self.cpu.r[reg::F as usize] |= flag::ZF;
+ }
- if n == 0 {
- state.cpu.r[reg::F as usize] |= flag::ZF;
+ self.w_reg(r_i, n)
}
- state.w_reg(r_i, n)
-}
+ fn bit(&mut self, n1: u8, n2: u8) -> Result<(), MemError> {
+ let z = (((self.r_reg(n2)? >> n1) & 1) ^ 1) << 7;
-pub fn bit(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> {
- let z = (((state.r_reg(n2)? >> n1) & 1) ^ 1) << 7;
+ self.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF);
+ self.cpu.r[reg::F as usize] |= flag::H | z;
+ Ok(())
+ }
- state.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF);
- state.cpu.r[reg::F as usize] |= flag::H | z;
- Ok(())
-}
+ fn set(&mut self, n1: u8, n2: u8) -> Result<(), MemError> {
+ self.w_reg(n2, self.r_reg(n2)? | (1 << n1))
+ }
-pub fn set(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> {
- state.w_reg(n2, state.r_reg(n2)? | (1 << n1))
-}
+ fn res(&mut self, n1: u8, n2: u8) -> Result<(), MemError> {
+ self.w_reg(n2, self.r_reg(n2)? & !(1 << n1))
+ }
-pub fn res(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> {
- state.w_reg(n2, state.r_reg(n2)? & !(1 << n1))
-}
+ // I don't remember why I separated op00, op01, op10 and op11 AND I'M NOT GOING TO CHANGE IT
+ // BECAUSE I LOVE CHAOS
-// I don't remember why I separated op00, op01, op10 and op11 AND I'M NOT GOING TO CHANGE IT
-// BECAUSE I LOVE CHAOS
-
-pub fn op00(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> {
- // Dispatcher for the instructions starting with 0b00 based on their 3 LSB
- match n2 {
- 0b000 => match n1 {
- 0b000 => Ok(4),
- 0b001 => ldnnsp(state),
- 0b010 => todo!("STOP"),
- 0b011 => jr8(state),
- _ => jrcc8(state, n1),
- },
- 0b001 => match n1 {
- 0b001 | 0b011 | 0b101 | 0b111 => Ok(addhlrr(state, n1 >> 1)),
- 0b000 | 0b010 | 0b100 | 0b110 => {
- let p = r_16b_from_pc(state)?;
- ldrr16(state, n1 >> 1, p);
- Ok(12)
+ fn op00(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> {
+ // Dispatcher for the instructions starting with 0b00 based on their 3 LSB
+ match n2 {
+ 0b000 => match n1 {
+ 0b000 => Ok(4),
+ 0b001 => self.ldnnsp(),
+ 0b010 => todo!("STOP"),
+ 0b011 => self.jr8(),
+ _ => self.jrcc8(n1),
+ },
+ 0b001 => match n1 {
+ 0b001 | 0b011 | 0b101 | 0b111 => Ok(self.addhlrr(n1 >> 1)),
+ 0b000 | 0b010 | 0b100 | 0b110 => {
+ let p = self.r_16b_from_pc()?;
+ self.ldrr16(n1 >> 1, p);
+ Ok(12)
+ }
+ _ => panic!(),
+ },
+ 0b010 => self.ld00a(n1),
+ 0b011 => match n1 {
+ 0b001 | 0b011 | 0b101 | 0b111 => Ok(self.dec16(n1 >> 1)),
+ 0b000 | 0b010 | 0b100 | 0b110 => Ok(self.inc16(n1 >> 1)),
+ _ => panic!(),
+ },
+ 0b100 => self.inc8(n1),
+ 0b101 => self.dec8(n1),
+ 0b110 => self.ldr8(n1),
+ 0b111 => {
+ match n1 {
+ 0b000 => self.rlc(7)?,
+ 0b001 => self.rrc(7)?,
+ 0b010 => self.rl(7)?,
+ 0b011 => self.rr(7)?,
+ 0b100 => self.daa(),
+ 0b101 => self.cpl(),
+ 0b110 => self.scf(),
+ 0b111 => self.ccf(),
+ _ => panic!(),
+ };
+ Ok(4)
}
_ => panic!(),
- },
- 0b010 => ld00a(state, n1),
- 0b011 => match n1 {
- 0b001 | 0b011 | 0b101 | 0b111 => Ok(dec16(state, n1 >> 1)),
- 0b000 | 0b010 | 0b100 | 0b110 => Ok(inc16(state, n1 >> 1)),
- _ => panic!(),
- },
- 0b100 => inc8(state, n1),
- 0b101 => dec8(state, n1),
- 0b110 => ldr8(state, n1),
- 0b111 => {
- match n1 {
- 0b000 => rlc(state, 7)?,
- 0b001 => rrc(state, 7)?,
- 0b010 => rl(state, 7)?,
- 0b011 => rr(state, 7)?,
- 0b100 => daa(state),
- 0b101 => cpl(state),
- 0b110 => scf(state),
- 0b111 => ccf(state),
- _ => panic!(),
- };
+ }
+ }
+
+ fn op01(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> {
+ // Dispatcher for the instructions starting with 0b01 (LD r,r and HALT)
+ if n1 == 0b110 && n2 == 0b110 {
+ self.mem.halt = true;
Ok(4)
+ } else {
+ self.ldrr(n1, n2)?;
+
+ if n1 == 0b110 || n2 == 0b110 {
+ Ok(8)
+ } else {
+ Ok(4)
+ }
}
- _ => panic!(),
}
-}
-pub fn op01(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> {
- // Dispatcher for the instructions starting with 0b01 (LD r,r and HALT)
- if n1 == 0b110 && n2 == 0b110 {
- state.mem.halt = true;
- Ok(4)
- } else {
- ldrr(state, n1, n2)?;
+ fn op10(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> {
+ // Dispatcher for the instructions starting with 0b10 (Arithmetic)
+ match n1 {
+ 0b000 => self.add(self.r_reg(n2)?),
+ 0b001 => self.adc(self.r_reg(n2)?),
+ 0b010 => self.sub(self.r_reg(n2)?),
+ 0b011 => self.sbc(self.r_reg(n2)?),
+ 0b100 => self.and(self.r_reg(n2)?),
+ 0b101 => self.xor(self.r_reg(n2)?),
+ 0b110 => self.or(self.r_reg(n2)?),
+ 0b111 => self.cp(self.r_reg(n2)?),
+ _ => panic!(),
+ }
- if n1 == 0b110 || n2 == 0b110 {
+ if n2 == 0b110 {
Ok(8)
} else {
Ok(4)
}
}
-}
-pub fn op10(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> {
- // Dispatcher for the instructions starting with 0b10 (Arithmetic)
- match n1 {
- 0b000 => add(state, state.r_reg(n2)?),
- 0b001 => adc(state, state.r_reg(n2)?),
- 0b010 => sub(state, state.r_reg(n2)?),
- 0b011 => sbc(state, state.r_reg(n2)?),
- 0b100 => and(state, state.r_reg(n2)?),
- 0b101 => xor(state, state.r_reg(n2)?),
- 0b110 => or(state, state.r_reg(n2)?),
- 0b111 => cp(state, state.r_reg(n2)?),
- _ => panic!(),
- }
-
- if n2 == 0b110 {
- Ok(8)
- } else {
- Ok(4)
- }
-}
-
-pub fn op11(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> {
- match n2 {
- 0b000 => match n1 {
- 0b100 => {
- let n = r_8b_from_pc(state)?;
- ldnna(state, n as u16 | 0xff00)?;
- Ok(12)
- }
- 0b101 => addsp8(state),
- 0b110 => {
- let n = r_8b_from_pc(state)?;
- ldann(state, n as u16 | 0xff00)?;
- Ok(12)
- }
- 0b111 => {
- let n = r_8b_from_pc(state)?;
- ldrr16(state, reg::HL, n as u16 + state.cpu.sp);
- Ok(12)
- }
- _ => retcc(state, n1 & 0b11),
- },
- 0b001 => match n1 {
- 0b001 => ret(state),
- 0b011 => {
- state.mem.ime = true;
-
- ret(state)
- }
- 0b101 => Ok(jphl(state)),
- 0b111 => Ok(ldsphl(state)),
- _ => {
- let p = pop(state)?;
- state.cpu.r[(n1 >> 1) as usize * 2 + 1] = (p & 0xff) as u8;
- state.cpu.r[(n1 >> 1) as usize * 2] = (p >> 8) as u8;
- Ok(12)
- }
- },
- 0b010 => match n1 {
- 0b100 => {
- ldnna(state, state.cpu.r[reg::C as usize] as u16 | 0xff00)?;
- Ok(8)
- }
- 0b101 => {
- let nn = r_16b_from_pc(state)?;
- ldnna(state, nn)?;
- Ok(16)
- }
+ fn op11(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> {
+ match n2 {
+ 0b000 => match n1 {
+ 0b100 => {
+ let n = self.r_8b_from_pc()?;
+ self.ldnna(n as u16 | 0xff00)?;
+ Ok(12)
+ }
+ 0b101 => self.addsp8(),
+ 0b110 => {
+ let n = self.r_8b_from_pc()?;
+ self.ldann(n as u16 | 0xff00)?;
+ Ok(12)
+ }
+ 0b111 => {
+ let n = self.r_8b_from_pc()?;
+ self.ldrr16(reg::HL, n as u16 + self.cpu.sp);
+ Ok(12)
+ }
+ _ => self.retcc(n1 & 0b11),
+ },
+ 0b001 => match n1 {
+ 0b001 => self.ret(),
+ 0b011 => {
+ self.mem.ime = true;
+
+ self.ret()
+ }
+ 0b101 => Ok(self.jphl()),
+ 0b111 => Ok(self.ldsphl()),
+ _ => {
+ let p = self.pop()?;
+ self.cpu.r[(n1 >> 1) as usize * 2 + 1] = (p & 0xff) as u8;
+ self.cpu.r[(n1 >> 1) as usize * 2] = (p >> 8) as u8;
+ Ok(12)
+ }
+ },
+ 0b010 => match n1 {
+ 0b100 => {
+ self.ldnna(self.cpu.r[reg::C as usize] as u16 | 0xff00)?;
+ Ok(8)
+ }
+ 0b101 => {
+ let nn = self.r_16b_from_pc()?;
+ self.ldnna(nn)?;
+ Ok(16)
+ }
+ 0b110 => {
+ self.ldann(self.cpu.r[reg::C as usize] as u16 | 0xff00)?;
+ Ok(8)
+ }
+ 0b111 => {
+ let nn = self.r_16b_from_pc()?;
+ self.ldann(nn)?;
+ Ok(16)
+ }
+ _ => self.jpcc16(n1 & 0b11),
+ },
+ 0b011 => match n1 {
+ 0b000 => self.jp16(),
+ 0b001 => self.op_bitwise(), // Bitwise operations
+ 0b010 | 0b011 | 0b100 | 0b101 => unimplemented!(),
+ 0b110 => {
+ self.mem.ime = false;
+ Ok(4)
+ }
+ 0b111 => {
+ self.mem.ime = true;
+ Ok(4)
+ }
+ _ => panic!(),
+ },
+ 0b100 => self.callcc(n1 & 0b11),
+ 0b101 => match n1 {
+ 0b001 => self.call(),
+ 0b011 | 0b101 | 0b111 => unimplemented!(),
+ _ => {
+ let value = self.cpu.r[(n1 >> 1) as usize * 2 + 1] as u16
+ | ((self.cpu.r[(n1 >> 1) as usize * 2] as u16) << 8);
+ self.push(value)?;
+ Ok(16)
+ }
+ },
0b110 => {
- ldann(state, state.cpu.r[reg::C as usize] as u16 | 0xff00)?;
+ let p = self.r_8b_from_pc()?;
+
+ match n1 {
+ 0b000 => self.add(p),
+ 0b001 => self.adc(p),
+ 0b010 => self.sub(p),
+ 0b011 => self.sbc(p),
+ 0b100 => self.and(p),
+ 0b101 => self.xor(p),
+ 0b110 => self.or(p),
+ 0b111 => self.cp(p),
+ _ => panic!(),
+ }
Ok(8)
}
0b111 => {
- let nn = r_16b_from_pc(state)?;
- ldann(state, nn)?;
+ let p = n1 << 3;
+
+ self.push(self.cpu.pc)?;
+ self.cpu.pc = p as u16;
Ok(16)
- }
- _ => jpcc16(state, n1 & 0b11),
- },
- 0b011 => match n1 {
- 0b000 => jp16(state),
- 0b001 => op_bitwise(state), // Bitwise operations
- 0b010 | 0b011 | 0b100 | 0b101 => unimplemented!(),
- 0b110 => {
- state.mem.ime = false;
- Ok(4)
- }
- 0b111 => {
- state.mem.ime = true;
- Ok(4)
- }
+ } // RST
_ => panic!(),
- },
- 0b100 => callcc(state, n1 & 0b11),
- 0b101 => match n1 {
- 0b001 => call(state),
- 0b011 | 0b101 | 0b111 => unimplemented!(),
- _ => {
- let value = state.cpu.r[(n1 >> 1) as usize * 2 + 1] as u16
- | ((state.cpu.r[(n1 >> 1) as usize * 2] as u16) << 8);
- push(state, value)?;
- Ok(16)
- }
- },
- 0b110 => {
- let p = r_8b_from_pc(state)?;
-
- match n1 {
- 0b000 => add(state, p),
- 0b001 => adc(state, p),
- 0b010 => sub(state, p),
- 0b011 => sbc(state, p),
- 0b100 => and(state, p),
- 0b101 => xor(state, p),
- 0b110 => or(state, p),
- 0b111 => cp(state, p),
- _ => panic!(),
- }
- Ok(8)
}
- 0b111 => {
- let p = n1 << 3;
+ }
- push(state, state.cpu.pc)?;
- state.cpu.pc = p as u16;
+ fn op_bitwise(&mut self) -> Result<u64, MemError> {
+ let p = self.r_8b_from_pc()?;
+ let opcode = p >> 6;
+ let n1 = p >> 3 & 0b111;
+ let n2 = p & 0b111;
+
+ match opcode {
+ 0b00 => match n1 {
+ 0b000 => self.rlc(n2),
+ 0b001 => self.rrc(n2),
+ 0b010 => self.rl(n2),
+ 0b011 => self.rr(n2),
+ 0b100 => self.sla(n2),
+ 0b101 => self.sra(n2),
+ 0b110 => self.swap(n2),
+ 0b111 => self.srl(n2),
+ _ => panic!(),
+ },
+ 0b01 => self.bit(n1, n2),
+ 0b10 => self.res(n1, n2),
+ 0b11 => self.set(n1, n2),
+ _ => panic!(),
+ }?;
+ if n2 == 0b110 {
Ok(16)
- } // RST
- _ => panic!(),
+ } else {
+ Ok(8)
+ }
}
-}
-pub fn op_bitwise(state: &mut GBState) -> Result<u64, MemError> {
- let p = r_8b_from_pc(state)?;
- let opcode = p >> 6;
- let n1 = p >> 3 & 0b111;
- let n2 = p & 0b111;
-
- match opcode {
- 0b00 => match n1 {
- 0b000 => rlc(state, n2),
- 0b001 => rrc(state, n2),
- 0b010 => rl(state, n2),
- 0b011 => rr(state, n2),
- 0b100 => sla(state, n2),
- 0b101 => sra(state, n2),
- 0b110 => swap(state, n2),
- 0b111 => srl(state, n2),
+ pub fn exec_opcode(&mut self) -> Result<u64, MemError> {
+ let opcode = self.mem.r(self.cpu.pc)?;
+
+ if self.is_debug {
+ println!(
+ "{:02x}:{:04x} = {:02x} (IME: {})",
+ self.mem.rom_bank, self.cpu.pc, opcode, self.mem.ime
+ );
+ }
+
+ self.cpu.pc += 1;
+
+ let n1 = (opcode >> 3) & 0b111;
+ let n2 = opcode & 0b111;
+
+ match opcode >> 6 {
+ 0b00 => self.op00(n1, n2),
+ 0b01 => self.op01(n1, n2),
+ 0b10 => self.op10(n1, n2),
+ 0b11 => self.op11(n1, n2),
_ => panic!(),
- },
- 0b01 => bit(state, n1, n2),
- 0b10 => res(state, n1, n2),
- 0b11 => set(state, n1, n2),
- _ => panic!(),
- }?;
- if n2 == 0b110 {
- Ok(16)
- } else {
- Ok(8)
+ }
}
}