Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rs/chip_emulator/src/chip8/cursive_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Display {
pub fn new(pixels: &[bool]) -> Self {
assert_eq!(pixels.len(), 64 * 32);
let mut tmp = [false; 64 * 32];
tmp.copy_from_slice(&pixels[..]);
tmp.copy_from_slice(pixels);
Display { pixels: tmp }
}
}
Expand Down Expand Up @@ -69,7 +69,7 @@ impl ChipWithCursiveDisplay for Chip8 {
if !self.draw {
return;
}
let display = get_display(&self);
let display = get_display(self);
gfx_sink
.send(Box::new(Box::new(move |s: &mut cursive::Cursive| {
s.pop_layer();
Expand Down
13 changes: 8 additions & 5 deletions rs/chip_emulator/src/chip8/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,24 @@ impl Chip for Chip8 {
return Err(LoadProgramError::ProgramTooLarge(program.len()));
}

for i in 0..program.len() {
self.set_memory_byte(program[i], (0x200 + i) as u16);
for (i, instruction) in program.iter().enumerate() {
self.set_memory_byte(*instruction, (0x200 + i) as u16);
}

Ok(())
}

fn cycle(&mut self) {
let opcode = self.next_instruction();
let mut state = self;
opcode.execute(&mut state);
let state = self;
opcode.execute(state);

state.cycles_since_timer_dec += 1;

if state.cycles_since_timer_dec % CHIP8_TIMER_RESOLUTION == 0 {
if state
.cycles_since_timer_dec
.is_multiple_of(CHIP8_TIMER_RESOLUTION)
{
if state.delay_timer > 0 {
state.delay_timer -= 1;
}
Expand Down
52 changes: 26 additions & 26 deletions rs/chip_emulator/src/chip8/opcodes/arithmetic_and_logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ use crate::chip8::{
define_instruction!(LdrInstruction, RegAndValue, 0x6);
impl Executable<Chip8> for LdrInstruction {
/// Opcode of the form `0x6XYZ` (LDR). Load a value `YZ` into `state.registers[X]`.
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
state.registers[self.reg() as usize] = self.value();
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

define_instruction!(AddInstruction, RegAndValue, 0x7);
impl Executable<Chip8> for AddInstruction {
/// Opcode of the form `0x7XYZ` (ADD). Add value `YZ` into `state.registers[X]`.
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
state.registers[self.reg() as usize] =
state.registers[self.reg() as usize].wrapping_add(self.value());
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

Expand Down Expand Up @@ -54,7 +54,7 @@ impl Executable<Chip8> for RegInstruction {
/// - If `Z == 0xE`, it sets `state.registers[X] = state.registers[X] << 1`; `state.registers[0xF]`
/// is set to `1` if the shifted out bit is set, and to `0` otherwise.
///
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
fn modify_registers(
state: &mut Chip8,
r1: u8,
Expand All @@ -71,54 +71,54 @@ impl Executable<Chip8> for RegInstruction {
}

match self.op3() {
0x0 => modify_registers(&mut state, self.op1(), self.op2(), |_, v2| (v2, None)),
0x1 => modify_registers(&mut state, self.op1(), self.op2(), |v1, v2| (v1 | v2, None)),
0x2 => modify_registers(&mut state, self.op1(), self.op2(), |v1, v2| (v1 & v2, None)),
0x3 => modify_registers(&mut state, self.op1(), self.op2(), |v1, v2| (v1 ^ v2, None)),
0x4 => modify_registers(&mut state, self.op1(), self.op2(), |v1, v2| {
0x0 => modify_registers(state, self.op1(), self.op2(), |_, v2| (v2, None)),
0x1 => modify_registers(state, self.op1(), self.op2(), |v1, v2| (v1 | v2, None)),
0x2 => modify_registers(state, self.op1(), self.op2(), |v1, v2| (v1 & v2, None)),
0x3 => modify_registers(state, self.op1(), self.op2(), |v1, v2| (v1 ^ v2, None)),
0x4 => modify_registers(state, self.op1(), self.op2(), |v1, v2| {
let (result, overflow) = v1.overflowing_add(v2);
(result, Some(overflow))
}),
0x5 => modify_registers(&mut state, self.op1(), self.op2(), |v1, v2| {
0x5 => modify_registers(state, self.op1(), self.op2(), |v1, v2| {
let (result, overflow) = v1.overflowing_sub(v2);
(result, Some(!overflow))
}),
0x6 => modify_registers(&mut state, self.op1(), self.op2(), |v1, _| {
0x6 => modify_registers(state, self.op1(), self.op2(), |v1, _| {
(v1 >> 1, Some(v1 & 1 != 0))
}),
0x7 => modify_registers(&mut state, self.op1(), self.op2(), |v1, v2| {
0x7 => modify_registers(state, self.op1(), self.op2(), |v1, v2| {
let (result, overflow) = v2.overflowing_sub(v1);
(result, Some(!overflow))
}),
0xE => modify_registers(&mut state, self.op1(), self.op2(), |v1, _| {
0xE => modify_registers(state, self.op1(), self.op2(), |v1, _| {
(v1 << 1, Some(v1 & 0x80 != 0))
}),
_ => panic!("Unsupported opcode"),
};
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

define_instruction!(LdInstruction, Address, 0xA);
impl Executable<Chip8> for LdInstruction {
/// Opcode of the form `0xAXYZ` (LD). Loads `XYZ` into `state.index`.
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
state.index = self.address();
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

define_instruction!(RndInstruction, RegAndValue, 0xC);
impl Executable<Chip8> for RndInstruction {
/// Opcode of the form `0xCXYZ` (RND). Generates a random value `v`, and sets
/// `state.registers[X] = v & YZ.
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
let mut rng = rng();
let sample = rng.random_range(0..=255);

state.registers[self.reg() as usize] = sample as u8 & self.value();

util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

Expand All @@ -133,7 +133,7 @@ impl Executable<Chip8> for DrwInstruction {
/// given in the index register.
/// - `state.registers[0xF]` is set to `1` if any pixel is flipped to `0`, and
/// to `0` otherwise.
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
fn translate_gfx(x: u16, y: u16) -> usize {
((x % 64) + ((y % 32) * 64)) as usize
}
Expand Down Expand Up @@ -169,7 +169,7 @@ impl Executable<Chip8> for DrwInstruction {
pixel_mask >>= 1;
}
}
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

Expand Down Expand Up @@ -201,7 +201,7 @@ impl Executable<Chip8> for LduInstruction {
/// - If `YZ == 0x65`, load `state.registers[0]` to `state.registers[X]` from memory starting
/// at `state.index`.
///
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
match self.value() {
0x07 => {
state.registers[self.reg() as usize] = state.delay_timer;
Expand Down Expand Up @@ -240,13 +240,13 @@ impl Executable<Chip8> for LduInstruction {
}
0x33 => {
let mut a: u8 = state.registers[self.reg() as usize];
state.memory[(state.index + 2) as usize] = (a % 10) as u8;
state.memory[(state.index + 2) as usize] = a % 10;

a /= 10;
state.memory[(state.index + 1) as usize] = (a % 10) as u8;
state.memory[(state.index + 1) as usize] = a % 10;

a /= 10;
state.memory[state.index as usize] = (a % 10) as u8;
state.memory[state.index as usize] = a % 10;
}
0x55 => {
for reg in 0x0..=self.reg() {
Expand All @@ -262,6 +262,6 @@ impl Executable<Chip8> for LduInstruction {
}
_ => unimplemented!("Unsupported opcode"),
}
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}
4 changes: 2 additions & 2 deletions rs/chip_emulator/src/chip8/opcodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ impl Opcode {
}
}

pub(super) fn execute(self, mut state: &mut Chip8) {
pub(super) fn execute(self, state: &mut Chip8) {
let executable_opcode: Box<dyn Executable<Chip8>> = self.into();
executable_opcode.execute(&mut state);
executable_opcode.execute(state);
}
}

Expand Down
32 changes: 16 additions & 16 deletions rs/chip_emulator/src/chip8/opcodes/program_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,56 +18,56 @@ impl Executable<Chip8> for CallInstruction {
fn execute(&self, state: &mut Chip8) {
assert!(state.stack_pointer < 16, "Stack overflow");
state.stack[state.stack_pointer as usize] = state.program_counter;
state.stack_pointer = state.stack_pointer + 1;
state.stack_pointer += 1;
state.program_counter = self.address();
}
}

define_instruction!(SeInstruction, RegAndValue, 0x3);
impl Executable<Chip8> for SeInstruction {
/// Opcode of the form `0x3XYZ` (SE). Skip the next instruction if `state.registers[X] == YZ`.
fn execute(&self, mut state: &mut Chip8) {
util::conditional_skip(&self, &mut state, |instruction, state| {
fn execute(&self, state: &mut Chip8) {
util::conditional_skip(&self, state, |instruction, state| {
state.registers[instruction.reg() as usize] == instruction.value()
});
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

define_instruction!(SneInstruction, RegAndValue, 0x4);
impl Executable<Chip8> for SneInstruction {
/// Opcode of the form `0x4XYZ` (SNE). Skip the next instruction if `state.registers[X] != YZ`.
fn execute(&self, mut state: &mut Chip8) {
util::conditional_skip(&self, &mut state, |instruction, state| {
fn execute(&self, state: &mut Chip8) {
util::conditional_skip(&self, state, |instruction, state| {
state.registers[instruction.reg() as usize] != instruction.value()
});
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

define_instruction!(SreInstruction, Operands, 0x5);
impl Executable<Chip8> for SreInstruction {
/// Opcode of the form `0x5XY0` (SRE). Skip the next instruction if `state.registers[X] == state.registers[y]`.
fn execute(&self, mut state: &mut Chip8) {
util::conditional_skip(&self, &mut state, |instruction, state| {
fn execute(&self, state: &mut Chip8) {
util::conditional_skip(&self, state, |instruction, state| {
assert_eq!(instruction.op3(), 0, "Unsupported opcode");
state.registers[instruction.op1() as usize]
== state.registers[instruction.op2() as usize]
});
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

define_instruction!(SrneInstruction, Operands, 0x9);
impl Executable<Chip8> for SrneInstruction {
/// Opcode of the form `0x9XY0` (SRNE). Skip the next instruction if `state.registers[X] != state.registers[Y]`.
fn execute(&self, mut state: &mut Chip8) {
util::conditional_skip(&self, &mut state, |instruction, state| {
fn execute(&self, state: &mut Chip8) {
util::conditional_skip(&self, state, |instruction, state| {
assert_eq!(instruction.op3(), 0, "Unsupported opcode");
state.registers[instruction.op1() as usize]
!= state.registers[instruction.op2() as usize]
});
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}

Expand All @@ -89,15 +89,15 @@ impl Executable<Chip8> for SkInstruction {
///
/// - If `YZ == A1`, it skips the next instruction if the key stored in `state.registers[X]`
/// is not pressed.
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
let skip = match self.value() {
0x9E => state.input_pins[state.registers[self.reg() as usize] as usize],
0xA1 => !state.input_pins[state.registers[self.reg() as usize] as usize],
_ => unimplemented!("Unsupported opcode"),
};
if skip {
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
util::increment_program_counter(&mut state);
util::increment_program_counter(state);
}
}
6 changes: 3 additions & 3 deletions rs/chip_emulator/src/chip8/opcodes/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ impl Executable<Chip8> for SysInstruction {
///
/// - If `XYZ == 0x0EE`, it returns from the current subroutine.
///
fn execute(&self, mut state: &mut Chip8) {
fn execute(&self, state: &mut Chip8) {
match self.address() {
0x0E0 => {
state.output_pins = [false; 64 * 32];
Expand All @@ -21,8 +21,8 @@ impl Executable<Chip8> for SysInstruction {
0x0EE => {
assert!(state.stack_pointer > 0, "Stack underflow");
state.program_counter = state.stack[(state.stack_pointer - 1) as usize];
state.stack_pointer = state.stack_pointer - 1;
util::increment_program_counter(&mut state);
state.stack_pointer -= 1;
util::increment_program_counter(state);
}
_ => panic!("Opcode not supported"),
};
Expand Down
Loading
Loading