mirror of
https://github.com/Noratrieb/chip-8.git
synced 2026-01-14 16:35:02 +01:00
naming
This commit is contained in:
parent
262209f725
commit
040b5d4477
2 changed files with 116 additions and 116 deletions
|
|
@ -11,7 +11,7 @@ use rand::Rng;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct Emulator {
|
struct Chip8Vm {
|
||||||
memory: [u8; 4096],
|
memory: [u8; 4096],
|
||||||
reg: [u8; 16],
|
reg: [u8; 16],
|
||||||
stack: [u16; 16],
|
stack: [u16; 16],
|
||||||
|
|
@ -22,7 +22,7 @@ struct Emulator {
|
||||||
sound_t: u8,
|
sound_t: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Emulator {
|
impl Default for Chip8Vm {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
memory: [0; 4096],
|
memory: [0; 4096],
|
||||||
|
|
@ -37,7 +37,7 @@ impl Default for Emulator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Emulator {
|
impl Chip8Vm {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
@ -69,17 +69,17 @@ impl Emulator {
|
||||||
|
|
||||||
|
|
||||||
pub fn run(program: &[u16]) {
|
pub fn run(program: &[u16]) {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
em.pc = 200;
|
vm.pc = 200;
|
||||||
|
|
||||||
while em.pc < program.len() as u16 {
|
while vm.pc < program.len() as u16 {
|
||||||
let instruction = program[em.pc as usize];
|
let instruction = program[vm.pc as usize];
|
||||||
execute(instruction, &mut em);
|
execute(instruction, &mut vm);
|
||||||
em.next();
|
vm.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(instruction: u16, em: &mut Emulator) {
|
fn execute(instruction: u16, em: &mut Chip8Vm) {
|
||||||
match instruction {
|
match instruction {
|
||||||
0x00E0 => unimplemented!(), // clear display
|
0x00E0 => unimplemented!(), // clear display
|
||||||
0x00EE => { // return subroutine
|
0x00EE => { // return subroutine
|
||||||
|
|
|
||||||
|
|
@ -1,179 +1,179 @@
|
||||||
use crate::interpreter::{Emulator, execute};
|
use crate::interpreter::{Chip8Vm, execute};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instructions_0_1_2() {
|
fn instructions_0_1_2() {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
//frame clearing is not implemented yet.
|
//frame clearing is not implemented yet.
|
||||||
em.pc = 10;
|
vm.pc = 10;
|
||||||
execute(0x20FF, &mut em); // call 0FF
|
execute(0x20FF, &mut vm); // call 0FF
|
||||||
assert_eq!(em.pc + 1, 0x0FF);
|
assert_eq!(vm.pc + 1, 0x0FF);
|
||||||
assert_eq!(em.sp, 1);
|
assert_eq!(vm.sp, 1);
|
||||||
em.pc = 0x0FF;
|
vm.pc = 0x0FF;
|
||||||
execute(0x00EE, &mut em); // return
|
execute(0x00EE, &mut vm); // return
|
||||||
assert_eq!(em.sp, 0);
|
assert_eq!(vm.sp, 0);
|
||||||
assert_eq!(em.pc, 10);
|
assert_eq!(vm.pc, 10);
|
||||||
execute(0x10AB, &mut em); // jmp to 0AB
|
execute(0x10AB, &mut vm); // jmp to 0AB
|
||||||
assert_eq!(em.pc + 1, 0x0AB);
|
assert_eq!(vm.pc + 1, 0x0AB);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instructions_3_4_5() {
|
fn instructions_3_4_5() {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
em.reg[0] = 0xF2;
|
vm.reg[0] = 0xF2;
|
||||||
execute(0x30F2, &mut em);
|
execute(0x30F2, &mut vm);
|
||||||
assert_eq!(em.pc, 1);
|
assert_eq!(vm.pc, 1);
|
||||||
execute(0x40F3, &mut em);
|
execute(0x40F3, &mut vm);
|
||||||
assert_eq!(em.pc, 2);
|
assert_eq!(vm.pc, 2);
|
||||||
execute(0x40F2, &mut em);
|
execute(0x40F2, &mut vm);
|
||||||
assert_eq!(em.pc, 2);
|
assert_eq!(vm.pc, 2);
|
||||||
em.reg[1] = 0xF2;
|
vm.reg[1] = 0xF2;
|
||||||
execute(0x5010, &mut em);
|
execute(0x5010, &mut vm);
|
||||||
assert_eq!(em.pc, 3);
|
assert_eq!(vm.pc, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instructions_6_7() {
|
fn instructions_6_7() {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
execute(0x60AB, &mut em);
|
execute(0x60AB, &mut vm);
|
||||||
assert_eq!(em.reg[0], 0xAB);
|
assert_eq!(vm.reg[0], 0xAB);
|
||||||
execute(0x69FF, &mut em);
|
execute(0x69FF, &mut vm);
|
||||||
assert_eq!(em.reg[9], 0xFF);
|
assert_eq!(vm.reg[9], 0xFF);
|
||||||
execute(0x7001, &mut em);
|
execute(0x7001, &mut vm);
|
||||||
assert_eq!(em.reg[0], 0xAC);
|
assert_eq!(vm.reg[0], 0xAC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// macros to simplify testing the 8xyz instructions
|
/// macros to simplify testing the 8xyz instructions
|
||||||
macro_rules! test_reg_ops {
|
macro_rules! test_reg_ops {
|
||||||
($i:literal: $x:literal $y:literal => $z:literal for $em:ident) => {
|
($i:literal: $x:literal $y:literal => $z:literal for $vm:ident) => {
|
||||||
$em.reg[0] = $x;
|
$vm.reg[0] = $x;
|
||||||
$em.reg[1] = $y;
|
$vm.reg[1] = $y;
|
||||||
crate::interpreter::execute($i, &mut $em);
|
crate::interpreter::execute($i, &mut $vm);
|
||||||
assert_eq!($em.reg[0], $z);
|
assert_eq!($vm.reg[0], $z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// macros to simplify testing the 8xyz instructions
|
/// macros to simplify testing the 8xyz instructions
|
||||||
macro_rules! test_reg_ops_flag {
|
macro_rules! test_reg_ops_flag {
|
||||||
($i:literal: $x:literal $y:literal => $z:literal + $f:literal for $em:ident) => {
|
($i:literal: $x:literal $y:literal => $z:literal + $f:literal for $vm:ident) => {
|
||||||
$em.reg[0] = $x;
|
$vm.reg[0] = $x;
|
||||||
$em.reg[1] = $y;
|
$vm.reg[1] = $y;
|
||||||
crate::interpreter::execute($i, &mut $em);
|
crate::interpreter::execute($i, &mut $vm);
|
||||||
assert_eq!($em.reg[0], $z);
|
assert_eq!($vm.reg[0], $z);
|
||||||
assert_eq!($em.reg[0xF], $f);
|
assert_eq!($vm.reg[0xF], $f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instructions_8xyz() {
|
fn instructions_8xyz() {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
em.reg[1] = 2;
|
vm.reg[1] = 2;
|
||||||
// 0 store V1 in V0
|
// 0 store V1 in V0
|
||||||
execute(0x8010, &mut em);
|
execute(0x8010, &mut vm);
|
||||||
assert_eq!(em.reg[0], 2);
|
assert_eq!(vm.reg[0], 2);
|
||||||
|
|
||||||
// 1 OR V0 and V1, expected result in V2
|
// 1 OR V0 and V1, expected result in V2
|
||||||
test_reg_ops!(0x8011: 0b10011111 0b11010001 => 0b11011111 for em);
|
test_reg_ops!(0x8011: 0b10011111 0b11010001 => 0b11011111 for vm);
|
||||||
|
|
||||||
// 2 AND V0 and V1, expected result in V2
|
// 2 AND V0 and V1, expected result in V2
|
||||||
test_reg_ops!(0x8012: 0b11011111 0b10010001 => 0b10010001 for em);
|
test_reg_ops!(0x8012: 0b11011111 0b10010001 => 0b10010001 for vm);
|
||||||
|
|
||||||
// 3 XOR V0 and V1, expected result in V2
|
// 3 XOR V0 and V1, expected result in V2
|
||||||
test_reg_ops!(0x8013: 0b11011111 0b10010001 => 0b01001110 for em);
|
test_reg_ops!(0x8013: 0b11011111 0b10010001 => 0b01001110 for vm);
|
||||||
|
|
||||||
// 4 ADD V0 to V1, overflow => flag
|
// 4 ADD V0 to V1, overflow => flag
|
||||||
test_reg_ops_flag!(0x8014: 10 10 => 20 + 0 for em);
|
test_reg_ops_flag!(0x8014: 10 10 => 20 + 0 for vm);
|
||||||
test_reg_ops_flag!(0x8014: 255 11 => 10 + 1 for em);
|
test_reg_ops_flag!(0x8014: 255 11 => 10 + 1 for vm);
|
||||||
|
|
||||||
// 5 SUB V1 from V0, V0 > V1 => flag
|
// 5 SUB V1 from V0, V0 > V1 => flag
|
||||||
test_reg_ops_flag!(0x8015: 20 10 => 10 + 1 for em);
|
test_reg_ops_flag!(0x8015: 20 10 => 10 + 1 for vm);
|
||||||
test_reg_ops_flag!(0x8015: 0 1 => 255 + 0 for em);
|
test_reg_ops_flag!(0x8015: 0 1 => 255 + 0 for vm);
|
||||||
|
|
||||||
// 6 SHR Shift V0 right by one bit, overflow => flag
|
// 6 SHR Shift V0 right by one bit, overflow => flag
|
||||||
test_reg_ops_flag!(0x8016: 0 0b10000000 => 0b01000000 + 0 for em);
|
test_reg_ops_flag!(0x8016: 0 0b10000000 => 0b01000000 + 0 for vm);
|
||||||
test_reg_ops_flag!(0x8016: 0 0b00000001 => 0b00000000 + 1 for em);
|
test_reg_ops_flag!(0x8016: 0 0b00000001 => 0b00000000 + 1 for vm);
|
||||||
|
|
||||||
// 7 Subtract V0 from V1, V1 > V0 => flag
|
// 7 Subtract V0 from V1, V1 > V0 => flag
|
||||||
test_reg_ops_flag!(0x8017: 10 20 => 10 + 1 for em);
|
test_reg_ops_flag!(0x8017: 10 20 => 10 + 1 for vm);
|
||||||
test_reg_ops_flag!(0x8017: 1 0 => 255 + 0 for em);
|
test_reg_ops_flag!(0x8017: 1 0 => 255 + 0 for vm);
|
||||||
|
|
||||||
// E SHL Shift V0 left by one bit, overflow => flag
|
// E SHL Shift V0 left by one bit, overflow => flag
|
||||||
test_reg_ops_flag!(0x801E: 0 0b00000001 => 0b00000010 + 0 for em);
|
test_reg_ops_flag!(0x801E: 0 0b00000001 => 0b00000010 + 0 for vm);
|
||||||
test_reg_ops_flag!(0x801E: 0 0b10000000 => 0b00000000 + 1 for em);
|
test_reg_ops_flag!(0x801E: 0 0b10000000 => 0b00000000 + 1 for vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instruction_9() {
|
fn instruction_9() {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
em.reg[0] = 10;
|
vm.reg[0] = 10;
|
||||||
em.reg[1] = 11;
|
vm.reg[1] = 11;
|
||||||
execute(0x9010, &mut em);
|
execute(0x9010, &mut vm);
|
||||||
assert_eq!(em.pc, 1);
|
assert_eq!(vm.pc, 1);
|
||||||
execute(0x9EE0, &mut em);
|
execute(0x9EE0, &mut vm);
|
||||||
assert_eq!(em.pc, 1);
|
assert_eq!(vm.pc, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instruction_a_b_c() {
|
fn instruction_a_b_c() {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
execute(0xA123, &mut em);
|
execute(0xA123, &mut vm);
|
||||||
assert_eq!(em.i, 0x123);
|
assert_eq!(vm.i, 0x123);
|
||||||
em.reg[0] = 100;
|
vm.reg[0] = 100;
|
||||||
execute(0xB123, &mut em);
|
execute(0xB123, &mut vm);
|
||||||
assert_eq!(em.pc, 100 + 0x123 - 1); // - 1 because the emulator does the next() at the end normally
|
assert_eq!(vm.pc, 100 + 0x123 - 1); // - 1 because the emulator does the next() at the end normally
|
||||||
|
|
||||||
execute(0xC000, &mut em);
|
execute(0xC000, &mut vm);
|
||||||
assert_eq!(em.reg[0], 0); // is 0 because the kk value is AND with the random value
|
assert_eq!(vm.reg[0], 0); // is 0 because the kk value is AND with the random value
|
||||||
execute(0xC00F, &mut em);
|
execute(0xC00F, &mut vm);
|
||||||
assert!(em.reg[0] < 0x10);
|
assert!(vm.reg[0] < 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instruction_f() {
|
fn instruction_f() {
|
||||||
let mut em = Emulator::default();
|
let mut vm = Chip8Vm::default();
|
||||||
|
|
||||||
em.delay_t = 245;
|
vm.delay_t = 245;
|
||||||
execute(0xF007, &mut em);
|
execute(0xF007, &mut vm);
|
||||||
assert_eq!(em.reg[0], 245);
|
assert_eq!(vm.reg[0], 245);
|
||||||
|
|
||||||
execute(0xF115, &mut em); // set delay_t = V1
|
execute(0xF115, &mut vm); // set delay_t = V1
|
||||||
assert_eq!(em.delay_t, 0);
|
assert_eq!(vm.delay_t, 0);
|
||||||
|
|
||||||
em.reg[0] = 13;
|
vm.reg[0] = 13;
|
||||||
execute(0xF018, &mut em); // set sound_t = V0
|
execute(0xF018, &mut vm); // set sound_t = V0
|
||||||
assert_eq!(em.sound_t, 13);
|
assert_eq!(vm.sound_t, 13);
|
||||||
|
|
||||||
em.reg[0] = 1;
|
vm.reg[0] = 1;
|
||||||
em.i = 10;
|
vm.i = 10;
|
||||||
execute(0xF01E, &mut em); // i = i + v0
|
execute(0xF01E, &mut vm); // i = i + v0
|
||||||
assert_eq!(em.i, 11);
|
assert_eq!(vm.i, 11);
|
||||||
|
|
||||||
// Fx19 unimplemented
|
// Fx19 unimplemented
|
||||||
|
|
||||||
|
|
||||||
em.i = 0;
|
vm.i = 0;
|
||||||
em.reg[0] = 255;
|
vm.reg[0] = 255;
|
||||||
em.reg[1] = 99;
|
vm.reg[1] = 99;
|
||||||
em.reg[2] = 1;
|
vm.reg[2] = 1;
|
||||||
execute(0xF033, &mut em);
|
execute(0xF033, &mut vm);
|
||||||
em.i = 3;
|
vm.i = 3;
|
||||||
execute(0xF133, &mut em);
|
execute(0xF133, &mut vm);
|
||||||
em.i = 6;
|
vm.i = 6;
|
||||||
execute(0xF233, &mut em);
|
execute(0xF233, &mut vm);
|
||||||
|
|
||||||
assert_eq!(&em.memory[0..9], &[2, 5, 5, 0, 9, 9, 0, 0, 1]);
|
assert_eq!(&vm.memory[0..9], &[2, 5, 5, 0, 9, 9, 0, 0, 1]);
|
||||||
|
|
||||||
// store all registers from 0 including A in memory at i
|
// store all registers from 0 including A in memory at i
|
||||||
for i in 0..=0xAu8 {
|
for i in 0..=0xAu8 {
|
||||||
em.reg[i as usize] = i + 1;
|
vm.reg[i as usize] = i + 1;
|
||||||
}
|
}
|
||||||
em.i = 100;
|
vm.i = 100;
|
||||||
execute(0xFA55, &mut em);
|
execute(0xFA55, &mut vm);
|
||||||
assert_eq!(&em.memory[100..=110], &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
|
assert_eq!(&vm.memory[100..=110], &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
|
||||||
|
|
||||||
// load all registers from 0 including A from memory at i
|
// load all registers from 0 including A from memory at i
|
||||||
for i in 0..=0xAu8 {
|
for i in 0..=0xAu8 {
|
||||||
em.memory[i as usize] = i + 1;
|
vm.memory[i as usize] = i + 1;
|
||||||
}
|
}
|
||||||
em.i = 0;
|
vm.i = 0;
|
||||||
execute(0xFA65, &mut em);
|
execute(0xFA65, &mut vm);
|
||||||
assert_eq!(&em.reg[0..=10], &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
|
assert_eq!(&vm.reg[0..=10], &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue