[cpu] Add Decode for keypress instructions
This commit is contained in:
@@ -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(_, _) => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
|
@@ -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))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user