[cpu] Implement remaining instructions

This commit is contained in:
2024-03-05 19:54:39 +05:30
parent 90a83e131a
commit 6c0d48b749
2 changed files with 82 additions and 16 deletions

View File

@@ -71,14 +71,13 @@ impl Device {
self.registers.pc += 2; self.registers.pc += 2;
let instruction = Instruction::decode_instruction(instr_slice); let instruction = Instruction::decode_instruction(instr_slice);
self.execute_instruction(instruction); self.execute_instruction(instruction)
Ok(())
} }
/// convert the 2 indices into one /// convert the 2 indices into one
fn get_framebuffer_index(x: usize, y: usize) -> usize { fn get_framebuffer_index(x: usize, y: usize) -> usize {
y * Self::FRAME_BUFFER_WIDTH + x y * Self::FRAME_BUFFER_WIDTH + x
} }
pub fn execute_instruction(&mut self, instruction: Instruction) { pub fn execute_instruction(&mut self, instruction: Instruction) -> EmulatorResult<()> {
// thread::sleep(Duration::from_millis(250)); // thread::sleep(Duration::from_millis(250));
log::trace!("Executing {:?}, {:?}",&instruction,&self.registers); log::trace!("Executing {:?}, {:?}",&instruction,&self.registers);
match instruction { match instruction {
@@ -205,11 +204,78 @@ impl Device {
let (shift_res, did_overflow) = self.registers.v[x].overflowing_shl(1); let (shift_res, did_overflow) = self.registers.v[x].overflowing_shl(1);
self.registers.v[x] = shift_res; self.registers.v[x] = shift_res;
self.set_flag_register(did_overflow); self.set_flag_register(did_overflow);
}, }
_=>{
todo!() Instruction::FetchDelayTimer(x) => {
let timer_left = self.timer.poll_value()?;
self.registers.v[x] = timer_left
}
Instruction::SetDelayTimer(x) => {
let delay_timer_val = self.registers.v[x];
self.timer.try_set_timer(delay_timer_val)?;
}
Instruction::SetSoundTimer(_) => {
log::warn!("Sound unimplemented, instruction {:?}",instruction);
}
Instruction::AddToIndex(x) => {
let reg_value = self.registers.v[x];
let index_original = self.registers.i;
// newer instruction set requires wrapping on 12 bit overflow, and setting vf
let addn_res = if (self.super_chip8_mode) {
let overflowing = (reg_value as u16 + index_original) >= 0x1000;
self.set_flag_register(overflowing);
(reg_value as u16 + index_original) % 0x1000
} else {
reg_value as u16 + index_original
};
self.registers.i = addn_res;
}
Instruction::GetKey(x) => {
let key_expected = self.registers.v[x];
if !self.device_keyboard.query_key_down(key_expected) {
self.registers.pc -= 2;
}
}
Instruction::SetIndexToFontCharacter(x) => {
let requested_char = self.registers.v[x];
// TODO extract 5 to constant
let font_address = Self::FONT_DEFAULT_MEM_LOCATION_START as u16 + 5 * requested_char as u16;
self.registers.i = font_address;
}
Instruction::DoBCDConversion(x) => {
let mut binary_value_to_decode_temp = self.registers.v[x];
let unit_digit = binary_value_to_decode_temp % 10;
binary_value_to_decode_temp /= 10;
let tens_digit = binary_value_to_decode_temp % 10;
binary_value_to_decode_temp /= 10;
let hundreds_digit = binary_value_to_decode_temp % 10;
binary_value_to_decode_temp /= 10;
// If this fails, something has gone truly wrong
assert_eq!(0, binary_value_to_decode_temp);
let val = [unit_digit, tens_digit, hundreds_digit];
let index = self.registers.i as usize;
self.memory[index..(index + 3)].copy_from_slice(&val);
}
Instruction::StoreRegistersToMemory(last_reg_to_store) => {
let reg_slice = &self.registers.v[0..=last_reg_to_store];
let index = self.registers.i as usize;
self.memory[index..=(index+last_reg_to_store)].copy_from_slice(reg_slice);
// Old Chip8 used to use i as a incrementing index
if !self.super_chip8_mode {
self.registers.i += last_reg_to_store as u16+ 1;
}
}
Instruction::LoadRegistersFromMemory(last_reg_to_load) => {
let index = self.registers.i as usize;
let mem_slice = &self.memory[index..=(index+last_reg_to_load)];
self.registers.v[0..=last_reg_to_load].copy_from_slice(mem_slice);
// Old Chip8 used to use i as a incrementing index
if !self.super_chip8_mode {
self.registers.i += last_reg_to_load as u16 + 1;
}
} }
}; };
Ok(())
} }
/// ///
/// Draw a sprite at location at (x,y) for n pixels long and 8 pixels wide. /// Draw a sprite at location at (x,y) for n pixels long and 8 pixels wide.

View File

@@ -5,12 +5,12 @@ use std::time::Duration;
use crate::util::EmulatorResult; use crate::util::EmulatorResult;
pub struct Timer { pub struct Timer {
timer_left: Arc<Mutex<u16>>, timer_left: Arc<Mutex<u8>>,
join_handle: Option<(JoinHandle<()>, std::sync::mpsc::Sender<()>)>, join_handle: Option<(JoinHandle<()>, std::sync::mpsc::Sender<()>)>,
} }
impl Timer { impl Timer {
pub const TIMER_THREAD_NAME: &str = "Timer"; pub const TIMER_THREAD_NAME: &'static str = "Timer";
pub fn new() -> Timer { pub fn new() -> Timer {
Timer { timer_left: Arc::new(Mutex::default()), join_handle: None } Timer { timer_left: Arc::new(Mutex::default()), join_handle: None }
} }
@@ -37,19 +37,19 @@ impl Timer {
self.join_handle = Some((res, sender)); self.join_handle = Some((res, sender));
} }
/// Set a timer down tick from `val` /// Set a timer down tick from `val`
pub fn try_set_timer(&self, val: u16) -> EmulatorResult<()> { pub fn try_set_timer(&self, val: u8) -> EmulatorResult<()> {
let mut timer_val = self.timer_left.lock()?; let mut timer_val = self.timer_left.lock()?;
*timer_val = val; *timer_val = val;
Ok(()) Ok(())
} }
pub fn poll_value(&self) -> EmulatorResult<u16> { pub fn poll_value(&self) -> EmulatorResult<u8> {
let res = self.timer_left.lock()?; let res = self.timer_left.lock()?;
Ok(res.clone()) Ok(res.clone())
} }
pub fn stop(self) { pub fn stop(self) {
if let Some((u, x)) = self.join_handle { if let Some((u, _)) = self.join_handle {
u.join().expect("Failed to close thread"); u.join().expect("Failed to close thread");
} else { } else {
log::warn!("Nothing present!"); log::warn!("Nothing present!");