[cpu] Add decode for procedures and conditional jumps
This commit is contained in:
@@ -102,6 +102,9 @@ impl Device {
|
|||||||
let y = self.registers.v[regy] as usize;
|
let y = self.registers.v[regy] as usize;
|
||||||
let toggle_state = self.draw_sprite_at_location(x, y, n);
|
let toggle_state = self.draw_sprite_at_location(x, y, n);
|
||||||
self.set_flag_register(toggle_state);
|
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) ;
|
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 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);
|
frame_buffer[index + (7 - bit_index)] = frame_buffer[index + (7 - bit_index)] ^ (bit_is_true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use crate::device::instruction::Instruction::{AddValueToRegister, ClearScreen, Draw, JumpTo, PassThrough, SetIndex, SetRegister};
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
@@ -7,12 +6,24 @@ pub enum Instruction {
|
|||||||
PassThrough,
|
PassThrough,
|
||||||
/// 00E0 - Clear the screen
|
/// 00E0 - Clear the screen
|
||||||
ClearScreen,
|
ClearScreen,
|
||||||
|
/// 00EE - Return from procedure
|
||||||
|
ReturnFromProcedure,
|
||||||
/// 1NNN - Jump to location
|
/// 1NNN - Jump to location
|
||||||
JumpTo(u16),
|
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
|
/// 6XNN - Set register to value
|
||||||
SetRegister(usize, u8),
|
SetRegister(usize, u8),
|
||||||
/// 7XNN - Add value to register
|
/// 7XNN - Add value to register
|
||||||
AddValueToRegister(usize, u8),
|
AddValueToRegister(usize, u8),
|
||||||
|
/// 9XY0 - If registers not equal, skip next
|
||||||
|
ConditionalInEqRegisterSkipNext(usize, usize),
|
||||||
/// ANNN - Set index value
|
/// ANNN - Set index value
|
||||||
SetIndex(u16),
|
SetIndex(u16),
|
||||||
///
|
///
|
||||||
@@ -26,29 +37,57 @@ impl Instruction {
|
|||||||
let outer_instruction_nibble = (instruction & 0xF000) >> 12;
|
let outer_instruction_nibble = (instruction & 0xF000) >> 12;
|
||||||
match outer_instruction_nibble {
|
match outer_instruction_nibble {
|
||||||
0x0 if instruction == 0xe0 => {
|
0x0 if instruction == 0xe0 => {
|
||||||
ClearScreen
|
Instruction::ClearScreen
|
||||||
|
}
|
||||||
|
0x0 if instruction == 0xee => {
|
||||||
|
Instruction::ReturnFromProcedure
|
||||||
}
|
}
|
||||||
0x0 => {
|
0x0 => {
|
||||||
log::warn!("Ignoring unsupported instruction {}",instruction);
|
log::warn!("Ignoring unsupported instruction {}",instruction);
|
||||||
PassThrough
|
Instruction::PassThrough
|
||||||
}
|
}
|
||||||
0x1 => {
|
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 => {
|
0x6 => {
|
||||||
SetRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
|
Instruction::SetRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
|
||||||
}
|
}
|
||||||
0x7 => {
|
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 => {
|
0xA => {
|
||||||
SetIndex(instruction & 0xfff)
|
Instruction::SetIndex(instruction & 0xfff)
|
||||||
}
|
}
|
||||||
0xD => {
|
0xD => {
|
||||||
let x = (instruction & 0xf00) >> 8;
|
let x = (instruction & 0xf00) >> 8;
|
||||||
let y = (instruction & 0xf0) >> 4;
|
let y = (instruction & 0xf0) >> 4;
|
||||||
let n = instruction & 0xf;
|
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 => {
|
0x8 => {
|
||||||
todo!("Arithmetic instructions pending")
|
todo!("Arithmetic instructions pending")
|
||||||
@@ -63,7 +102,7 @@ impl Instruction {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::device::instruction::Instruction;
|
use crate::device::instruction::Instruction;
|
||||||
use crate::device::instruction::Instruction::{AddValueToRegister, ClearScreen, Draw, JumpTo, SetIndex, SetRegister};
|
use crate::device::instruction::Instruction::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clear_screen() {
|
fn test_clear_screen() {
|
||||||
@@ -73,10 +112,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
fn test_procedure_return() {
|
||||||
fn test_other_0x0nnn_instructions_panic() {
|
let instruction_bytes = 0x00ee_u16.to_be_bytes();
|
||||||
let instruction_bytes = 0x00f0_u16.to_be_bytes();
|
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||||
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));
|
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]
|
#[test]
|
||||||
fn test_set_register_instruction() {
|
fn test_set_register_instruction() {
|
||||||
let instruction_bytes = 0x6a00_u16.to_be_bytes();
|
let instruction_bytes = 0x6a00_u16.to_be_bytes();
|
||||||
@@ -114,6 +190,12 @@ mod tests {
|
|||||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||||
assert_eq!(ins, AddValueToRegister(15, 0x23));
|
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]
|
#[test]
|
||||||
fn test_set_index() {
|
fn test_set_index() {
|
||||||
|
Reference in New Issue
Block a user