From 90a83e131a4b6b2cec7b1780ca98bc91ebf8c32e Mon Sep 17 00:00:00 2001 From: Atreya Bain Date: Tue, 5 Mar 2024 19:24:45 +0530 Subject: [PATCH] [cpu] Add all remaining instruction decodes --- src/device/device.rs | 47 +++++++++++++--- src/device/instruction.rs | 112 +++++++++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 9 deletions(-) diff --git a/src/device/device.rs b/src/device/device.rs index 5ea0af8..ceb96be 100644 --- a/src/device/device.rs +++ b/src/device/device.rs @@ -36,7 +36,7 @@ impl Device { stack: Vec::with_capacity(16), timer, super_chip8_mode: false, - device_keyboard + device_keyboard, } } } @@ -63,9 +63,9 @@ impl Device { const FONT_DEFAULT_MEM_LOCATION_START: usize = 0x50; const FONT_DEFAULT_MEM_LOCATION_END: usize = 0x9F; const ROM_START: usize = 0x200; - pub fn cycle(&mut self) ->EmulatorResult<()>{ + pub fn cycle(&mut self) -> EmulatorResult<()> { self.device_keyboard.update_keyboard()?; - + let pc = self.registers.pc as usize; let instr_slice = self.memory.get(pc..pc + 2).expect("Failed to get memory"); self.registers.pc += 2; @@ -140,12 +140,26 @@ impl Device { self.registers.pc += 2; } } - Instruction::JumpWithOffset(_, _) => {} + Instruction::JumpWithOffset(x, num) => { + let regnum = if self.super_chip8_mode { x } else { 0 }; + let new_pc = self.registers.v[regnum] as u16 + num ; + self.registers.pc = new_pc; + } Instruction::RandomAnd(dest, n) => { self.registers.v[dest] = random::() & n; } - Instruction::SkipIfKeyPressed(_) => {} - Instruction::SkipIfKeyNotPressed(_) => {} + Instruction::SkipIfKeyPressed(x) => { + let key_press_expected_for = self.registers.v[x]; + if self.device_keyboard.query_key_down(key_press_expected_for) { + self.registers.pc += 2; + } + } + Instruction::SkipIfKeyNotPressed(x) => { + let key_press_expected_for = self.registers.v[x]; + if !self.device_keyboard.query_key_down(key_press_expected_for) { + self.registers.pc += 2; + } + } Instruction::Set(x, y) => { self.registers.v[x] = self.registers.v[y]; } @@ -170,14 +184,31 @@ impl Device { self.registers.v[x] = wrapped_subtraction_result; self.set_flag_register(is_overflow); } - Instruction::RShift(_, _) => {} Instruction::RSub(x, y) => { let left = self.registers.v[y]; let (wrapped_subtraction_result, is_overflow) = left.overflowing_sub(self.registers.v[x]); self.registers.v[x] = wrapped_subtraction_result; self.set_flag_register(is_overflow); } - Instruction::LShift(_, _) => {} + Instruction::RShift(x, y) => { + if(self.super_chip8_mode){ + self.registers.v[x] = self.registers.v[y]; + } + let (shift_res,did_overflow) = self.registers.v[x].overflowing_shr(1); + self.registers.v[x] = shift_res; + self.set_flag_register(did_overflow); + } + Instruction::LShift(x, y) => { + if(self.super_chip8_mode){ + self.registers.v[x] = self.registers.v[y]; + } + let (shift_res,did_overflow) = self.registers.v[x].overflowing_shl(1); + self.registers.v[x] = shift_res; + self.set_flag_register(did_overflow); + }, + _=>{ + todo!() + } }; } /// diff --git a/src/device/instruction.rs b/src/device/instruction.rs index 2a20249..a08582a 100644 --- a/src/device/instruction.rs +++ b/src/device/instruction.rs @@ -37,6 +37,24 @@ pub enum Instruction { SkipIfKeyPressed(usize), /// EXA1 - Check if key is not pressed SkipIfKeyNotPressed(usize), + /// FX07 - Get delay timer, put into register + FetchDelayTimer(usize), + /// FX15 - set delay timer as register + SetDelayTimer(usize), + /// FX18 - Set sound timer as register + SetSoundTimer(usize), + /// FX1E - Add register to index + AddToIndex(usize), + /// FX0A - Wait for key as indicated by register + GetKey(usize), + /// FX29 - Set index to register-requested font char address in memory + SetIndexToFontCharacter(usize), + /// FX33 - Convert register val to bcd and store at location pointed by index + DoBCDConversion(usize), + /// FX55 - Store all registers from v0 to vx to memory location pointed to by index + StoreRegistersToMemory(usize), + /// FX65 - Load all registers from v0 to vx to memory location pointed to by index + LoadRegistersFromMemory(usize), // ALU operations going ahead /// 8XY0 - x=y @@ -138,7 +156,44 @@ impl Instruction { 0xE if (instruction & 0xff) == 0xa1 => { let x = (instruction & 0xf00) >> 8; Instruction::SkipIfKeyNotPressed(x as usize) - } + } + 0xF if (instruction & 0xff) == 0x07 =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::FetchDelayTimer(x as usize) + } + 0xF if (instruction & 0xff) == 0x15 =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::SetDelayTimer(x as usize) + } + 0xF if (instruction & 0xff) == 0x18 =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::SetSoundTimer(x as usize) + } + 0xF if (instruction & 0xff) == 0x1E =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::AddToIndex(x as usize) + } + 0xF if (instruction & 0xff) == 0x0A =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::GetKey(x as usize) + } + //TODO add tests from here + 0xF if (instruction & 0xff) == 0x29 =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::SetIndexToFontCharacter(x as usize) + } + 0xF if (instruction & 0xff) == 0x33 =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::DoBCDConversion(x as usize) + } + 0xF if (instruction & 0xff) == 0x55 =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::StoreRegistersToMemory(x as usize) + } + 0xF if (instruction & 0xff) == 0x65 =>{ + let x = (instruction & 0xf00) >> 8; + Instruction::LoadRegistersFromMemory(x as usize) + } _ => { todo!("Unimplemented instruction") } @@ -388,5 +443,60 @@ mod tests { let ins = Instruction::decode_instruction(&instruction_bytes); assert_eq!(ins, SkipIfKeyNotPressed(0xb)) } + + #[test] + fn test_fetch_delay_timer(){ + let instruction_bytes = 0xfa07_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, FetchDelayTimer(0xa)) + } + #[test] + fn test_set_delay_timer(){ + let instruction_bytes = 0xfb15_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, SetDelayTimer(0xb)) + } + #[test] + fn test_set_sound_timer(){ + let instruction_bytes = 0xfc18_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, SetSoundTimer(0xc)) + } + #[test] + fn test_add_to_index(){ + let instruction_bytes = 0xfb1e_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, AddToIndex(0xb)) + } + #[test] + fn test_get_key(){ + let instruction_bytes = 0xf50a_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, GetKey(0x5)) + } + #[test] + fn test_set_index_to_font_char(){ + let instruction_bytes = 0xfb29_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, SetIndexToFontCharacter(0xb)) + } + #[test] + fn test_do_bcd_conversion(){ + let instruction_bytes = 0xfd33_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, DoBCDConversion(0xd)) + } + #[test] + fn test_store_regs_to_mem(){ + let instruction_bytes = 0xfb55_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, StoreRegistersToMemory(0xb)) + } + #[test] + fn test_load_regs_to_mem(){ + let instruction_bytes = 0xf965_u16.to_be_bytes(); + let ins = Instruction::decode_instruction(&instruction_bytes); + assert_eq!(ins, LoadRegistersFromMemory(0b1001)) + } } \ No newline at end of file