From 62792763488cb09b188b70c099acb98541accff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pinheiro?= Date: Tue, 3 Oct 2023 00:39:56 +0100 Subject: [PATCH] more 8bit adds, some not working --- src/lr35902.rs | 233 +++++++++++++++++++++++++++++------------------ tests/lr35902.rs | 117 +++++++++++++++--------- 2 files changed, 218 insertions(+), 132 deletions(-) diff --git a/src/lr35902.rs b/src/lr35902.rs index 26e6ea5..ee7d183 100644 --- a/src/lr35902.rs +++ b/src/lr35902.rs @@ -41,7 +41,6 @@ impl fmt::Debug for LR35902 { } } -#[allow(dead_code)] impl LR35902 { pub fn new() -> Self { let mut m = Self::default(); @@ -49,145 +48,168 @@ impl LR35902 { m } - fn a(&self) -> u8 { - bw::get_byte16::<1>(self.af) - } - - fn b(&self) -> u8 { - bw::get_byte16::<1>(self.bc) - } - - fn c(&self) -> u8 { - bw::get_byte16::<0>(self.bc) - } - - fn d(&self) -> u8 { - bw::get_byte16::<1>(self.de) - } - - fn e(&self) -> u8 { - bw::get_byte16::<0>(self.de) - } - - fn h(&self) -> u8 { - bw::get_byte16::<1>(self.hl) - } - - fn l(&self) -> u8 { - bw::get_byte16::<0>(self.hl) + pub fn f(&self) -> u8 { + bw::get_byte16::<0>(self.af) } - fn z_flag(&self) -> bool { - bw::test_bit16::<8>(self.af) - } - - fn n_flag(&self) -> bool { - bw::test_bit16::<7>(self.af) + pub fn set_f(&mut self, value: u8) { + self.af = bw::set_byte16::<0>(self.af, value); } - fn h_flag(&self) -> bool { - bw::test_bit16::<6>(self.af) - } - - fn c_flag(&self) -> bool { - bw::test_bit16::<5>(self.af) + pub fn a(&self) -> u8 { + bw::get_byte16::<1>(self.af) } pub fn set_a(&mut self, value: u8) { self.af = bw::set_byte16::<1>(self.af, value); } + pub fn af(&self) -> u16 { + self.af + } + pub fn set_af(&mut self, af: u16) { self.af = af; } + pub fn b(&self) -> u8 { + bw::get_byte16::<1>(self.bc) + } + pub fn set_b(&mut self, value: u8) { self.bc = bw::set_byte16::<1>(self.bc, value); } + pub fn c(&self) -> u8 { + bw::get_byte16::<0>(self.bc) + } + pub fn set_c(&mut self, value: u8) { self.bc = bw::set_byte16::<0>(self.bc, value); } + pub fn bc(&self) -> u16 { + self.bc + } + pub fn set_bc(&mut self, bc: u16) { self.bc = bc; } + pub fn d(&self) -> u8 { + bw::get_byte16::<1>(self.de) + } + pub fn set_d(&mut self, value: u8) { self.de = bw::set_byte16::<1>(self.de, value); } + pub fn e(&self) -> u8 { + bw::get_byte16::<0>(self.de) + } + pub fn set_e(&mut self, value: u8) { self.de = bw::set_byte16::<0>(self.de, value); } + pub fn de(&self) -> u16 { + self.de + } + pub fn set_de(&mut self, de: u16) { self.de = de; } + pub fn h(&self) -> u8 { + bw::get_byte16::<1>(self.hl) + } + pub fn set_h(&mut self, value: u8) { self.hl = bw::set_byte16::<1>(self.hl, value); } + pub fn l(&self) -> u8 { + bw::get_byte16::<0>(self.hl) + } + pub fn set_l(&mut self, value: u8) { self.hl = bw::set_byte16::<0>(self.hl, value); } + pub fn hl(&self) -> u16 { + self.hl + } pub fn set_hl(&mut self, hl: u16) { self.hl = hl; } - fn set_z_flag(&mut self, value: bool) { + pub fn z_flag(&self) -> bool { + bw::test_bit16::<8>(self.af) + } + + pub fn set_z_flag(&mut self, value: bool) { self.af = bw::set_bit16::<7>(self.af, value); } - fn set_n_flag(&mut self, value: bool) { + pub fn n_flag(&self) -> bool { + bw::test_bit16::<7>(self.af) + } + pub fn set_n_flag(&mut self, value: bool) { self.af = bw::set_bit16::<6>(self.af, value); } - fn set_h_flag(&mut self, value: bool) { + pub fn h_flag(&self) -> bool { + bw::test_bit16::<6>(self.af) + } + pub fn set_h_flag(&mut self, value: bool) { self.af = bw::set_bit16::<5>(self.af, value); } - fn set_c_flag(&mut self, value: bool) { + pub fn c_flag(&self) -> bool { + bw::test_bit16::<5>(self.af) + } + + pub fn set_c_flag(&mut self, value: bool) { self.af = bw::set_bit16::<4>(self.af, value); } - pub fn set_sp(&mut self, sp: u16) { - self.sp = sp; + pub fn clock_cycles(&mut self) -> u64 { + self.clock_cycles } - pub fn set_pc(&mut self, pc: u16) { - self.pc = pc; + pub fn set_clock_cycles(&mut self, clock_cycles: u64) { + self.clock_cycles = clock_cycles; } - pub fn set_memory8(&mut self, index: u16, value: u8) { - self.mem[index as usize] = value; + pub fn sp(&mut self) -> u16 { + self.sp } - fn memory8(&self, index: u16) -> u8 { - self.mem[index as usize] + pub fn set_sp(&mut self, sp: u16) { + self.sp = sp; } - fn load_bootrom(&mut self, bootrom: &[u8; 256]) { - self.mem[..256].clone_from_slice(bootrom); + pub fn pc(&mut self) -> u16 { + self.pc } - pub fn set_clock_cycles(&mut self, clock_cycles: u64) { - self.clock_cycles = clock_cycles; + pub fn set_pc(&mut self, pc: u16) { + self.pc = pc; } - /// get 8 bit immediate at position pc + 1 + pos - fn get_immediate8(&self, pos: u8) -> u8 { - self.mem[(self.pc as usize) + (pos as usize) + 1] + pub fn mem8(&self, index: u16) -> u8 { + self.mem[index as usize] } - /// get 16 bit immediate at position pc + 1 + pos - fn get_immediate16(&self, pos: u8) -> u16 { - // little-endian: the first byte in memory is the LSB - ((self.get_immediate8(pos + 1) as u16) << 8) + self.get_immediate8(pos) as u16 + pub fn set_mem8(&mut self, index: u16, value: u8) { + self.mem[index as usize] = value; } + fn load_bootrom(&mut self, bootrom: &[u8; 256]) { + self.mem[..256].clone_from_slice(bootrom); + } + + /// Run one cycle pub fn step(&mut self) { let mut opcode = self.mem[self.pc as usize] as u16; if self.next_cb { @@ -196,7 +218,6 @@ impl LR35902 { } let instruction = INSTRUCTIONS[opcode as usize]; println!("{:#02X} {}", instruction.opcode, instruction.mnemonic); - println!("{:?}", self); self.execute(instruction); if instruction.kind != InstructionKind::Jump { self.pc += instruction.size as u16; @@ -206,6 +227,35 @@ impl LR35902 { // TODO: measure time and panic if cycle time exceeded } + /// get 8 bit immediate at position pc + 1 + pos + fn get_d8(&self, pos: u8) -> u8 { + self.mem8(self.pc + pos as u16 + 1) + } + + /// get 16 bit immediate at position pc + 1 + pos + fn get_d16(&self, pos: u8) -> u16 { + // little-endian: the first byte in memory is the LSB + ((self.get_d8(pos + 1) as u16) << 8) + self.get_d8(pos) as u16 + } + + fn add8(&mut self, x: u8, y: u8) -> u8 { + let (result, overflow) = x.overflowing_add(y); + self.set_z_flag(result == 0); + self.set_n_flag(false); + self.set_h_flag(((x & 0x0f) + (y & 0x0f)) > 0x0f); + self.set_c_flag(overflow); + result + } + + fn add16(&mut self, x: u16, y: u16) -> u16 { + let (result, overflow) = x.overflowing_add(y); + self.set_z_flag(result == 0); + self.set_n_flag(false); + self.set_h_flag((((x >> 8) & 0x0f) + ((y >> 8) & 0x0f)) > 0x0f); + self.set_c_flag(overflow); + result + } + fn execute(&mut self, instruction: Instruction) { match instruction.opcode { 0x0 => { @@ -213,7 +263,7 @@ impl LR35902 { } 0x1 => { // LD BC,d16 - self.bc = self.get_immediate16(0); + self.bc = self.get_d16(0); } 0x2 => { // LD (BC),A @@ -245,7 +295,8 @@ impl LR35902 { } 0x9 => { // ADD HL,BC - unimplemented!() + let result = self.add16(self.hl(), self.bc()); + self.set_hl(result); } 0xA => { // LD A,(BC) @@ -277,7 +328,7 @@ impl LR35902 { } 0x11 => { // LD DE,d16 - self.de = self.get_immediate16(0); + self.de = self.get_d16(0); } 0x12 => { // LD (DE),A @@ -341,7 +392,7 @@ impl LR35902 { } 0x21 => { // LD HL,d16 - self.hl = self.get_immediate16(0); + self.hl = self.get_d16(0); } 0x22 => { // LD (HL+),A @@ -405,11 +456,11 @@ impl LR35902 { } 0x31 => { // LD SP,d16 - self.sp = self.get_immediate16(0); + self.sp = self.get_d16(0); } 0x32 => { // LD (HL-),A - self.set_memory8(self.hl, self.a()); + self.set_mem8(self.hl, self.a()); self.hl -= 1 } 0x33 => { @@ -458,7 +509,7 @@ impl LR35902 { } 0x3E => { // LD A,d8 - self.set_a(self.get_immediate8(0)); + self.set_a(self.get_d8(0)); } 0x3F => { // CCF @@ -723,40 +774,45 @@ impl LR35902 { } 0x80 => { // ADD A,B - let (result, overflow) = self.a().overflowing_add(self.b()); - self.set_z_flag(result == 0); - self.set_n_flag(false); - self.set_h_flag(((self.a() & 0b1111) + (self.b() & 0b1111)) > 0b1111); - self.set_c_flag(overflow); + let result = self.add8(self.a(), self.b()); self.set_a(result); } 0x81 => { // ADD A,C - unimplemented!() + let result = self.add8(self.a(), self.c()); + self.set_a(result); } 0x82 => { // ADD A,D - unimplemented!() + let result = self.add8(self.a(), self.d()); + self.set_a(result); } 0x83 => { // ADD A,E - unimplemented!() + let result = self.add8(self.a(), self.e()); + self.set_a(result); } 0x84 => { // ADD A,H - unimplemented!() + let result = self.add8(self.a(), self.h()); + self.set_a(result); } 0x85 => { // ADD A,L - unimplemented!() + let result = self.add8(self.a(), self.l()); + self.set_a(result); } 0x86 => { // ADD A,(HL) - unimplemented!() + // TODO: not tested + let result = self.add8(self.a(), self.mem[self.hl() as usize]); + self.set_a(result); } 0x87 => { // ADD A,A - unimplemented!() + // TODO: not working + let result = self.add8(self.a(), self.a()); + self.set_a(result); } 0x88 => { // ADC A,B @@ -1013,7 +1069,8 @@ impl LR35902 { } 0xC6 => { // ADD A,d8 - unimplemented!() + let result = self.add8(self.a(), self.get_d8(0)); + self.set_a(result); } 0xC7 => { // RST 00H @@ -1125,7 +1182,7 @@ impl LR35902 { } 0xE2 => { // LD (C),A - self.set_memory8(self.c().into(), self.a()); + self.set_mem8(self.c().into(), self.a()); } 0xE3 => { // Not implemented @@ -2375,7 +2432,7 @@ mod tests { bootrom[2] = 3; cpu.load_bootrom(&bootrom); - assert_eq!(cpu.get_immediate8(0), 2); + assert_eq!(cpu.get_d8(0), 2); } #[test] @@ -2387,14 +2444,14 @@ mod tests { bootrom[2] = 3; cpu.load_bootrom(&bootrom); - assert_eq!(cpu.get_immediate16(0), 3 * 256 + 2); + assert_eq!(cpu.get_d16(0), 3 * 256 + 2); } #[test] fn test_memory() { let mut cpu = LR35902::default(); - cpu.set_memory8(10, 255); - assert_eq!(cpu.memory8(10), 255); + cpu.set_mem8(10, 255); + assert_eq!(cpu.mem8(10), 255); } } diff --git a/tests/lr35902.rs b/tests/lr35902.rs index b488178..f4029c6 100644 --- a/tests/lr35902.rs +++ b/tests/lr35902.rs @@ -15,7 +15,7 @@ impl LR35902Builder { } } - pub fn with_register(mut self, register: &str, value: u8) -> Self { + pub fn with_reg8(self, register: &str, value: u8) -> Self { match register { "b" => self.with_b(value), "c" => self.with_c(value), @@ -27,11 +27,31 @@ impl LR35902Builder { _ => panic!(), } } - pub fn with_af(mut self, af: u16) -> Self { - self.lr35902.set_af(af); + + // pub fn with_reg16(self, register: &str, value: u16) -> Self { + // match register { + // "bc" => self.with_bc(value), + // "de" => self.with_de(value), + // "hl" => self.with_hl(value), + // _ => panic!(), + // } + // } + + pub fn with_a(mut self, a: u8) -> Self { + self.lr35902.set_a(a); self } + pub fn with_f(mut self, f: u8) -> Self { + self.lr35902.set_f(f); + self + } + + // pub fn with_af(mut self, af: u16) -> Self { + // self.lr35902.set_af(af); + // self + // } + pub fn with_b(mut self, b: u8) -> Self { self.lr35902.set_b(b); self @@ -42,13 +62,23 @@ impl LR35902Builder { self } + pub fn with_bc(mut self, bc: u16) -> Self { + self.lr35902.set_bc(bc); + self + } + pub fn with_d(mut self, d: u8) -> Self { self.lr35902.set_d(d); self } pub fn with_e(mut self, e: u8) -> Self { - self.lr35902.set_d(e); + self.lr35902.set_e(e); + self + } + + pub fn with_de(mut self, de: u16) -> Self { + self.lr35902.set_de(de); self } @@ -62,21 +92,6 @@ impl LR35902Builder { self } - pub fn with_a(mut self, a: u8) -> Self { - self.lr35902.set_a(a); - self - } - - pub fn with_bc(mut self, bc: u16) -> Self { - self.lr35902.set_bc(bc); - self - } - - pub fn with_de(mut self, de: u16) -> Self { - self.lr35902.set_de(de); - self - } - pub fn with_hl(mut self, hl: u16) -> Self { self.lr35902.set_hl(hl); self @@ -106,7 +121,7 @@ impl LR35902Builder { //} pub fn with_memory_byte(mut self, index: u16, value: u8) -> LR35902Builder { - self.lr35902.set_memory8(index, value); + self.lr35902.set_mem8(index, value); self } @@ -243,58 +258,59 @@ fn test_instr_0x032_ld_hld_a(#[case] a: u8, #[case] hl: u16) { } #[rstest] -#[case(0x40, "b", "b", 0x01)] // 1 -#[case(0x40, "b", "b", 0xFF)] // 2 +#[case(0x40, "b", "b", 0x01)] // 1 +#[case(0x40, "b", "b", 0xFF)] // 2 #[case(0x41, "b", "c", 0x01)] // 3 #[case(0x41, "b", "c", 0xFF)] // 4 #[case(0x42, "b", "d", 0x01)] // 5 #[case(0x42, "b", "d", 0xFF)] // 6 -//#[case(0x43, "b", "e", 0x01)] // 7 +//#[case(0x43, "b", "e", 0x01)] // 7 //#[case(0x43, "b", "e", 0xFF)] // 8 #[case(0x44, "b", "h", 0x01)] // 9 -#[case(0x44, "b", "h", 0xFF)] // 10 +#[case(0x44, "b", "h", 0xFF)] // 10 #[case(0x45, "b", "l", 0x01)] // 11 #[case(0x45, "b", "l", 0xFF)] // 12 #[case(0x47, "b", "a", 0x01)] // 13 #[case(0x47, "b", "a", 0xFF)] // 14 #[case(0x48, "c", "b", 0x01)] // 13 #[case(0x48, "c", "b", 0xFF)] // 14 -#[case(0x49, "c", "c", 0x01)] // 15 -#[case(0x49, "c", "c", 0xFF)] // 16 +#[case(0x49, "c", "c", 0x01)] // 15 +#[case(0x49, "c", "c", 0xFF)] // 16 #[case(0x4A, "c", "d", 0x01)] // 17 #[case(0x4A, "c", "d", 0xFF)] // 18 //#[case(0x4B, "c", "e", 0x01)] // 19 //#[case(0x4B, "c", "e", 0xFF)] // 20 #[case(0x4C, "c", "h", 0x01)] // 21 -#[case(0x4C, "c", "h", 0xFF)] // 22 +#[case(0x4C, "c", "h", 0xFF)] // 22 #[case(0x4D, "c", "l", 0x01)] // 23 #[case(0x4D, "c", "l", 0xFF)] // 24 #[case(0x4F, "c", "a", 0x01)] // 25 #[case(0x4F, "c", "a", 0xFF)] // 26 #[case(0x50, "d", "b", 0x01)] // 27 -#[case(0x50, "d", "b", 0xFF)] // 28 -//#[case(0x51, "d", "c", 0x01)] // 29 -//#[case(0x51, "d", "c", 0xFF)] // 30 +#[case(0x50, "d", "b", 0xFF)] +// 28 +//#[case(0x51, "d", "c", 0x01)] // 29 +//#[case(0x51, "d", "c", 0xFF)] // 30 //#[case(0x52, "d", "d", 0x01)] // 31 //#[case(0x52, "d", "d", 0xFF)] // 32 //#[case(0x53, "d", "e", 0x01)] // 33 //#[case(0x53, "d", "e", 0xFF)] // 34 #[case(0x54, "d", "h", 0x01)] // 35 -#[case(0x54, "d", "h", 0xFF)] // 36 +#[case(0x54, "d", "h", 0xFF)] // 36 #[case(0x55, "d", "l", 0x01)] // 37 #[case(0x55, "d", "l", 0xFF)] // 38 #[case(0x57, "d", "a", 0x01)] // 39 #[case(0x57, "d", "a", 0xFF)] // 40 fn test_load_8_bit_reg_to_8_bit_reg( - #[case] instr: u8, + #[case] opcode: u8, #[case] dst_reg: &str, #[case] src_reg: &str, #[case] value: u8, ) { // Given let builder = LR35902Builder::new() - .with_memory_byte(0x0000, instr) // instruction LD (HL-), a - .with_register(src_reg, value); + .with_memory_byte(0x0000, opcode) + .with_reg8(src_reg, value); let mut sut = builder.clone().build(); // When @@ -304,21 +320,33 @@ fn test_load_8_bit_reg_to_8_bit_reg( let expected = builder .with_pc(1) .with_clock_cycles(4) - .with_register(dst_reg, value) // hl gets decremented + .with_reg8(dst_reg, value) // hl gets decremented .build(); assert_eq!(sut, expected); } #[rstest] -#[case(0xfe, 0x01, 0xff, 0b0000)] // no flags -#[case(0x0f, 0x01, 0x10, 0b0010)] // half carry -#[case(0xff, 0x01, 0x00, 0b1011)] // zero, half carry and carry -fn test_add(#[case] a: u16, #[case] b: u16, #[case] r: u16, #[case] f: u16) { +#[case(0x80, "b", 0xfe, 0x01, 0xff, 0b0000)] // no flags +#[case(0x80, "b", 0x0f, 0x01, 0x10, 0b0010)] // half carry +#[case(0x80, "b", 0xff, 0x01, 0x00, 0b1011)] // zero, half carry and carry +#[case(0x81, "c", 0xff, 0x01, 0x00, 0b1011)] // zero, half carry and carry +#[case(0x82, "d", 0xff, 0x01, 0x00, 0b1011)] // zero, half carry and carry +#[case(0x83, "e", 0xff, 0x01, 0x00, 0b1011)] // zero, half carry and carry +#[case(0x84, "h", 0xff, 0x01, 0x00, 0b1011)] // zero, half carry and carry +#[case(0x85, "l", 0xff, 0x01, 0x00, 0b1011)] // zero, half carry and carry +fn test_add8( + #[case] opcode: u8, + #[case] src_reg: &str, + #[case] a: u8, + #[case] y: u8, + #[case] r: u8, + #[case] f: u8, +) { // Given let builder = LR35902Builder::new() - .with_memory_byte(0x0000, 0x80) // instruction ADD AF, BC - .with_af(a << 8) - .with_bc(b << 8); + .with_memory_byte(0x0000, opcode) + .with_a(a) + .with_reg8(src_reg, y); let mut sut = builder.clone().build(); // When @@ -327,8 +355,9 @@ fn test_add(#[case] a: u16, #[case] b: u16, #[case] r: u16, #[case] f: u16) { // Then let expected = builder .with_pc(1) - .with_af((r << 8) + (f << 4)) - .with_bc(b << 8) + .with_a(r) + .with_f(f << 4) + .with_reg8(src_reg, y) .with_clock_cycles(4) .build(); assert_eq!(sut, expected);