Refactor several opcodes + remove opcode property
This commit is contained in:
parent
05f52dd397
commit
f4a8840b91
77
src/emu.rs
77
src/emu.rs
|
@ -5,7 +5,6 @@ use std::path::Path;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Chip8 {
|
pub struct Chip8 {
|
||||||
opcode: u16,
|
|
||||||
i: u16,
|
i: u16,
|
||||||
pc: u16,
|
pc: u16,
|
||||||
sp: u8,
|
sp: u8,
|
||||||
|
@ -21,7 +20,6 @@ pub struct Chip8 {
|
||||||
impl Default for Chip8 {
|
impl Default for Chip8 {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut chip8 = Chip8 {
|
let mut chip8 = Chip8 {
|
||||||
opcode: 0,
|
|
||||||
i: 0,
|
i: 0,
|
||||||
pc: 0x200, // Progrm counter starts at 0x200
|
pc: 0x200, // Progrm counter starts at 0x200
|
||||||
sp: 0,
|
sp: 0,
|
||||||
|
@ -60,16 +58,16 @@ impl Chip8 {
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn execute_cycle(&mut self) {
|
pub fn execute_cycle(&mut self) {
|
||||||
self.opcode = self.get_opcode();
|
let opcode = self.get_opcode();
|
||||||
println!("{:#x}", self.opcode);
|
// println!("{:#x}", self.opcode);
|
||||||
self.execute_opcode();
|
self.execute_opcode(opcode);
|
||||||
|
|
||||||
self.delay.tick();
|
self.delay.tick();
|
||||||
self.sound.tick();
|
self.sound.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_font_set(&mut self) {
|
pub fn load_font_set(&mut self) {
|
||||||
self.memory[0..0x50].copy_from_slice(&Self::FONT_SET);
|
self.memory[0x50..0xA0].copy_from_slice(&Self::FONT_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_rom<P: AsRef<Path>>(&mut self, path: P) -> Result<(), io::Error> {
|
pub fn load_rom<P: AsRef<Path>>(&mut self, path: P) -> Result<(), io::Error> {
|
||||||
|
@ -98,11 +96,11 @@ impl Chip8 {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_opcode(&mut self) {
|
fn execute_opcode(&mut self, opcode: u16) {
|
||||||
let (nib_1, nib_2, nib_3, nib_4) = Self::get_nibs(self.opcode);
|
let (nib_1, nib_2, nib_3, nib_4) = Self::get_nibs(opcode);
|
||||||
|
|
||||||
let nnn: u16 = self.opcode & 0x0FFF;
|
let nnn: u16 = opcode & 0x0FFF;
|
||||||
let kk: u8 = (self.opcode & 0x00FF) as u8;
|
let kk: u8 = (opcode & 0x00FF) as u8;
|
||||||
let x = nib_2;
|
let x = nib_2;
|
||||||
let y = nib_3;
|
let y = nib_3;
|
||||||
let n = nib_4;
|
let n = nib_4;
|
||||||
|
@ -114,6 +112,8 @@ impl Chip8 {
|
||||||
(0x0, 0x0, 0xE, 0x0) => self.cls(),
|
(0x0, 0x0, 0xE, 0x0) => self.cls(),
|
||||||
// 00EE
|
// 00EE
|
||||||
(0x0, 0x0, 0xE, 0xE) => self.ret(),
|
(0x0, 0x0, 0xE, 0xE) => self.ret(),
|
||||||
|
// 0NNN
|
||||||
|
(0x0, _, _, _) => { /* Nothing to see here */ }
|
||||||
// 1NNN
|
// 1NNN
|
||||||
(0x1, _, _, _) => self.jmp_addr(nnn),
|
(0x1, _, _, _) => self.jmp_addr(nnn),
|
||||||
// 2NNN
|
// 2NNN
|
||||||
|
@ -179,7 +179,7 @@ impl Chip8 {
|
||||||
// Fx65
|
// Fx65
|
||||||
(0xF, _, 0x6, 0x5) => self.load_into_vx_from_i(x),
|
(0xF, _, 0x6, 0x5) => self.load_into_vx_from_i(x),
|
||||||
// Otherwise...
|
// Otherwise...
|
||||||
_ => panic!("UNIMPLEMENTED OPCODE: {:#x}", self.opcode),
|
_ => panic!("UNIMPLEMENTED OPCODE: {:#x}", opcode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ impl Chip8 {
|
||||||
|
|
||||||
fn jmp_addr(&mut self, nnn: u16) {
|
fn jmp_addr(&mut self, nnn: u16) {
|
||||||
// sets the program counter to addr (nnn)
|
// sets the program counter to addr (nnn)
|
||||||
self.pc = nnn;
|
self.pc = nnn - 2; // We want to execute nnn so decrement pc by 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_addr(&mut self, nnn: u16) {
|
fn call_addr(&mut self, nnn: u16) {
|
||||||
|
@ -205,7 +205,7 @@ impl Chip8 {
|
||||||
// pc is then set to addr
|
// pc is then set to addr
|
||||||
self.sp += 1;
|
self.sp += 1;
|
||||||
self.stack[self.sp as usize] = self.pc;
|
self.stack[self.sp as usize] = self.pc;
|
||||||
self.pc = nnn;
|
self.pc = nnn - 2; // see Chip8#jmp_addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn se_vx_byte(&mut self, x: u8, kk: u8) {
|
fn se_vx_byte(&mut self, x: u8, kk: u8) {
|
||||||
|
@ -236,6 +236,7 @@ impl Chip8 {
|
||||||
|
|
||||||
fn add_vx_byte(&mut self, x: u8, kk: u8) {
|
fn add_vx_byte(&mut self, x: u8, kk: u8) {
|
||||||
// calculate Vx + kk, then store it in Vx
|
// calculate Vx + kk, then store it in Vx
|
||||||
|
// This does indeed overflow without setting VF
|
||||||
self.v[x as usize] = self.v[x as usize].wrapping_add(kk);
|
self.v[x as usize] = self.v[x as usize].wrapping_add(kk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,22 +266,19 @@ impl Chip8 {
|
||||||
// only the lowest 8 bits of result are stored in Vx
|
// only the lowest 8 bits of result are stored in Vx
|
||||||
let x = x as usize;
|
let x = x as usize;
|
||||||
|
|
||||||
let (res, did_overflow) = self.v[x].overflowing_add(self.v[y as usize]);
|
let (sum, did_overflow) = self.v[x].overflowing_add(self.v[y as usize]);
|
||||||
|
self.v[x] = sum;
|
||||||
self.v[0xF] = if did_overflow { 1 } else { 0 };
|
self.v[0xF] = if did_overflow { 1 } else { 0 };
|
||||||
self.v[x] = res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_vx_vy(&mut self, x: u8, y: u8) {
|
fn sub_vx_vy(&mut self, x: u8, y: u8) {
|
||||||
// TODO: Confirm that the default behaviour
|
|
||||||
// for this opcode includes a wrapping subtraction
|
|
||||||
|
|
||||||
// subtract Vx and Vy, if Vx > Vy VF is set to 1, otherwise 0
|
// subtract Vx and Vy, if Vx > Vy VF is set to 1, otherwise 0
|
||||||
// then set Vx to Vx - Vy
|
// then set Vx to Vx - Vy
|
||||||
let vx = self.v[x as usize];
|
let x = x as usize;
|
||||||
let vy = self.v[y as usize];
|
let y = y as usize;
|
||||||
|
|
||||||
self.v[0xF] = if vx > vy { 1 } else { 0 };
|
self.v[0xF] = if self.v[x] > self.v[y] { 1 } else { 0 };
|
||||||
self.v[x as usize] = vx.wrapping_sub(vy);
|
self.v[x] = self.v[x].wrapping_sub(self.v[y]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shr(&mut self, x: u8) {
|
fn shr(&mut self, x: u8) {
|
||||||
|
@ -288,18 +286,18 @@ impl Chip8 {
|
||||||
// then shift Vx one to the right
|
// then shift Vx one to the right
|
||||||
let x = x as usize;
|
let x = x as usize;
|
||||||
|
|
||||||
self.v[0xF] = if (self.v[x] & 1) == 1 { 1 } else { 0 };
|
self.v[0xF] = if (self.v[x] & 0x01) == 0x01 { 1 } else { 0 };
|
||||||
self.v[x] >>= 1;
|
self.v[x] >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subn_vx_vy(&mut self, x: u8, y: u8) {
|
fn subn_vx_vy(&mut self, x: u8, y: u8) {
|
||||||
// subtract Vy and Vx, if Vy > Vx VF is set to 1, otherwise 0
|
// subtract Vy and Vx, if Vy > Vx VF is set to 1, otherwise 0
|
||||||
// then set Vx = Vy - Vx
|
// then set Vx = Vy - Vx
|
||||||
let vx = self.v[x as usize];
|
let x = x as usize;
|
||||||
let vy = self.v[y as usize];
|
let y = y as usize;
|
||||||
|
|
||||||
self.v[0xF] = if vy > vx { 1 } else { 0 };
|
self.v[0xF] = if self.v[y] > self.v[x] { 1 } else { 0 };
|
||||||
self.v[x as usize] = vy.wrapping_sub(vx);
|
self.v[x as usize] = self.v[y].wrapping_sub(self.v[x]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shl(&mut self, x: u8) {
|
fn shl(&mut self, x: u8) {
|
||||||
|
@ -325,7 +323,7 @@ impl Chip8 {
|
||||||
|
|
||||||
fn jmp_addr_with_offset(&mut self, nnn: u16) {
|
fn jmp_addr_with_offset(&mut self, nnn: u16) {
|
||||||
// set program counter to addr + V0
|
// set program counter to addr + V0
|
||||||
self.pc = nnn + self.v[0] as u16;
|
self.pc = nnn + self.v[0] as u16 - 2; // see Chip8#jmp_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rand(&mut self, x: u8, kk: u8) {
|
fn rand(&mut self, x: u8, kk: u8) {
|
||||||
|
@ -347,7 +345,6 @@ impl Chip8 {
|
||||||
fn skip_on_press(&mut self, x: u8) {
|
fn skip_on_press(&mut self, x: u8) {
|
||||||
// if current key is the same as the on in Vx
|
// if current key is the same as the on in Vx
|
||||||
// program counter is increased by 2
|
// program counter is increased by 2
|
||||||
|
|
||||||
if self.key.is_pressed(self.v[x as usize]) {
|
if self.key.is_pressed(self.v[x as usize]) {
|
||||||
self.pc += 2;
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
|
@ -356,7 +353,6 @@ impl Chip8 {
|
||||||
fn skip_not_pressed(&mut self, x: u8) {
|
fn skip_not_pressed(&mut self, x: u8) {
|
||||||
// if current key is not the sameas the one in Vx
|
// if current key is not the sameas the one in Vx
|
||||||
// increment the program counter by 2
|
// increment the program counter by 2
|
||||||
|
|
||||||
if !self.key.is_pressed(self.v[x as usize]) {
|
if !self.key.is_pressed(self.v[x as usize]) {
|
||||||
self.pc += 2;
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
|
@ -389,12 +385,16 @@ impl Chip8 {
|
||||||
|
|
||||||
fn add_vx_to_i(&mut self, x: u8) {
|
fn add_vx_to_i(&mut self, x: u8) {
|
||||||
// set I to be I + Vx
|
// set I to be I + Vx
|
||||||
self.i += self.v[x as usize] as u16;
|
// Althought not standard, we check for overflow as well here
|
||||||
|
// Memory is 4KB (12-bits) so anything mor than that "overflows"
|
||||||
|
let sum = self.i + self.v[x as usize] as u16;
|
||||||
|
self.v[0xF] = if sum > 0x0FFF { 1 } else { 0 };
|
||||||
|
self.i = sum & 0x0FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_i_to_hex_sprite_loc(&mut self, x: u8) {
|
fn set_i_to_hex_sprite_loc(&mut self, x: u8) {
|
||||||
// set I to location of hex sprite related to Vx
|
// set I to location of hex sprite related to Vx
|
||||||
self.i = self.v[x as usize] as u16 * 5;
|
self.i = 0x50 + (5 * self.v[x as usize] as u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_digits_to_i(&mut self, x: u8) {
|
fn copy_digits_to_i(&mut self, x: u8) {
|
||||||
|
@ -402,11 +402,11 @@ impl Chip8 {
|
||||||
// take tens digit and place it at I + 1
|
// take tens digit and place it at I + 1
|
||||||
// take ones digit and place it at I + 2
|
// take ones digit and place it at I + 2
|
||||||
let i = self.i as usize;
|
let i = self.i as usize;
|
||||||
let mut iter = Self::digits(self.v[x as usize] as usize);
|
let mut digit = Self::digits(self.v[x as usize] as usize);
|
||||||
|
|
||||||
let ones = iter.next().unwrap(); // Ther has to at least be a ones lol
|
let ones = digit.next().unwrap(); // Ther has to at least be a ones lol
|
||||||
let tens = iter.next().unwrap_or(0);
|
let tens = digit.next().unwrap_or(0);
|
||||||
let hundreds = iter.next().unwrap_or(0);
|
let hundreds = digit.next().unwrap_or(0);
|
||||||
|
|
||||||
self.memory[i] = hundreds as u8;
|
self.memory[i] = hundreds as u8;
|
||||||
self.memory[i + 1] = tens as u8;
|
self.memory[i + 1] = tens as u8;
|
||||||
|
@ -415,7 +415,6 @@ impl Chip8 {
|
||||||
|
|
||||||
fn copy_from_vx_to_memory(&mut self, x: u8) {
|
fn copy_from_vx_to_memory(&mut self, x: u8) {
|
||||||
// copy values v0 -> Vx to memory starting at i
|
// copy values v0 -> Vx to memory starting at i
|
||||||
|
|
||||||
for n in 0..=(x as usize) {
|
for n in 0..=(x as usize) {
|
||||||
self.memory[self.i as usize + n] = self.v[n];
|
self.memory[self.i as usize + n] = self.v[n];
|
||||||
}
|
}
|
||||||
|
@ -423,9 +422,7 @@ impl Chip8 {
|
||||||
|
|
||||||
fn load_into_vx_from_i(&mut self, x: u8) {
|
fn load_into_vx_from_i(&mut self, x: u8) {
|
||||||
// read what will be values of v0 -> vx from memory starting at i
|
// read what will be values of v0 -> vx from memory starting at i
|
||||||
let x = x as usize;
|
for n in 0..=(x as usize) {
|
||||||
|
|
||||||
for n in 0..=x {
|
|
||||||
self.v[n] = self.memory[self.i as usize + n];
|
self.v[n] = self.memory[self.i as usize + n];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue