diff --git a/src/processor/opcodes.rs b/src/processor/opcodes.rs index bdd12df..9827993 100644 --- a/src/processor/opcodes.rs +++ b/src/processor/opcodes.rs @@ -1,15 +1,201 @@ use crate::verbose_println; use std::ops::{BitAnd, BitOr, BitXor}; -use super::{as_signed, res, set, swap_nibbles, CPU, FLAGS}; +use super::{as_signed, res, set, swap_nibbles, Flags, Reg8, SplitRegister, CPU}; impl CPU { #[allow(dead_code)] pub fn run_opcode(&mut self, opcode: u8) { match opcode { - 0x0 => { + 0x00 => { // noop } + 0x01 => self.reg.bc = self.ld_immediate_word(), + 0x02 => self.memory.set(self.reg.bc, self.reg.get_8(Reg8::A)), + 0x03 => self.reg.bc = self.inc_pair(self.reg.bc), + 0x04 => self.inc(Reg8::B), + 0x05 => self.dec(Reg8::B), + 0x06 => { + let byte = self.ld_immediate_byte(); + self.reg.set_8(Reg8::B, byte); + } + 0x07 => { + let val = self.rlc(self.reg.get_8(Reg8::A)); + self.reg.set_8(Reg8::A, val); + } + 0x08 => { + let addr = self.ld_immediate_word(); + self.memory.set(addr, self.reg.sp.get_low()); + self.memory + .set(addr.wrapping_add(0x1), self.reg.sp.get_high()); + } + 0x09 => self.reg.hl = self.add_u16s(self.reg.hl, self.reg.bc), + 0x0A => self.reg.set_8(Reg8::A, self.memory.get(self.reg.bc)), + 0x0B => self.reg.bc = self.dec_pair(self.reg.bc), + 0x0C => self.inc(Reg8::C), + 0x0D => self.dec(Reg8::C), + 0x0E => { + let byte = self.ld_immediate_byte(); + self.reg.set_8(Reg8::C, byte); + } + 0x0F => { + let val = self.rrc(self.reg.get_8(Reg8::A)); + self.reg.set_8(Reg8::A, val); + } + 0x10 => { + // stop + panic!("stop instruction"); + } + 0x11 => self.reg.de = self.ld_immediate_word(), + 0x12 => self.memory.set(self.reg.de, self.reg.get_8(Reg8::A)), + 0x13 => self.reg.de = self.inc_pair(self.reg.de), + 0x14 => self.inc(Reg8::D), + 0x15 => self.dec(Reg8::D), + 0x16 => { + let byte = self.ld_immediate_byte(); + self.reg.set_8(Reg8::D, byte); + } + 0x17 => { + let val = self.rl(self.reg.get_8(Reg8::A)); + self.reg.set_8(Reg8::A, val); + } + 0x18 => { + let jump = as_signed(self.ld_immediate_byte()); + self.jr(jump); + } + 0x19 => self.reg.hl = self.add_u16s(self.reg.hl, self.reg.de), + 0x1A => self.reg.set_8(Reg8::A, self.memory.get(self.reg.de)), + 0x1B => self.reg.de = self.dec_pair(self.reg.de), + 0x1C => self.inc(Reg8::E), + 0x1D => self.dec(Reg8::E), + 0x1E => { + let byte = self.ld_immediate_byte(); + self.reg.set_8(Reg8::E, byte); + } + 0x1F => { + let val = self.rr(self.reg.get_8(Reg8::A)); + self.reg.set_8(Reg8::A, val); + } + 0x20 => { + let jump = as_signed(self.ld_immediate_byte()); + if !self.is_flag(Flags::Zero) { + self.jr(jump); + } + } + 0x21 => self.reg.hl = self.ld_immediate_word(), + 0x22 => { + self.memory.set(self.reg.hl, self.reg.get_8(Reg8::A)); + self.reg.hl = self.inc_pair(self.reg.hl); + } + 0x23 => self.reg.hl = self.inc_pair(self.reg.hl), + 0x24 => self.inc(Reg8::H), + 0x25 => self.dec(Reg8::H), + 0x26 => { + let byte = self.ld_immediate_byte(); + self.reg.set_8(Reg8::H, byte); + } + 0x27 => { + let mut a = self.reg.get_8(Reg8::A); + if !self.is_flag(Flags::NSubtract) { + // after an addition, adjust if (half-)carry occurred or if result is out of bounds + if self.is_flag(Flags::Carry) || a > 0x99 { + a += 0x60; + self.set_flag(Flags::Carry); + } + if self.is_flag(Flags::HalfCarry) || (a & 0x0f) > 0x09 { + a += 0x6; + } + } else { + // after a subtraction, only adjust if (half-)carry occurred + if self.is_flag(Flags::Carry) { + a -= 0x60; + } + if self.is_flag(Flags::HalfCarry) { + a -= 0x6; + } + } + // these flags are always updated + self.set_or_clear_flag(Flags::Zero, a == 0); + self.clear_flag(Flags::HalfCarry); + self.reg.set_8(Reg8::A, a); + } + 0x28 => { + let jump = as_signed(self.ld_immediate_byte()); + if self.is_flag(Flags::Zero) { + self.jr(jump); + } + } + 0x29 => self.reg.hl = self.add_u16s(self.reg.hl, self.reg.hl), + 0x2A => { + self.reg.set_8(Reg8::A, self.memory.get(self.reg.hl)); + self.reg.hl = self.inc_pair(self.reg.hl); + } + 0x2B => self.reg.hl = self.dec_pair(self.reg.hl), + 0x2C => self.inc(Reg8::L), + 0x2D => self.dec(Reg8::L), + 0x2E => { + let byte = self.ld_immediate_byte(); + self.reg.set_8(Reg8::L, byte); + } + 0x2F => { + let val = !self.reg.get_8(Reg8::A); + self.reg.set_8(Reg8::A, val); + self.set_flag(Flags::NSubtract); + self.set_flag(Flags::HalfCarry); + } + 0x30 => { + let jump = as_signed(self.ld_immediate_byte()); + if !self.is_flag(Flags::Carry) { + self.jr(jump); + } + } + 0x31 => self.reg.sp = self.ld_immediate_word(), + 0x32 => { + self.memory.set(self.reg.hl, self.reg.get_8(Reg8::A)); + self.reg.hl = self.dec_pair(self.reg.hl); + } + 0x33 => self.reg.sp = self.inc_pair(self.reg.sp), + 0x34 => { + let val = self.inc_raw(self.memory.get(self.reg.hl)); + self.memory.set(self.reg.hl, val); + } + 0x35 => { + let val = self.dec_raw(self.memory.get(self.reg.hl)); + self.memory.set(self.reg.hl, val); + } + 0x36 => { + let byte = self.ld_immediate_byte(); + self.memory.set(self.reg.hl, byte); + } + 0x37 => { + self.clear_flag(Flags::NSubtract); + self.clear_flag(Flags::HalfCarry); + self.set_flag(Flags::Carry); + } + 0x38 => { + let jump = as_signed(self.ld_immediate_byte()); + if self.is_flag(Flags::Carry) { + self.jr(jump); + } + } + 0x39 => self.reg.hl = self.add_u16s(self.reg.hl, self.reg.sp), + 0x3A => { + self.reg.set_8(Reg8::A, self.memory.get(self.reg.hl)); + self.reg.hl = self.dec_pair(self.reg.hl); + } + 0x3B => self.reg.sp = self.dec_pair(self.reg.sp), + 0x3C => self.inc(Reg8::A), + 0x3D => self.dec(Reg8::A), + 0x3E => { + let byte = self.ld_immediate_byte(); + self.reg.set_8(Reg8::A, byte); + } + 0x3F => { + self.clear_flag(Flags::NSubtract); + self.clear_flag(Flags::HalfCarry); + self.set_or_clear_flag(Flags::Carry, !self.is_flag(Flags::Carry)); + } + _ => { undefined(opcode); }