[cpu] Add decode for procedures and conditional jumps

This commit is contained in:
2024-03-04 18:03:56 +05:30
parent 1690c52bac
commit c83b90aead
2 changed files with 99 additions and 14 deletions

View File

@@ -102,6 +102,9 @@ impl Device {
let y = self.registers.v[regy] as usize;
let toggle_state = self.draw_sprite_at_location(x, y, n);
self.set_flag_register(toggle_state);
},
remaining=>{
log::error!("Unimplemented instruction {:?}",remaining);
}
};
}
@@ -124,7 +127,7 @@ impl Device {
let bit_is_true = (slice_from_memory & (1 << bit_index)) == (1<<bit_index) ;
// if the pixel is going to be toggled false, set this flag bit to true
if(frame_buffer[index + (7 - bit_index)] && (bit_is_true)) { is_pixel_toggled_off = true;}
if frame_buffer[index + (7 - bit_index)] && (bit_is_true) { is_pixel_toggled_off = true;}
frame_buffer[index + (7 - bit_index)] = frame_buffer[index + (7 - bit_index)] ^ (bit_is_true);
}
}

View File

@@ -1,5 +1,4 @@
use byteorder::{BigEndian, ByteOrder};
use crate::device::instruction::Instruction::{AddValueToRegister, ClearScreen, Draw, JumpTo, PassThrough, SetIndex, SetRegister};
#[derive(Eq, PartialEq, Debug)]
pub enum Instruction {
@@ -7,12 +6,24 @@ pub enum Instruction {
PassThrough,
/// 00E0 - Clear the screen
ClearScreen,
/// 00EE - Return from procedure
ReturnFromProcedure,
/// 1NNN - Jump to location
JumpTo(u16),
/// 2NNN - Link and jump
JumpAndLink(u16),
/// 3XNN - If register equals number, Skip next
ConditionalEqSkipNext(usize, u8),
/// 4XNN - If register equals number, Skip next
ConditionalInEqSkipNext(usize, u8),
/// 5XY0 - If registers equal, Skip next
ConditionalEqRegisterSkipNext(usize, usize),
/// 6XNN - Set register to value
SetRegister(usize, u8),
/// 7XNN - Add value to register
AddValueToRegister(usize, u8),
/// 9XY0 - If registers not equal, skip next
ConditionalInEqRegisterSkipNext(usize, usize),
/// ANNN - Set index value
SetIndex(u16),
///
@@ -26,29 +37,57 @@ impl Instruction {
let outer_instruction_nibble = (instruction & 0xF000) >> 12;
match outer_instruction_nibble {
0x0 if instruction == 0xe0 => {
ClearScreen
Instruction::ClearScreen
}
0x0 if instruction == 0xee => {
Instruction::ReturnFromProcedure
}
0x0 => {
log::warn!("Ignoring unsupported instruction {}",instruction);
PassThrough
Instruction::PassThrough
}
0x1 => {
JumpTo(instruction & 0xfff)
Instruction::JumpTo(instruction & 0xfff)
}
0x2 => {
Instruction::JumpAndLink(instruction & 0xfff)
}
0x3 => {
let register = (instruction & 0xf00) >> 8;
let val = instruction & 0xff;
Instruction::ConditionalEqSkipNext(register as usize, val as u8)
}
0x4 => {
let register = (instruction & 0xf00) >> 8;
let val = instruction & 0xff;
Instruction::ConditionalInEqSkipNext(register as usize, val as u8)
}
0x5 => {
let registerx = (instruction & 0xf00) >> 8;
let registery = (instruction & 0xf0) >> 4;
Instruction::ConditionalEqRegisterSkipNext(registerx as usize, registery as usize)
}
0x6 => {
SetRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
Instruction::SetRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
}
0x7 => {
AddValueToRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
Instruction::AddValueToRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
}
0x9 =>{
let registerx = (instruction & 0xf00) >> 8;
let registery = (instruction & 0xf0) >> 4;
Instruction::ConditionalInEqRegisterSkipNext(registerx as usize, registery as usize)
}
0xA => {
SetIndex(instruction & 0xfff)
Instruction::SetIndex(instruction & 0xfff)
}
0xD => {
let x = (instruction & 0xf00) >> 8;
let y = (instruction & 0xf0) >> 4;
let n = instruction & 0xf;
Draw(x as usize, y as usize, n as u8)
Instruction::Draw(x as usize, y as usize, n as u8)
}
0x8 => {
todo!("Arithmetic instructions pending")
@@ -63,7 +102,7 @@ impl Instruction {
#[cfg(test)]
mod tests {
use crate::device::instruction::Instruction;
use crate::device::instruction::Instruction::{AddValueToRegister, ClearScreen, Draw, JumpTo, SetIndex, SetRegister};
use crate::device::instruction::Instruction::*;
#[test]
fn test_clear_screen() {
@@ -73,10 +112,19 @@ mod tests {
}
#[test]
#[should_panic]
fn test_other_0x0nnn_instructions_panic() {
let instruction_bytes = 0x00f0_u16.to_be_bytes();
Instruction::decode_instruction(&instruction_bytes);
fn test_procedure_return() {
let instruction_bytes = 0x00ee_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, ReturnFromProcedure);
}
#[test]
fn test_other_0x0nnn_instructions_passthrough() {
for instruction_hex in [0xf0u16, 0x0, 0x1, 0x10] {
let instruction_bytes = instruction_hex.to_be_bytes();
let instruction = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(instruction, PassThrough)
}
}
@@ -94,6 +142,34 @@ mod tests {
assert_eq!(ins, JumpTo(0xfaf));
}
#[test]
fn test_link_jump() {
let instruction_bytes = 0x2afa_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, JumpAndLink(0xafa));
}
#[test]
fn test_conditional_equal_skip() {
let instruction_bytes = 0x3fad_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, ConditionalEqSkipNext(0xf, 0xad));
}
#[test]
fn test_conditional_in_equal_skip() {
let instruction_bytes = 0x4fea_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, ConditionalInEqSkipNext(0xf, 0xea));
}
#[test]
fn test_conditional_register_equal_skip() {
let instruction_bytes = 0x5fa0_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, ConditionalEqRegisterSkipNext(0xf, 0xa));
}
#[test]
fn test_set_register_instruction() {
let instruction_bytes = 0x6a00_u16.to_be_bytes();
@@ -114,6 +190,12 @@ mod tests {
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, AddValueToRegister(15, 0x23));
}
#[test]
fn test_conditional_register_in_equal_skip() {
let instruction_bytes = 0x9af0_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, ConditionalInEqRegisterSkipNext(0xa, 0xf));
}
#[test]
fn test_set_index() {