diff --git a/src/main.rs b/src/main.rs index c4b7acf..2c5c4a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,6 +76,7 @@ pub struct Memory { oam: [u8; 160], interrupts: u8, ime: bool, + ime_scheduled: u8, io: [u8; 76], } @@ -93,6 +94,7 @@ impl Memory { oam: [0x0; 160], interrupts: 0x0, ime: false, + ime_scheduled: 0x0, io: [0xFF; 76], } } diff --git a/src/processor/instructions/instructions.rs b/src/processor/instructions/instructions.rs index ccc370e..aefc45e 100644 --- a/src/processor/instructions/instructions.rs +++ b/src/processor/instructions/instructions.rs @@ -110,6 +110,10 @@ impl CPU { self.reg.pc.set_low(address); } + pub(crate) fn ret(&mut self) { + self.reg.pc = self.pop_word(); + } + pub(crate) fn jr(&mut self, jump: i8) { self.reg.pc = self.reg.pc.wrapping_add_signed(jump.into()); } diff --git a/src/processor/instructions/primitives.rs b/src/processor/instructions/primitives.rs index 94809d9..23550ad 100644 --- a/src/processor/instructions/primitives.rs +++ b/src/processor/instructions/primitives.rs @@ -120,6 +120,20 @@ impl CPU { } } + pub(crate) fn sp_add(&mut self, first: u16, second: i8) -> u16 { + let (result, carry) = first.overflowing_add_signed(second.into()); + self.clear_flag(Flags::NSubtract); + self.clear_flag(Flags::Zero); + self.set_or_clear_flag(Flags::Carry, carry); + self.set_or_clear_flag( + Flags::HalfCarry, + (((first & 0xFFF).wrapping_add_signed(>::into(second) & 0xFFF)) + & 0x1000) + == 0x1000, + ); + return result; + } + pub(crate) fn add_u8s(&mut self, first: u8, second: u8) -> u8 { let (result, carry) = first.overflowing_add(second); self.clear_flag(Flags::NSubtract); diff --git a/src/processor/opcodes.rs b/src/processor/opcodes.rs index 4117178..ce1a5b2 100644 --- a/src/processor/opcodes.rs +++ b/src/processor/opcodes.rs @@ -6,6 +6,13 @@ 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) { + if self.memory.ime_scheduled > 0 { + self.memory.ime_scheduled = self.memory.ime_scheduled.saturating_sub(1); + if self.memory.ime_scheduled == 0 { + self.memory.ime = true; + } + } + match opcode { 0x00 => { // noop @@ -491,9 +498,201 @@ impl CPU { 0xBD => self.cp(self.reg.get_8(Reg8::A), self.reg.get_8(Reg8::L)), 0xBE => self.cp(self.reg.get_8(Reg8::A), self.memory.get(self.reg.hl)), 0xBF => self.cp(self.reg.get_8(Reg8::A), self.reg.get_8(Reg8::A)), - - _ => { - undefined(opcode); + 0xC0 => { + if !self.is_flag(Flags::Zero) { + self.ret(); + } + } + 0xC1 => self.reg.bc = self.pop_word(), + 0xC2 => { + let jump = self.ld_immediate_word(); + if !self.is_flag(Flags::Zero) { + self.reg.pc = jump; + } + } + 0xC3 => { + let jump = self.ld_immediate_word(); + self.reg.pc = jump; + } + 0xC4 => { + let pc = self.ld_immediate_word(); + if !self.is_flag(Flags::Zero) { + self.push(self.reg.pc); + self.reg.pc = pc; + } + } + 0xC5 => self.push(self.reg.bc), + 0xC6 => { + let byte = self.ld_immediate_byte(); + let val = self.add_u8s(self.reg.get_8(Reg8::A), byte); + self.reg.set_8(Reg8::A, val); + } + 0xC7 => self.rst(0x0), + 0xC8 => { + if self.is_flag(Flags::Zero) { + self.ret(); + } + } + 0xC9 => self.ret(), + 0xCA => { + let jump = self.ld_immediate_word(); + if self.is_flag(Flags::Zero) { + self.reg.pc = jump; + } + } + 0xCB => panic!("haven't implemented 0xCB opcodes yet!!"), + 0xCC => { + let pc = self.ld_immediate_word(); + if self.is_flag(Flags::Zero) { + self.push(self.reg.pc); + self.reg.pc = pc; + } + } + 0xCD => { + let pc = self.ld_immediate_word(); + self.push(self.reg.pc); + self.reg.pc = pc; + } + 0xCE => { + let byte = self.ld_immediate_byte(); + let val = self.adc(self.reg.get_8(Reg8::A), byte); + self.reg.set_8(Reg8::A, val); + } + 0xCF => self.rst(0x08), + 0xD0 => { + if !self.is_flag(Flags::Carry) { + self.ret(); + } + } + 0xD1 => self.reg.de = self.pop_word(), + 0xD2 => { + let jump = self.ld_immediate_word(); + if !self.is_flag(Flags::Carry) { + self.reg.pc = jump; + } + } + 0xD4 => { + let pc = self.ld_immediate_word(); + if !self.is_flag(Flags::Carry) { + self.push(self.reg.pc); + self.reg.pc = pc; + } + } + 0xD5 => self.push(self.reg.de), + 0xD6 => { + let byte = self.ld_immediate_byte(); + let val = self.sub_u8s(self.reg.get_8(Reg8::A), byte); + self.reg.set_8(Reg8::A, val); + } + 0xD7 => self.rst(0x10), + 0xD8 => { + if self.is_flag(Flags::Carry) { + self.ret(); + } + } + 0xD9 => { + self.ret(); + self.memory.ime = true; + } + 0xDA => { + let jump = self.ld_immediate_word(); + if self.is_flag(Flags::Carry) { + self.reg.pc = jump; + } + } + 0xDC => { + let pc = self.ld_immediate_word(); + if self.is_flag(Flags::Carry) { + self.push(self.reg.pc); + self.reg.pc = pc; + } + } + 0xDE => { + let byte = self.ld_immediate_byte(); + let val = self.sbc(self.reg.get_8(Reg8::A), byte); + self.reg.set_8(Reg8::A, val); + } + 0xDF => self.rst(0x18), + 0xE0 => { + let mut addr: u16 = 0x0; + addr.set_high(0xFF); + addr.set_low(self.ld_immediate_byte()); + self.memory.set(addr, self.reg.get_8(Reg8::A)); + } + 0xE1 => self.reg.hl = self.pop_word(), + 0xE2 => { + let mut addr: u16 = 0x0; + addr.set_high(0xFF); + addr.set_low(self.reg.get_8(Reg8::C)); + self.memory.set(addr, self.reg.get_8(Reg8::A)); + } + 0xE5 => self.push(self.reg.hl), + 0xE6 => { + let byte = self.ld_immediate_byte(); + let val = self.and(self.reg.get_8(Reg8::A), byte); + self.reg.set_8(Reg8::A, val); + } + 0xE7 => self.rst(0x20), + 0xE8 => { + let v = as_signed(self.ld_immediate_byte()); + self.reg.sp = self.sp_add(self.reg.sp, v); + } + 0xE9 => { + self.reg.pc = self.reg.hl; + } + 0xEA => { + let addr = self.ld_immediate_word(); + self.memory.set(addr, self.reg.get_8(Reg8::A)); + } + 0xEE => { + let byte = self.ld_immediate_byte(); + let val = self.xor(self.reg.get_8(Reg8::A), byte); + self.reg.set_8(Reg8::A, val); + } + 0xEF => self.rst(0x28), + 0xF0 => { + let mut addr: u16 = 0x0; + addr.set_high(0xFF); + addr.set_low(self.ld_immediate_byte()); + self.reg.set_8(Reg8::A, self.memory.get(addr)); + } + 0xF1 => self.reg.af = self.pop_word(), + 0xF2 => { + let mut addr: u16 = 0x0; + addr.set_high(0xFF); + addr.set_low(self.reg.get_8(Reg8::C)); + self.reg.set_8(Reg8::A, self.memory.get(addr)); + } + 0xF3 => { + self.memory.ime = false; + self.memory.ime_scheduled = 0; + } + 0xF5 => self.push(self.reg.af), + 0xF6 => { + let byte = self.ld_immediate_byte(); + let val = self.or(self.reg.get_8(Reg8::A), byte); + self.reg.set_8(Reg8::A, val); + } + 0xF7 => self.rst(0x30), + 0xF8 => { + let v = as_signed(self.ld_immediate_byte()); + self.reg.hl = self.sp_add(self.reg.sp, v); + } + 0xF9 => { + self.reg.sp = self.reg.hl; + } + 0xFA => { + let addr = self.ld_immediate_word(); + self.reg.set_8(Reg8::A, self.memory.get(addr)); + } + 0xFB => self.memory.ime_scheduled = 2, + 0xFE => { + let byte = self.ld_immediate_byte(); + self.cp(self.reg.get_8(Reg8::A), byte); + } + 0xFF => self.rst(0x38), + 0xD3 | 0xDB | 0xDD | 0xE3 | 0xE4 | 0xEB | 0xEC | 0xED | 0xF4 | 0xFC | 0xFD => { + undefined(opcode) } } }