diff options
Diffstat (limited to 'src/opcodes.rs')
-rw-r--r-- | src/opcodes.rs | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/src/opcodes.rs b/src/opcodes.rs new file mode 100644 index 0000000..f238239 --- /dev/null +++ b/src/opcodes.rs @@ -0,0 +1,825 @@ +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; + + 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; + + 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)?) +} + +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)?; + + state.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); +} + +pub fn ldnnsp(state: &mut GBState) -> Result<u64, MemError> { + // Load SP into an arbitrary position in memory + let p = r_16b_from_pc(state)?; + + state.mem.w(p, (state.cpu.sp & 0xff) as u8)?; + state.mem.w(p + 1, (state.cpu.sp >> 8) as u8)?; + Ok(20) +} + +pub fn ldsphl(state: &mut GBState) -> u64 { + state.cpu.sp = state.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(()) +} + +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(()) +} + +pub fn push(state: &mut GBState, x: u16) -> Result<(), MemError> { + state.cpu.sp -= 2; + + state.mem.w(state.cpu.sp, (x & 0xff) as u8)?; + + state.mem.w(state.cpu.sp + 1, (x >> 8) as u8)?; + + 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); + + state.cpu.sp += 2; + + Ok(res) +} + +pub fn jr8(state: &mut GBState) -> Result<u64, MemError> { + // Unconditional relative jump + let p = r_8b_from_pc(state)?; + + state.cpu.pc = (state.cpu.pc as i16 + p as i8 as i16) as u16; + + Ok(12) +} + +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 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) +} + +pub fn jp16(state: &mut GBState) -> Result<u64, MemError> { + // Unconditional absolute jump + let p = r_16b_from_pc(state)?; + + state.cpu.pc = p; + + Ok(16) +} + +pub fn jphl(state: &mut GBState) -> u64 { + // Unconditional absolute jump to HL + state.cpu.pc = state.cpu.r16(reg::HL); + + 4 +} + +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 state.cpu.check_flag(n1 & 0b11) { + cycles += 4; + state.cpu.pc = p; + } + + Ok(cycles) +} + +pub fn call(state: &mut GBState) -> Result<u64, MemError> { + // Unconditional function call + let p = r_16b_from_pc(state)?; + + push(state, state.cpu.pc)?; + state.cpu.pc = p; + + Ok(24) +} + +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 state.cpu.check_flag(n1 & 0b11) { + cycles += 12; + push(state, state.cpu.pc)?; + state.cpu.pc = p; + } + + Ok(cycles) +} + +pub fn ret(state: &mut GBState) -> Result<u64, MemError> { + let res = pop(state)?; + + if res == 0 { + println!("DEBUG: {:?}", state.cpu); + panic!("RET to start"); + } + + state.cpu.pc = res; + + Ok(16) +} + +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) +} + +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 { + 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 { + state.cpu.w16(reg::HL, state.cpu.r16(reg::HL) + 1); // (HL+) + } + + if n1 & 0b110 == 0b110 { + state.cpu.w16(reg::HL, state.cpu.r16(reg::HL) - 1); // (HL-) + } + + Ok(8) +} + +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 state.r_reg(n1)? & 0xf == 0x0 { + state.cpu.r[reg::F as usize] |= flag::H; + } + + Ok(4) +} + +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; + + 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; + } + + if state.r_reg(n1)? & 0xf == 0xf { + state.cpu.r[reg::F as usize] |= flag::H; + } + + Ok(4) +} + +pub fn inc16(state: &mut GBState, rr: u8) -> u64 { + // Increment 16 bit register + state.cpu.w16(rr, state.cpu.r16(rr) + 1); + 8 +} + +pub fn dec16(state: &mut GBState, rr: u8) -> u64 { + // Decrement 16 bit register + state.cpu.w16(rr, state.cpu.r16(rr) - 1); + 8 +} + +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 +} + +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 +} + +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; + + 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; + } + + let nibble_high = state.cpu.r[reg::A as usize] >> 4; + + state.cpu.r[reg::F as usize] &= !(flag::CY | 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; + } + + if state.cpu.r[reg::A as usize] == 0 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } + + state.cpu.r[reg::F as usize] &= !flag::H; +} + +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; + + state.cpu.sp = (state.cpu.sp as i32 + n as i32) as u16; + + state.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY); + + if (state.cpu.sp & 0xff) as i32 + n as i32 & !0xff != 0 { + state.cpu.r[reg::F as usize] |= flag::H; + } + + if (state.cpu.sp as i32 + n as i32) & !0xffff != 0 { + state.cpu.r[reg::F as usize] |= flag::CY; + } + Ok(16) +} + +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; + + state.cpu.r[reg::F as usize] = 0; + + if (x & 0xf) + (state.cpu.r[reg::A as usize] & 0xf) > 0xf { + state.cpu.r[reg::F as usize] |= flag::H; + } + + if res > 0xff { + state.cpu.r[reg::F as usize] |= flag::CY; + } + + state.cpu.r[reg::A as usize] = res as u8; + + if state.cpu.r[reg::A as usize] == 0 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } +} + +pub fn addhlrr(state: &mut GBState, rr: u8) -> u64 { + let n = state.cpu.r16(rr); + let hl = state.cpu.r16(reg::HL); + + state.cpu.w16(reg::HL, (hl as i32 + n as i32) as u16); + + state.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY); + + if (hl & 0xff) as i32 + n as i32 & !0xff != 0 { + state.cpu.r[reg::F as usize] |= flag::H; + } + + if (hl as i32 + n as i32) & !0xffff != 0 { + state.cpu.r[reg::F as usize] |= flag::CY; + } + + 8 +} + +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; + + state.cpu.r[reg::F as usize] = 0; + + if (x & 0xf) + ((state.cpu.r[reg::A as usize] & 0xf) + carry) > 0xf { + state.cpu.r[reg::F as usize] |= flag::H; + } + + if res > 0xff { + state.cpu.r[reg::F as usize] |= flag::CY; + } + + state.cpu.r[reg::A as usize] = res as u8; + + if state.cpu.r[reg::A as usize] == 0 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } +} + +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; + + if (x & 0xf) > (state.cpu.r[reg::A as usize] & 0xf) { + state.cpu.r[reg::F as usize] |= flag::H; + } + + if x > state.cpu.r[reg::A as usize] { + state.cpu.r[reg::F as usize] |= flag::CY; + } + + state.cpu.r[reg::A as usize] = state.cpu.r[reg::A as usize] - x; + + if state.cpu.r[reg::A as usize] == 0 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } +} + +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; + + if (x & 0xf) > (state.cpu.r[reg::A as usize] & 0xf) - carry { + state.cpu.r[reg::F as usize] |= flag::H; + } + + 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; + } + + state.cpu.r[reg::A as usize] = state.cpu.r[reg::A as usize] - x - carry; + + if state.cpu.r[reg::A as usize] == 0 { + state.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; + + state.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; + } +} + +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; + + state.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; + } +} + +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; + + state.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; + } +} + +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); + + state.cpu.r[reg::F as usize] |= flag::N; + + if x & 0xf > state.cpu.r[reg::A as usize] & 0xf { + state.cpu.r[reg::F as usize] |= flag::H; + } + + if x > state.cpu.r[reg::A as usize] { + state.cpu.r[reg::F as usize] |= flag::CY; + } + + let res = state.cpu.r[reg::A as usize] - x; + + if res == 0 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } +} + +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) +} + +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) +} + +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) +} + +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; + + 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) +} + +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)?; + + 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 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } + + state.w_reg(r_i, n) +} + +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)?; + + 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 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } + + state.w_reg(r_i, n) +} + +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; + + state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + + n = nibble_high | (nibble_low << 4); + + if n == 0 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } + + state.w_reg(r_i, n) +} + +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)?; + + 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 { + state.cpu.r[reg::F as usize] |= flag::ZF; + } + + state.w_reg(r_i, n) +} + +pub fn bit(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> { + let z = (((state.r_reg(n2)? >> n1) & 1) ^ 1) << 7; + + state.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF); + state.cpu.r[reg::F as usize] |= flag::H | z; + Ok(()) +} + +pub fn set(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> { + state.w_reg(n2, state.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 + +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) + } + _ => 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!(), + }; + 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)?; + + if n1 == 0b110 || 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) + } + 0b110 => { + ldann(state, state.cpu.r[reg::C as usize] as u16 | 0xff00)?; + Ok(8) + } + 0b111 => { + let nn = r_16b_from_pc(state)?; + ldann(state, nn)?; + 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) + } + _ => 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; + Ok(16) + } // RST + _ => panic!(), + } +} + +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), + _ => 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) + } +} |