diff --git a/src/bus.rs b/src/bus.rs index a78aca0..3b10a1e 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -1,3 +1,5 @@ +use crate::instruction::Cycles; + use super::cartridge::Cartridge; use super::high_ram::HighRAM; use super::interrupt::Interrupt; @@ -50,6 +52,12 @@ impl Bus { pub fn load_cartridge(&mut self, path: &str) { self.cartridge = Some(Cartridge::new(path).unwrap()); } + + pub fn step(&mut self, cycles: Cycles) { + let _ = self.timer.step(cycles); + let _ = self.sound.step(cycles); + let _ = self.ppu.step(cycles); + } } impl Bus { diff --git a/src/cpu.rs b/src/cpu.rs index 673dea9..0db9dea 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -68,6 +68,21 @@ impl Cpu { pub fn execute(&mut self, instruction: Instruction) -> Cycles { Instruction::execute(self, instruction) } + + pub fn step(&mut self) -> Cycles { + let opcode = self.fetch(); + let instr = self.decode(opcode); + let cycles = self.execute(instr); + + println!( + "Addr: {:#06X} | Opcode: {:#04X} | Instr: {:X?}", + self.reg.pc, opcode, instr + ); + + self.bus.step(cycles); + + cycles + } } impl Cpu { diff --git a/src/high_ram.rs b/src/high_ram.rs index a78c429..b445753 100644 --- a/src/high_ram.rs +++ b/src/high_ram.rs @@ -6,7 +6,7 @@ pub struct HighRAM { impl Default for HighRAM { fn default() -> Self { Self { - buf: vec![0u8; 127].into_boxed_slice(), + buf: vec![0u8; 128].into_boxed_slice(), } } } diff --git a/src/instruction.rs b/src/instruction.rs index ee8e4b9..527f6df 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -118,18 +118,18 @@ pub enum JumpCondition { #[derive(Debug, Copy, Clone)] struct Table; -#[derive(Debug, Copy, Clone)] -pub struct Cycles(u8); +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Cycles(u32); impl Instruction { pub fn execute(cpu: &mut Cpu, instruction: Self) -> Cycles { match instruction { - Instruction::NOP => Cycles(4), + Instruction::NOP => Cycles::new(4), Instruction::LD(lhs, rhs) => match (lhs, rhs) { (LDTarget::ByteAtAddress(nn), LDTarget::RegisterPair(RegisterPair::SP)) => { // LD (nn), SP | Put Stack Pointer at address nn cpu.write_word(nn, cpu.register_pair(RegisterPair::SP)); - Cycles(20) + Cycles::new(20) } (LDTarget::RegisterPair(pair), LDTarget::ImmediateWord(nn)) => { // LD rp[p], nn | Put value nn into register pair @@ -140,7 +140,7 @@ impl Instruction { | RegisterPair::SP => cpu.set_register_pair(pair, nn), _ => unreachable!(), } - Cycles(12) + Cycles::new(12) } (LDTarget::IndirectRegister(pair), LDTarget::Register(InstrRegister::A)) => { let a = cpu.register(Register::A); @@ -167,7 +167,7 @@ impl Instruction { } _ => unreachable!(), } - Cycles(8) + Cycles::new(8) } (LDTarget::Register(InstrRegister::A), LDTarget::IndirectRegister(pair)) => { match pair { @@ -196,7 +196,7 @@ impl Instruction { } _ => unreachable!(), } - Cycles(8) + Cycles::new(8) } (LDTarget::Register(reg), LDTarget::ImmediateByte(n)) => { // LD r[y], n | Store n in Register @@ -204,7 +204,7 @@ impl Instruction { InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); cpu.write_byte(addr, n); - Cycles(12) + Cycles::new(12) } InstrRegister::A | InstrRegister::B @@ -214,7 +214,7 @@ impl Instruction { | InstrRegister::H | InstrRegister::L => { cpu.set_register(Register::try_from(reg).unwrap(), n); - Cycles(8) + Cycles::new(8) } } } @@ -222,13 +222,13 @@ impl Instruction { // LD (0xFF00 + C), A | Store value of register A at address 0xFF00 + C let addr = 0xFF00 + cpu.register(Register::C) as u16; cpu.write_byte(addr, cpu.register(Register::A)); - Cycles(8) + Cycles::new(8) } (LDTarget::Register(InstrRegister::A), LDTarget::IndirectC) => { let addr = 0xFF00 + cpu.register(Register::C) as u16; let byte = cpu.read_byte(addr); cpu.set_register(Register::A, byte); - Cycles(8) + Cycles::new(8) } (LDTarget::Register(lhs), LDTarget::Register(rhs)) => { // LD r[y], r[z] | Store value of RHS Register in LHS Register @@ -258,25 +258,25 @@ impl Instruction { | InstrRegister::L | InstrRegister::A => { cpu.set_register(Register::try_from(lhs).unwrap(), rhs_value); - Cycles(4) + Cycles::new(4) } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); cpu.write_byte(addr, rhs_value); - Cycles(8) + Cycles::new(8) } } } (LDTarget::ByteAtAddressWithOffset(n), LDTarget::Register(InstrRegister::A)) => { // LD (0xFF00 + n), A | Store register A at address (0xFF00 + n) cpu.write_byte(0xFF00 + (n as u16), cpu.register(Register::A)); - Cycles(12) + Cycles::new(12) } (LDTarget::Register(InstrRegister::A), LDTarget::ByteAtAddressWithOffset(n)) => { // LD A, (0xFF00 + n) | Store value at address (0xFF00 + n) in register A let byte = cpu.read_byte(0xFF00 + (n as u16)); cpu.set_register(Register::A, byte); - Cycles(12) + Cycles::new(12) } ( LDTarget::RegisterPair(RegisterPair::SP), @@ -284,20 +284,20 @@ impl Instruction { ) => { // LD SP, HL | Load Register HL into Register SP cpu.set_register_pair(RegisterPair::SP, cpu.register_pair(RegisterPair::HL)); - Cycles(8) + Cycles::new(8) } (LDTarget::ByteAtAddress(nn), LDTarget::Register(InstrRegister::A)) => { cpu.write_byte(nn, cpu.register(Register::A)); - Cycles(16) + Cycles::new(16) } (LDTarget::Register(InstrRegister::A), LDTarget::ByteAtAddress(nn)) => { let byte = cpu.read_byte(nn); cpu.set_register(Register::A, byte); - Cycles(16) + Cycles::new(16) } _ => unreachable!(), }, - Instruction::STOP => Cycles(4), + Instruction::STOP => Cycles::new(4), Instruction::JR(cond, offset) => { // JR cc[y - 4], d | If condition is true, then add d to current address and jump // JR d | Add d to current address and jump @@ -308,36 +308,36 @@ impl Instruction { match cond { JumpCondition::Always => { cpu.set_register_pair(RegisterPair::PC, new_addr); - Cycles(12) + Cycles::new(12) } JumpCondition::NotZero => { if !flags.z { cpu.set_register_pair(RegisterPair::PC, new_addr); - return Cycles(12); + return Cycles::new(12); } - Cycles(8) + Cycles::new(8) } JumpCondition::Zero => { if flags.z { cpu.set_register_pair(RegisterPair::PC, new_addr); - return Cycles(12); + return Cycles::new(12); } - Cycles(8) + Cycles::new(8) } JumpCondition::NotCarry => { if !flags.c { cpu.set_register_pair(RegisterPair::PC, new_addr); - return Cycles(12); + return Cycles::new(12); } - Cycles(8) + Cycles::new(8) } JumpCondition::Carry => { if flags.c { cpu.set_register_pair(RegisterPair::PC, new_addr); - return Cycles(12); + return Cycles::new(12); } - Cycles(8) + Cycles::new(8) } } } @@ -360,7 +360,7 @@ impl Instruction { _ => unreachable!(), } cpu.set_register(Register::Flag, flags.into()); - Cycles(8) + Cycles::new(8) } (MATHTarget::Register(InstrRegister::A), MATHTarget::Register(reg)) => { // ADD A, r[z] | Add (A + r[z]) to register A @@ -378,12 +378,12 @@ impl Instruction { | InstrRegister::A => { let value = cpu.register(Register::try_from(reg).unwrap()); sum = Self::add_u8s(a_value, value, &mut flags); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); sum = Self::add_u8s(a_value, value, &mut flags); - cycles = Cycles(4); + cycles = Cycles::new(4); } } @@ -397,7 +397,7 @@ impl Instruction { let d = d as i8; let sum = Self::add_u16_i8(cpu.register_pair(RegisterPair::SP), d, &mut flags); cpu.set_register_pair(RegisterPair::SP, sum); - Cycles(16) + Cycles::new(16) } (MATHTarget::Register(InstrRegister::A), MATHTarget::ImmediateByte(n)) => { // ADD A, n | Add n to register A @@ -406,7 +406,7 @@ impl Instruction { cpu.set_register(Register::A, sum); cpu.set_register(Register::Flag, flags.into()); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -429,13 +429,13 @@ impl Instruction { let value = cpu.register(reg); cpu.set_register(reg, Self::inc_register(value, &mut flags)); - cycles = Cycles(4) + cycles = Cycles::new(4) } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); let byte = Self::inc_register(cpu.read_byte(addr), &mut flags); cpu.write_byte(addr, byte); - cycles = Cycles(12) + cycles = Cycles::new(12) } } cpu.set_register(Register::Flag, flags.into()); @@ -453,7 +453,7 @@ impl Instruction { } _ => unreachable!(), } - Cycles(8) + Cycles::new(8) } } } @@ -466,7 +466,7 @@ impl Instruction { } _ => unreachable!(), } - Cycles(8) + Cycles::new(8) } Instruction::DEC(Registers::Byte(reg)) => { // DEC r[y] | Decrement Register @@ -485,13 +485,13 @@ impl Instruction { let value = cpu.register(reg); cpu.set_register(reg, Self::dec_register(value, &mut flags)); - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); let byte = cpu.read_byte(addr); cpu.write_byte(addr, Self::dec_register(byte, &mut flags)); - cycles = Cycles(12); + cycles = Cycles::new(12); } } cpu.set_register(Register::Flag, flags.into()); @@ -508,7 +508,7 @@ impl Instruction { flags.update(false, false, false, msb == 0x01); cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, rot_a); - Cycles(4) + Cycles::new(4) } Instruction::RRCA => { // Rotate Register A right @@ -521,7 +521,7 @@ impl Instruction { flags.update(false, false, false, lsb == 0x01); cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, rot_a); - Cycles(4) + Cycles::new(4) } Instruction::RLA => { // Rotate register A left through carry @@ -533,7 +533,7 @@ impl Instruction { flags.update(false, false, false, carry); cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, rot_a); - Cycles(4) + Cycles::new(4) } Instruction::RRA => { // Rotate register A right through carry @@ -545,7 +545,7 @@ impl Instruction { flags.update(false, false, false, carry); cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, rot_a); - Cycles(4) + Cycles::new(4) } Instruction::DAA => unimplemented!(), Instruction::CPL => { @@ -558,7 +558,7 @@ impl Instruction { cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, !a); // Bitwise not is ! instead of ~ - Cycles(4) + Cycles::new(4) } Instruction::SCF => { // Set Carry Flag @@ -569,7 +569,7 @@ impl Instruction { flags.c = true; cpu.set_register(Register::Flag, flags.into()); - Cycles(4) + Cycles::new(4) } Instruction::CCF => { // Compliment Carry Flag (inverse) @@ -580,7 +580,7 @@ impl Instruction { flags.c = !flags.c; cpu.set_register(Register::Flag, flags.into()); - Cycles(4) + Cycles::new(4) } Instruction::HALT => unimplemented!(), Instruction::ADC(target) => match target { @@ -603,12 +603,12 @@ impl Instruction { let value = cpu.register(Register::try_from(reg).unwrap()) + (flags.c as u8); sum = Self::add_u8s(a_value, value, &mut flags); - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); sum = Self::add_u8s(a_value, value, &mut flags); - cycles = Cycles(8); + cycles = Cycles::new(8); } } cpu.set_register(Register::Flag, flags.into()); @@ -623,7 +623,7 @@ impl Instruction { cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, sum); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -645,12 +645,12 @@ impl Instruction { | InstrRegister::A => { let value = cpu.register(Register::try_from(reg).unwrap()); diff = Self::sub_u8s(a_value, value, &mut flags); - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); diff = Self::sub_u8s(a_value, value, &mut flags); - cycles = Cycles(8); + cycles = Cycles::new(8); } } @@ -665,7 +665,7 @@ impl Instruction { cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, diff); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -689,12 +689,12 @@ impl Instruction { let value = cpu.register(Register::try_from(reg).unwrap()) + (flags.c as u8); diff = Self::sub_u8s(a_value, value, &mut flags); - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); diff = Self::sub_u8s(a_value, value, &mut flags); - cycles = Cycles(8); + cycles = Cycles::new(8); } } @@ -711,7 +711,7 @@ impl Instruction { cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, diff); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -733,12 +733,12 @@ impl Instruction { | InstrRegister::A => { let value = cpu.register(Register::try_from(reg).unwrap()); result = a_value & value; - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); result = a_value & value; - cycles = Cycles(8); + cycles = Cycles::new(8); } } @@ -755,7 +755,7 @@ impl Instruction { flags.update(result == 0, false, true, false); cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, result); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -777,12 +777,12 @@ impl Instruction { | InstrRegister::A => { let value = cpu.register(Register::try_from(reg).unwrap()); result = a_value ^ value; - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); result = a_value ^ value; - cycles = Cycles(8); + cycles = Cycles::new(8); } } @@ -799,7 +799,7 @@ impl Instruction { flags.update(result == 0, false, false, false); cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, result); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -821,12 +821,12 @@ impl Instruction { | InstrRegister::A => { let value = cpu.register(Register::try_from(reg).unwrap()); result = a_value | value; - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); result = a_value | value; - cycles = Cycles(8); + cycles = Cycles::new(8); } } @@ -843,7 +843,7 @@ impl Instruction { flags.update(result == 0, false, false, false); cpu.set_register(Register::Flag, flags.into()); cpu.set_register(Register::A, result); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -864,12 +864,12 @@ impl Instruction { | InstrRegister::A => { let value = cpu.register(Register::try_from(reg).unwrap()); let _ = Self::sub_u8s(a_value, value, &mut flags); - cycles = Cycles(4); + cycles = Cycles::new(4); } InstrRegister::IndirectHL => { let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); let _ = Self::sub_u8s(a_value, value, &mut flags); - cycles = Cycles(8); + cycles = Cycles::new(8); } } @@ -882,7 +882,7 @@ impl Instruction { let _ = Self::sub_u8s(cpu.register(Register::A), n, &mut flags); cpu.set_register(Register::Flag, flags.into()); - Cycles(8) + Cycles::new(8) } _ => unreachable!(), }, @@ -896,38 +896,38 @@ impl Instruction { if !flags.z { let addr = Self::pop(cpu); cpu.set_register_pair(RegisterPair::PC, addr); - return Cycles(20); + return Cycles::new(20); } - Cycles(8) + Cycles::new(8) } JumpCondition::Zero => { if flags.z { let addr = Self::pop(cpu); cpu.set_register_pair(RegisterPair::PC, addr); - return Cycles(20); + return Cycles::new(20); } - Cycles(8) + Cycles::new(8) } JumpCondition::NotCarry => { if !flags.c { let addr = Self::pop(cpu); cpu.set_register_pair(RegisterPair::PC, addr); - return Cycles(20); + return Cycles::new(20); } - Cycles(8) + Cycles::new(8) } JumpCondition::Carry => { if flags.c { let addr = Self::pop(cpu); cpu.set_register_pair(RegisterPair::PC, addr); - return Cycles(20); + return Cycles::new(20); } - Cycles(8) + Cycles::new(8) } JumpCondition::Always => { let addr = Self::pop(cpu); cpu.set_register_pair(RegisterPair::PC, addr); - Cycles(16) + Cycles::new(16) } } } @@ -937,7 +937,7 @@ impl Instruction { let mut flags: Flags = cpu.register(Register::Flag).into(); let sum = Self::add_u16_i8(cpu.register_pair(RegisterPair::SP), d, &mut flags); cpu.set_register_pair(RegisterPair::HL, sum); - Cycles(12) + Cycles::new(12) } Instruction::POP(pair) => { // POP rp2[p] | Pop from stack into register pair rp[2] @@ -949,20 +949,20 @@ impl Instruction { } _ => unreachable!(), } - Cycles(12) + Cycles::new(12) } Instruction::RETI => { // Same as RET, after which interrupts are enabled. let addr = Self::pop(cpu); cpu.set_register_pair(RegisterPair::PC, addr); cpu.set_ime(true); - Cycles(16) + Cycles::new(16) } Instruction::JP(cond, target) => match target { JPTarget::RegisterPair(RegisterPair::HL) => { // JP HL | Load register pair HL into program counter cpu.set_register_pair(RegisterPair::PC, cpu.register_pair(RegisterPair::HL)); - Cycles(4) + Cycles::new(4) } JPTarget::ImmediateWord(nn) => { // JP cc[y], nn | Store Immediate Word in the Program Counter if cond is met @@ -973,34 +973,34 @@ impl Instruction { JumpCondition::NotZero => { if !flags.z { cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(16); + return Cycles::new(16); } - Cycles(12) + Cycles::new(12) } JumpCondition::Zero => { if flags.z { cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(16); + return Cycles::new(16); } - Cycles(12) + Cycles::new(12) } JumpCondition::NotCarry => { if !flags.c { cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(16); + return Cycles::new(16); } - Cycles(12) + Cycles::new(12) } JumpCondition::Carry => { if flags.c { cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(16); + return Cycles::new(16); } - Cycles(12) + Cycles::new(12) } JumpCondition::Always => { cpu.set_register_pair(RegisterPair::PC, nn); - Cycles(16) + Cycles::new(16) } } } @@ -1009,13 +1009,13 @@ impl Instruction { Instruction::DI => { // Disable IME cpu.set_ime(false); - Cycles(4) + Cycles::new(4) } Instruction::EI => { // Enable IME (After the next instruction) // FIXME: IME is set after the next instruction, this currently is not represented in this emulator. cpu.set_ime(true); - Cycles(4) + Cycles::new(4) } Instruction::CALL(cond, nn) => { // CALL cc[y], nn | Store nn on the stack, then store nn in the program coutner if cond is met @@ -1028,38 +1028,38 @@ impl Instruction { if !flags.z { Self::push(cpu, pc); cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(24); + return Cycles::new(24); } - Cycles(12) + Cycles::new(12) } JumpCondition::Zero => { if flags.z { Self::push(cpu, pc); cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(24); + return Cycles::new(24); } - Cycles(12) + Cycles::new(12) } JumpCondition::NotCarry => { if !flags.c { Self::push(cpu, pc); cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(24); + return Cycles::new(24); } - Cycles(12) + Cycles::new(12) } JumpCondition::Carry => { if flags.c { Self::push(cpu, pc); cpu.set_register_pair(RegisterPair::PC, nn); - return Cycles(24); + return Cycles::new(24); } - Cycles(12) + Cycles::new(12) } JumpCondition::Always => { Self::push(cpu, pc); cpu.set_register_pair(RegisterPair::PC, nn); - Cycles(24) + Cycles::new(24) } } } @@ -1072,14 +1072,14 @@ impl Instruction { } _ => unreachable!(), } - Cycles(16) + Cycles::new(16) } Instruction::RST(n) => { // RST n | Push current address onto the stack, jump to 0x0000 + n let addr = cpu.register_pair(RegisterPair::PC); Self::push(cpu, addr); cpu.set_register_pair(RegisterPair::PC, n as u16); - Cycles(16) + Cycles::new(16) } Instruction::RLC(reg) => { // RLC r[z] | Rotate register r[z] left @@ -1103,7 +1103,7 @@ impl Instruction { rot_reg = value.rotate_left(1); cpu.set_register(register, rot_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); @@ -1113,7 +1113,7 @@ impl Instruction { rot_reg = value.rotate_left(1); cpu.write_byte(addr, rot_reg); - cycles = Cycles(16); + cycles = Cycles::new(16); } } @@ -1143,7 +1143,7 @@ impl Instruction { rot_reg = value.rotate_right(1); cpu.set_register(register, rot_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); @@ -1153,7 +1153,7 @@ impl Instruction { rot_reg = value.rotate_right(1); cpu.write_byte(addr, rot_reg); - cycles = Cycles(16); + cycles = Cycles::new(16); } } @@ -1184,7 +1184,7 @@ impl Instruction { carry = new_carry; cpu.set_register(register, rot_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); @@ -1195,7 +1195,7 @@ impl Instruction { carry = new_carry; cpu.write_byte(addr, rot_reg); - cycles = Cycles(16); + cycles = Cycles::new(16); } } @@ -1227,7 +1227,7 @@ impl Instruction { carry = new_carry; cpu.set_register(register, rot_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); @@ -1238,7 +1238,7 @@ impl Instruction { carry = new_carry; cpu.write_byte(addr, rot_reg); - cycles = Cycles(16); + cycles = Cycles::new(16); } } @@ -1269,7 +1269,7 @@ impl Instruction { shift_reg = value << 1; cpu.set_register(register, shift_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); @@ -1279,7 +1279,7 @@ impl Instruction { shift_reg = value << 1; cpu.write_byte(addr, value); - cycles = Cycles(16); + cycles = Cycles::new(16); } } @@ -1311,7 +1311,7 @@ impl Instruction { shift_reg = (value >> 1) | (msb << 7); // msb is duplicated in this op cpu.set_register(register, shift_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); @@ -1322,7 +1322,7 @@ impl Instruction { shift_reg = (value >> 1) | (msb << 7); // msb is duplicated in this op cpu.write_byte(addr, value); - cycles = Cycles(16); + cycles = Cycles::new(16); } } @@ -1351,7 +1351,7 @@ impl Instruction { swap_reg = Self::swap_bits(value); cpu.set_register(register, swap_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { @@ -1361,7 +1361,7 @@ impl Instruction { swap_reg = Self::swap_bits(value); cpu.write_byte(addr, swap_reg); - cycles = Cycles(16) + cycles = Cycles::new(16) } } @@ -1392,7 +1392,7 @@ impl Instruction { shift_reg = value >> 1; cpu.set_register(register, shift_reg); - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); @@ -1402,7 +1402,7 @@ impl Instruction { shift_reg = value >> 1; cpu.write_byte(addr, shift_reg); - cycles = Cycles(16); + cycles = Cycles::new(16); } } @@ -1428,14 +1428,14 @@ impl Instruction { let value = cpu.register(register); is_bit_set = ((value >> y) & 0x01) == 0x01; - cycles = Cycles(8); + cycles = Cycles::new(8); } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); let value = cpu.read_byte(addr); is_bit_set = ((value >> y) & 0x01) == 0x01; - cycles = Cycles(12); + cycles = Cycles::new(12); } } @@ -1462,14 +1462,14 @@ impl Instruction { let value = cpu.register(register); cpu.set_register(register, value & !(1u8 << y)); - Cycles(8) + Cycles::new(8) } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); let value = cpu.read_byte(addr); cpu.write_byte(addr, value & !(1u8 << y)); - Cycles(16) + Cycles::new(16) } } } @@ -1490,14 +1490,14 @@ impl Instruction { let value = cpu.register(register); cpu.set_register(register, value | (1u8 << y)); - Cycles(8) + Cycles::new(8) } InstrRegister::IndirectHL => { let addr = cpu.register_pair(RegisterPair::HL); let value = cpu.read_byte(addr); cpu.write_byte(addr, value | (1u8 << y)); - Cycles(16) + Cycles::new(16) } } } @@ -2085,3 +2085,80 @@ impl std::fmt::Debug for Registers { } } } + +impl Cycles { + pub fn new(num: u32) -> Self { + Self(num) + } +} + +impl std::ops::Add for Cycles { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl std::ops::Add for Cycles { + type Output = Self; + + fn add(self, rhs: u32) -> Self::Output { + Self(self.0 + rhs) + } +} + +impl std::ops::AddAssign for Cycles { + fn add_assign(&mut self, rhs: Self) { + *self = Self(self.0 + rhs.0); + } +} + +impl std::ops::AddAssign for Cycles { + fn add_assign(&mut self, rhs: u32) { + *self = Self(self.0 + rhs); + } +} + +impl std::ops::Rem for Cycles { + type Output = Self; + + fn rem(self, rhs: Self) -> Self::Output { + Self(self.0 % rhs.0) + } +} + +impl std::ops::Rem for Cycles { + type Output = Self; + + fn rem(self, rhs: u32) -> Self::Output { + Self(self.0 % rhs) + } +} + +impl From for Cycles { + fn from(num: u32) -> Self { + Self(num) + } +} + +#[cfg(test)] +mod tests { + use super::Cycles; + + #[test] + fn cycle_add_works() { + let lhs: Cycles = Cycles::new(0); + let rhs: Cycles = Cycles::new(0); + + assert_eq!(Cycles::new(9), rhs + lhs); + } + + #[test] + fn cycle_add_assign_works() { + let mut cycles: Cycles = Cycles::new(0); + cycles += 5; + + assert_eq!(Cycles::new(10), cycles); + } +} diff --git a/src/main.rs b/src/main.rs index c6a7dc9..1f9e976 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use anyhow::{anyhow, Result}; use gb::cpu::Cpu as LR35902; use pixels::{Pixels, SurfaceTexture}; -use std::io::Write; use winit::{ dpi::LogicalSize, event::{Event, VirtualKeyCode}, @@ -20,9 +19,6 @@ fn main() -> Result<()> { let mut input = WinitInputHelper::new(); let window = create_window(&event_loop)?; let mut pixels = create_pixels(&window)?; - - let out = Box::leak(Box::new(std::io::stdout())); - let mut out_handle = out.lock(); let mut game_boy = LR35902::new(); game_boy.load_cartridge("bin/cpu_instrs.gb"); @@ -54,19 +50,8 @@ fn main() -> Result<()> { } // Emulation - let addr = game_boy.register_pair(gb::cpu::RegisterPair::PC); - - let opcode = game_boy.fetch(); - let instruction = game_boy.decode(opcode); - let _cycles = game_boy.execute(instruction); - window.request_redraw(); - - write!( - out_handle, - "Addr: {:#06X} | Opcode: {:#04X} | Instr: {:X?}\n", - addr, opcode, instruction - ) - .unwrap(); + let _cycles = game_boy.step(); + // window.request_redraw(); } }); diff --git a/src/ppu.rs b/src/ppu.rs index a030c23..a84c6f7 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -1,14 +1,32 @@ +use crate::instruction::Cycles; + #[derive(Debug, Clone)] pub struct PPU { pub lcd_control: LCDControl, pub monochrome: Monochrome, pub pos: ScreenPosition, pub vram: Box<[u8]>, + pub oam: Box<[u8]>, pub stat: LCDStatus, + cycles: Cycles, + mode: PPUMode, } impl PPU { - pub fn step(&mut self) {} + pub fn step(&mut self, cycles: Cycles) { + self.cycles += cycles; + + match self.mode { + PPUMode::OAMScan => { + if self.cycles >= 80.into() { + self.cycles = cycles % 80; + } + } + PPUMode::Draw => {} + PPUMode::HBlank => {} + PPUMode::VBlank => {} + } + } pub fn draw(&self, frame: &mut [u8]) { for (_i, pixel) in frame.chunks_exact_mut(4).enumerate() { @@ -26,10 +44,21 @@ impl Default for PPU { pos: Default::default(), stat: Default::default(), vram: vec![0; 8192].into_boxed_slice(), + oam: vec![0; 160].into_boxed_slice(), + cycles: 0.into(), + mode: PPUMode::OAMScan, } } } +#[derive(Debug, Clone, Copy)] +enum PPUMode { + OAMScan, + Draw, + HBlank, + VBlank, +} + #[derive(Debug, Clone, Copy, Default)] pub struct LCDStatus { lyc_eq_ly: bool, diff --git a/src/sound.rs b/src/sound.rs index fc83ca2..25bfd61 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -1,9 +1,17 @@ +use crate::instruction::Cycles; + #[derive(Debug, Clone, Copy, Default)] pub struct Sound { pub control: SoundControl, pub ch1: Channel1, } +impl Sound { + pub fn step(&mut self, _cycles: Cycles) { + // + } +} + #[derive(Debug, Clone, Copy, Default)] pub struct SoundControl { pub channel: ChannelControl, diff --git a/src/timer.rs b/src/timer.rs index a1f1fd9..2d00045 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,8 +1,16 @@ +use crate::instruction::Cycles; + #[derive(Debug, Clone, Copy)] pub struct Timer { pub control: TimerControl, } +impl Timer { + pub fn step(&mut self, _cycles: Cycles) { + // + } +} + impl Default for Timer { fn default() -> Self { Self {