Skip to content

Commit

Permalink
feat: add schip support
Browse files Browse the repository at this point in the history
  • Loading branch information
nikoof committed Nov 24, 2023
1 parent acb3b17 commit 77c6ef3
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 41 deletions.
56 changes: 46 additions & 10 deletions src/interpreter/chip8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ where

'cpu: loop {
let next_instruction = self.next_instruction()?;
self.execute_instruction(next_instruction);
self.execute_instruction(next_instruction)?;
self.window
.update_buffer(&self.display, DISPLAY_WIDTH, DISPLAY_HEIGHT);

Expand Down Expand Up @@ -136,116 +136,141 @@ where
Instruction::new(opcode).ok_or(anyhow!("Cannot decode opcode {:#06x}", opcode))
}

fn execute_instruction(&mut self, instruction: Instruction) {
fn execute_instruction(&mut self, instruction: Instruction) -> Result<()> {
use Instruction::*;
match instruction {
ClearScreen => self.display.fill(0),
Jump { address } => self.pc = address,
ClearScreen => Ok(self.display.fill(0)),
Jump { address } => Ok(self.pc = address),
JumpOffset {
address,
offset_register: _,
} => {
self.pc = address;
self.pc = address + self.variables[0] as usize;
Ok(())
}
SetLiteral { dest, value } => self.variables[dest] = value,
SetLiteral { dest, value } => Ok(self.variables[dest] = value),
AddLiteral { dest, value } => {
self.variables[dest] = self.variables[dest].wrapping_add(value)
self.variables[dest] = self.variables[dest].wrapping_add(value);
Ok(())
}
SetIndex { src } => self.index = src,
SetIndexFont { src } => {
SetIndex { src } => Ok(self.index = src),
SetIndexFont { src, big: _ } => {
let character = (self.variables[src] & 0x0F) as usize;
self.index = FONT_ADDRESS + 5 * character;
Ok(())
}
AddIndex { src } => {
let (res, overflow) = self.index.overflowing_add(self.variables[src] as usize);
self.index = res;
self.variables[0xF] = overflow as u8;
Ok(())
}
Call { address } => {
self.stack.push(self.pc);
self.pc = address;
Ok(())
}
Return => {
self.pc = self.stack.pop().expect("Don't pop out of main");
Ok(())
}
SkipEq { x, y } => {
if self.variables[x] == self.variables[y] {
self.pc += 2;
}
Ok(())
}
SkipNotEq { x, y } => {
if self.variables[x] != self.variables[y] {
self.pc += 2;
}
Ok(())
}
SkipEqLiteral { x, value } => {
if self.variables[x] == value {
self.pc += 2;
}
Ok(())
}
SkipNotEqLiteral { x, value } => {
if self.variables[x] != value {
self.pc += 2;
}
Ok(())
}
SkipIfKey { key_register } => {
if self.window.is_key_down(self.variables[key_register]) {
self.pc += 2;
}
Ok(())
}
SkipIfNotKey { key_register } => {
if !self.window.is_key_down(self.variables[key_register]) {
self.pc += 2;
}
Ok(())
}
GetKey { dest } => {
if let Some(key) = self.window.get_key() {
self.variables[dest] = key as u8;
} else {
self.pc -= 2;
}
Ok(())
}
Set { dest, src } => {
self.variables[dest] = self.variables[src];
Ok(())
}
Or { lhs, rhs } => {
self.variables[lhs] |= self.variables[rhs];
Ok(())
}
And { lhs, rhs } => {
self.variables[lhs] &= self.variables[rhs];
Ok(())
}
Xor { lhs, rhs } => {
self.variables[lhs] ^= self.variables[rhs];
Ok(())
}
Add { lhs, rhs } => {
let (res, overflow) = self.variables[lhs].overflowing_add(self.variables[rhs]);
self.variables[lhs] = res;
self.variables[0xF] = overflow as u8;
Ok(())
}
Sub { lhs, rhs, dest } => {
let (res, overflow) = self.variables[lhs].overflowing_sub(self.variables[rhs]);
self.variables[dest] = res;
self.variables[0xF] = !overflow as u8;
Ok(())
}
// TODO: Make ambiguity configurable
LeftShift { lhs, rhs } => {
self.variables[lhs] = self.variables[rhs];
let flag = self.variables[lhs] >> 7;
self.variables[lhs] <<= 1;
self.variables[0xF] = flag;
Ok(())
}
RightShift { lhs, rhs } => {
self.variables[lhs] = self.variables[rhs];
let flag = self.variables[lhs] & 1;
self.variables[lhs] >>= 1;
self.variables[0xF] = flag;
Ok(())
}
GetDelay { dest } => {
self.variables[dest] = self.delay_timer;
Ok(())
}
SetDelay { src } => {
self.delay_timer = self.variables[src];
Ok(())
}
SetSound { src } => {
self.sound_timer = self.variables[src];
Ok(())
}
Draw {
x,
Expand All @@ -271,9 +296,11 @@ where
self.display[buffer_index] ^= pixel;
}
}
Ok(())
}
Random { x, mask } => {
self.variables[x] = rand::random::<u8>() & mask;
Ok(())
}
DecimalConversion { src } => {
let mut n = self.variables[src];
Expand All @@ -282,17 +309,26 @@ where
self.memory[self.index + i] = n % 10;
n /= 10;
}
Ok(())
}
StoreMemory { registers } => {
for i in 0..=registers {
self.memory[self.index + i] = self.variables[i];
// self.index = i;
}
Ok(())
}
LoadMemory { registers } => {
for i in 0..=registers {
self.variables[i] = self.memory[self.index + i];
// self.index = i;
}
Ok(())
}
_ => Err(anyhow!(
"Instruction {:?} not in Chip8 instruction set.",
instruction
)),
}
}
}
42 changes: 37 additions & 5 deletions src/interpreter/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum Instruction {
// Chip8 instructions
ClearScreen,
Draw {
x: usize,
Expand Down Expand Up @@ -126,6 +127,7 @@ pub enum Instruction {

SetIndexFont {
src: usize,
big: bool,
},

DecimalConversion {
Expand All @@ -144,6 +146,25 @@ pub enum Instruction {
x: usize,
mask: u8,
},

// Schip extension
Hires,
Lores,

ScrollRight,
ScrollLeft,
ScrollDown {
amount: usize,
},

SaveFlags {
x: usize,
},
LoadFlags {
x: usize,
},

Exit,
}

impl Instruction {
Expand All @@ -155,7 +176,17 @@ impl Instruction {
0x0000 => match opcode {
0x00E0 => Some(ClearScreen),
0x00EE => Some(Return),
_ => None,
0x00FF => Some(Hires),
0x00FE => Some(Lores),
0x00FB => Some(ScrollRight),
0x00FC => Some(ScrollLeft),
0x00FD => Some(Exit),
_ => match opcode & 0x00F0 {
0x00C0 => Some(ScrollDown {
amount: xyn(opcode).2 as usize,
}),
_ => None,
},
},
0x1000 => {
let address = nnn(opcode);
Expand Down Expand Up @@ -215,11 +246,9 @@ impl Instruction {
}
}
0xA000 => Some(SetIndex { src: nnn(opcode) }),

// TODO: Make this op's behaviour configurable.
0xB000 => Some(JumpOffset {
address: nnn(opcode),
offset_register: 0,
offset_register: xnn(opcode).0,
}),

0xC000 => {
Expand Down Expand Up @@ -253,10 +282,13 @@ impl Instruction {
0x18 => Some(SetSound { src: x }),
0x1E => Some(AddIndex { src: x }),
0x0A => Some(GetKey { dest: x }),
0x29 => Some(SetIndexFont { src: x }),
0x29 => Some(SetIndexFont { src: x, big: false }),
0x30 => Some(SetIndexFont { src: x, big: true }),
0x33 => Some(DecimalConversion { src: x }),
0x55 => Some(StoreMemory { registers: x }),
0x65 => Some(LoadMemory { registers: x }),
0x75 => Some(SaveFlags { x }),
0x85 => Some(LoadFlags { x }),
_ => None,
}
}
Expand Down
Loading

0 comments on commit 77c6ef3

Please sign in to comment.