[cpu] Add Decode for keypress instructions

This commit is contained in:
2024-03-04 19:46:15 +05:30
parent 69dc84d1c5
commit 9329d4e51a
2 changed files with 127 additions and 71 deletions

View File

@@ -103,9 +103,32 @@ impl Device {
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=>{ Instruction::JumpAndLink(jump_location) => {
log::error!("Unimplemented instruction {:?}",remaining); self.stack.push(self.registers.pc);
self.registers.pc = jump_location;
} }
Instruction::ReturnFromProcedure =>{
let old_pc = self.stack.pop().expect("Expected value on stack pop");
self.registers.pc = old_pc;
}
Instruction::ConditionalEqSkipNext(_, _) => {}
Instruction::ConditionalInEqSkipNext(_, _) => {}
Instruction::ConditionalEqRegisterSkipNext(_, _) => {}
Instruction::ConditionalInEqRegisterSkipNext(_, _) => {}
Instruction::JumpWithOffset(_, _) => {}
Instruction::RandomOr(_, _) => {}
Instruction::SkipIfKeyPressed(_) => {}
Instruction::SkipIfKeyNotPressed(_) => {}
Instruction::Set(_, _) => {}
Instruction::Or(_, _) => {}
Instruction::And(_, _) => {}
Instruction::Xor(_, _) => {}
Instruction::Add(_, _) => {}
Instruction::Sub(_, _) => {}
Instruction::RShift(_, _) => {}
Instruction::RSub(_, _) => {}
Instruction::LShift(_, _) => {}
}; };
} }
/// ///

View File

@@ -27,32 +27,36 @@ pub enum Instruction {
/// ANNN - Set index value /// ANNN - Set index value
SetIndex(u16), SetIndex(u16),
/// B(X+N)NN - Jump to address with offset. Either v0 or specified register /// B(X+N)NN - Jump to address with offset. Either v0 or specified register
JumpWithOffset(usize,u16), JumpWithOffset(usize, u16),
/// CXNN - AND a random number with NN and place in register /// CXNN - AND a random number with NN and place in register
RandomOr(usize,u16), RandomOr(usize, u16),
/// DXYN - Draw pixels at xy pointed by register for n bytes long /// DXYN - Draw pixels at xy pointed by register for n bytes long
Draw(usize, usize, u8), Draw(usize, usize, u8),
/// EX9E - Check if key is pressed
SkipIfKeyPressed(usize),
/// EXA1 - Check if key is not pressed
SkipIfKeyNotPressed(usize),
// ALU operations going ahead // ALU operations going ahead
/// 8XY0 - x=y /// 8XY0 - x=y
Set(usize,usize), Set(usize, usize),
/// 8XY1 - x|=y /// 8XY1 - x|=y
Or(usize,usize), Or(usize, usize),
/// 8XY2 - x|=y /// 8XY2 - x|=y
And(usize,usize), And(usize, usize),
/// 8XY3 - x^=y /// 8XY3 - x^=y
Xor(usize,usize), Xor(usize, usize),
/// 8XY4 - x+=y /// 8XY4 - x+=y
Add(usize,usize), Add(usize, usize),
/// 8XY5 - x-=y /// 8XY5 - x-=y
Sub(usize,usize), Sub(usize, usize),
/// 8XY6 - (x=y)?, x>>=1 /// 8XY6 - (x=y)?, x>>=1
RShift(usize,usize), RShift(usize, usize),
/// 8XY7 - x=y-x /// 8XY7 - x=y-x
RSub(usize,usize), RSub(usize, usize),
/// 8XYE - (x=y)?, x<<=1 /// 8XYE - (x=y)?, x<<=1
LShift(usize,usize), LShift(usize, usize),
} }
impl Instruction { impl Instruction {
@@ -98,11 +102,11 @@ impl Instruction {
} }
0x7 => { 0x7 => {
Instruction::AddValueToRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8) Instruction::AddValueToRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
}, }
0x8=>{ 0x8 => {
Self::decode_arithmetic_instruction(instruction) Self::decode_arithmetic_instruction(instruction)
} }
0x9 =>{ 0x9 => {
let register_x = (instruction & 0xf00) >> 8; let register_x = (instruction & 0xf00) >> 8;
let register_y = (instruction & 0xf0) >> 4; let register_y = (instruction & 0xf0) >> 4;
@@ -111,15 +115,15 @@ impl Instruction {
0xA => { 0xA => {
Instruction::SetIndex(instruction & 0xfff) Instruction::SetIndex(instruction & 0xfff)
} }
0xB =>{ 0xB => {
let register_x = (instruction & 0xf00) >> 8; let register_x = (instruction & 0xf00) >> 8;
let jump_address_base = instruction & 0xfff; let jump_address_base = instruction & 0xfff;
Instruction::JumpWithOffset(register_x as usize, jump_address_base) Instruction::JumpWithOffset(register_x as usize, jump_address_base)
} }
0xC =>{ 0xC => {
let register_x = (instruction & 0xf00) >> 8; let register_x = (instruction & 0xf00) >> 8;
let mask = instruction & 0xff; let mask = instruction & 0xff;
Instruction::RandomOr(register_x as usize,mask) Instruction::RandomOr(register_x as usize, mask)
} }
0xD => { 0xD => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
@@ -127,46 +131,54 @@ impl Instruction {
let n = instruction & 0xf; let n = instruction & 0xf;
Instruction::Draw(x as usize, y as usize, n as u8) Instruction::Draw(x as usize, y as usize, n as u8)
} }
0xE if (instruction & 0xff) == 0x9e => {
let x = (instruction & 0xf00) >> 8;
Instruction::SkipIfKeyPressed(x as usize)
},
0xE if (instruction & 0xff) == 0xa1 => {
let x = (instruction & 0xf00) >> 8;
Instruction::SkipIfKeyNotPressed(x as usize)
}
_ => { _ => {
todo!("Unimplemented instruction") todo!("Unimplemented instruction")
} }
} }
} }
fn decode_arithmetic_instruction(instruction: u16) ->Instruction{ fn decode_arithmetic_instruction(instruction: u16) -> Instruction {
assert_eq!(instruction&0xF000,0x8000); assert_eq!(instruction & 0xF000, 0x8000);
let reg_x = ((instruction & 0xf00 )>>8) as usize; let reg_x = ((instruction & 0xf00) >> 8) as usize;
let reg_y = ((instruction & 0xf0) >> 4) as usize; let reg_y = ((instruction & 0xf0) >> 4) as usize;
let operation = instruction & 0xf; let operation = instruction & 0xf;
match operation { match operation {
0=>{ 0 => {
Instruction::Set(reg_x,reg_y) Instruction::Set(reg_x, reg_y)
},
1=>{
Instruction::Or(reg_x,reg_y)
},
2=>{
Instruction::And(reg_x,reg_y)
},
3=>{
Instruction::Xor(reg_x,reg_y)
},
4=>{
Instruction::Add(reg_x,reg_y)
},
5=>{
Instruction::Sub(reg_x,reg_y)
},
6=>{
Instruction::RShift(reg_x,reg_y)
} }
7=>{ 1 => {
Instruction::RSub(reg_x,reg_y) Instruction::Or(reg_x, reg_y)
},
0xe=>{
Instruction::LShift(reg_x,reg_y)
} }
_=>{ 2 => {
Instruction::And(reg_x, reg_y)
}
3 => {
Instruction::Xor(reg_x, reg_y)
}
4 => {
Instruction::Add(reg_x, reg_y)
}
5 => {
Instruction::Sub(reg_x, reg_y)
}
6 => {
Instruction::RShift(reg_x, reg_y)
}
7 => {
Instruction::RSub(reg_x, reg_y)
}
0xe => {
Instruction::LShift(reg_x, reg_y)
}
_ => {
log::error!("Encountered unexpected alu instruction {}",instruction); log::error!("Encountered unexpected alu instruction {}",instruction);
Instruction::PassThrough Instruction::PassThrough
} }
@@ -265,6 +277,7 @@ 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] #[test]
fn test_conditional_register_in_equal_skip() { fn test_conditional_register_in_equal_skip() {
let instruction_bytes = 0x9af0_u16.to_be_bytes(); let instruction_bytes = 0x9af0_u16.to_be_bytes();
@@ -278,22 +291,21 @@ mod tests {
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SetIndex(0xfaf)); assert_eq!(ins, SetIndex(0xfaf));
} }
#[test] #[test]
fn test_jump_with_offset() { fn test_jump_with_offset() {
let instruction_bytes = 0xbfae_u16.to_be_bytes(); let instruction_bytes = 0xbfae_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, JumpWithOffset(0xf,0xfae)); assert_eq!(ins, JumpWithOffset(0xf, 0xfae));
} }
#[test] #[test]
fn test_random_and() { fn test_random_and() {
let instruction_bytes = 0xcabd_u16.to_be_bytes(); let instruction_bytes = 0xcabd_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, RandomOr(0xa,0xbd)); assert_eq!(ins, RandomOr(0xa, 0xbd));
} }
#[test] #[test]
fn test_draw() { fn test_draw() {
@@ -303,57 +315,78 @@ mod tests {
} }
#[test] #[test]
fn test_alu_set(){ fn test_alu_set() {
let instruction_bytes = 0x8a50_u16.to_be_bytes(); let instruction_bytes = 0x8a50_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, Set(0xa,0x5)) assert_eq!(ins, Set(0xa, 0x5))
} }
#[test] #[test]
fn test_alu_or(){ fn test_alu_or() {
let instruction_bytes = 0x85a1_u16.to_be_bytes(); let instruction_bytes = 0x85a1_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, Or(0x5,0xa)) assert_eq!(ins, Or(0x5, 0xa))
} }
#[test] #[test]
fn test_alu_and(){ fn test_alu_and() {
let instruction_bytes = 0x8ba2_u16.to_be_bytes(); let instruction_bytes = 0x8ba2_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, And(0xb,0xa)) assert_eq!(ins, And(0xb, 0xa))
} }
#[test] #[test]
fn test_alu_xor(){ fn test_alu_xor() {
let instruction_bytes = 0x8ab3_u16.to_be_bytes(); let instruction_bytes = 0x8ab3_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, Xor(0xa,0xb)) assert_eq!(ins, Xor(0xa, 0xb))
} }
#[test] #[test]
fn test_alu_add(){ fn test_alu_add() {
let instruction_bytes = 0x8ed4_u16.to_be_bytes(); let instruction_bytes = 0x8ed4_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, Add(0xe,0xd)) assert_eq!(ins, Add(0xe, 0xd))
} }
#[test] #[test]
fn test_alu_sub(){ fn test_alu_sub() {
let instruction_bytes = 0x8ed5_u16.to_be_bytes(); let instruction_bytes = 0x8ed5_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, Sub(0xe,0xd)) assert_eq!(ins, Sub(0xe, 0xd))
} }
#[test] #[test]
fn test_alu_r_sub(){ fn test_alu_r_sub() {
let instruction_bytes = 0x8517_u16.to_be_bytes(); let instruction_bytes = 0x8517_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, RSub(0x5,0x1)) assert_eq!(ins, RSub(0x5, 0x1))
} }
#[test] #[test]
fn test_alu_right_shift(){ fn test_alu_right_shift() {
let instruction_bytes = 0x89a6_u16.to_be_bytes(); let instruction_bytes = 0x89a6_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, RShift(0x9,0xa)) assert_eq!(ins, RShift(0x9, 0xa))
} }
#[test] #[test]
fn test_alu_left_shift(){ fn test_alu_left_shift() {
let instruction_bytes = 0x812e_u16.to_be_bytes(); let instruction_bytes = 0x812e_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, LShift(0x1,0x2)) assert_eq!(ins, LShift(0x1, 0x2))
} }
#[test]
fn test_skip_if_keypress(){
let instruction_bytes = 0xef9e_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SkipIfKeyPressed(0xf))
}
#[test]
fn test_skip_if_not_keypress(){
let instruction_bytes = 0xeba1_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SkipIfKeyNotPressed(0xb))
}
} }