mirror of https://github.com/Ivsucram/ivsemu.git
Rust fmt
This commit is contained in:
parent
3b9d18447f
commit
a05f885ebc
|
@ -7,7 +7,8 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
rand = "0.8.4"
|
||||
vulkano = "0.24.0"
|
||||
# vulkano = "0.24.0"
|
||||
# imgui = "0.7.0"
|
||||
|
||||
[dependencies.sdl2]
|
||||
version = "0.34.5"
|
||||
|
|
|
@ -2,41 +2,63 @@
|
|||
use ::sdl2;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
const DISPLAY_WIDTH: usize = 64;
|
||||
const DISPLAY_HEIGHT: usize = 32;
|
||||
const DISPLAY_SCALE: u32 = 10;
|
||||
const DISPLAY_SCALE: u32 = 30;
|
||||
|
||||
pub struct ProgramCounter(usize);
|
||||
pub struct Ram([u8; 4 * 1024]);
|
||||
pub struct DisplayBuffer([[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH]);
|
||||
pub struct Registers{
|
||||
x_0: u8, x_1: u8, x_2: u8, x_3: u8, x_4: u8, x_5: u8, x_6: u8, x_7: u8,
|
||||
x_8: u8, x_9: u8, x_a: u8, x_b: u8, x_c: u8, x_d: u8, x_e: u8, x_f: u8
|
||||
pub struct Ram {
|
||||
ram: [u8; 4 * 1024],
|
||||
font_address: usize,
|
||||
rom_address: usize,
|
||||
}
|
||||
pub struct Clock{
|
||||
pub struct Registers {
|
||||
x_0: u8,
|
||||
x_1: u8,
|
||||
x_2: u8,
|
||||
x_3: u8,
|
||||
x_4: u8,
|
||||
x_5: u8,
|
||||
x_6: u8,
|
||||
x_7: u8,
|
||||
x_8: u8,
|
||||
x_9: u8,
|
||||
x_a: u8,
|
||||
x_b: u8,
|
||||
x_c: u8,
|
||||
x_d: u8,
|
||||
x_e: u8,
|
||||
x_f: u8,
|
||||
}
|
||||
pub struct Clock {
|
||||
tick: u8,
|
||||
clock_hz: u128,
|
||||
elapsed: std::time::SystemTime
|
||||
clock_hz: f64,
|
||||
elapsed: std::time::SystemTime,
|
||||
}
|
||||
pub struct Keypad {
|
||||
pub struct Keypad {
|
||||
key_status: [bool; 0x10],
|
||||
keys: std::collections::HashMap<sdl2::keyboard::Keycode, usize>
|
||||
keys: std::collections::HashMap<sdl2::keyboard::Keycode, usize>,
|
||||
}
|
||||
pub struct OpCodes {
|
||||
opcode: u16,
|
||||
n1: u8, n2: u8, n3: u8, n4: u8,
|
||||
x: usize, y: usize,
|
||||
n: u8, nn: u8, nnn: usize
|
||||
pub struct OpCodes {
|
||||
opcode: u16,
|
||||
n1: u8,
|
||||
n2: u8,
|
||||
n3: u8,
|
||||
n4: u8,
|
||||
x: usize,
|
||||
y: usize,
|
||||
n: u8,
|
||||
nn: u8,
|
||||
nnn: usize,
|
||||
str_to_hex_helper: std::collections::HashMap<char, Option<u8>>, // Helper
|
||||
}
|
||||
|
||||
impl ProgramCounter {
|
||||
fn init() -> ProgramCounter {
|
||||
ProgramCounter {
|
||||
0: 0x200
|
||||
}
|
||||
ProgramCounter { 0: 0x200 }
|
||||
}
|
||||
|
||||
fn increment(&mut self) {
|
||||
|
@ -51,29 +73,67 @@ impl ProgramCounter {
|
|||
impl Registers {
|
||||
fn init() -> Registers {
|
||||
Registers {
|
||||
x_0: 0, x_1: 0, x_2: 0, x_3: 0, x_4: 0, x_5: 0, x_6: 0, x_7: 0,
|
||||
x_8: 0, x_9: 0, x_a: 0, x_b: 0, x_c: 0, x_d: 0, x_e: 0, x_f: 0
|
||||
x_0: 0,
|
||||
x_1: 0,
|
||||
x_2: 0,
|
||||
x_3: 0,
|
||||
x_4: 0,
|
||||
x_5: 0,
|
||||
x_6: 0,
|
||||
x_7: 0,
|
||||
x_8: 0,
|
||||
x_9: 0,
|
||||
x_a: 0,
|
||||
x_b: 0,
|
||||
x_c: 0,
|
||||
x_d: 0,
|
||||
x_e: 0,
|
||||
x_f: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, register: usize) -> u8 {
|
||||
assert!(register <= 0xF);
|
||||
match register {
|
||||
0x0 => self.x_0, 0x1 => self.x_1, 0x2 => self.x_2, 0x3 => self.x_3,
|
||||
0x4 => self.x_4, 0x5 => self.x_5, 0x6 => self.x_6, 0x7 => self.x_7,
|
||||
0x8 => self.x_8, 0x9 => self.x_9, 0xA => self.x_a, 0xB => self.x_b,
|
||||
0xC => self.x_c, 0xD => self.x_d, 0xE => self.x_e, 0xF => self.x_f,
|
||||
_ => 0
|
||||
0x0 => self.x_0,
|
||||
0x1 => self.x_1,
|
||||
0x2 => self.x_2,
|
||||
0x3 => self.x_3,
|
||||
0x4 => self.x_4,
|
||||
0x5 => self.x_5,
|
||||
0x6 => self.x_6,
|
||||
0x7 => self.x_7,
|
||||
0x8 => self.x_8,
|
||||
0x9 => self.x_9,
|
||||
0xA => self.x_a,
|
||||
0xB => self.x_b,
|
||||
0xC => self.x_c,
|
||||
0xD => self.x_d,
|
||||
0xE => self.x_e,
|
||||
0xF => self.x_f,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, register: usize, value: u8) {
|
||||
assert!(register <= 0xF);
|
||||
match register {
|
||||
0x0 => self.x_0 = value, 0x1 => self.x_1 = value, 0x2 => self.x_2 = value, 0x3 => self.x_3 = value,
|
||||
0x4 => self.x_4 = value, 0x5 => self.x_5 = value, 0x6 => self.x_6 = value, 0x7 => self.x_7 = value,
|
||||
0x8 => self.x_8 = value, 0x9 => self.x_9 = value, 0xA => self.x_a = value, 0xB => self.x_b = value,
|
||||
0xC => self.x_c = value, 0xD => self.x_d = value, 0xE => self.x_e = value, 0xF => self.x_f = value,
|
||||
0x0 => self.x_0 = value,
|
||||
0x1 => self.x_1 = value,
|
||||
0x2 => self.x_2 = value,
|
||||
0x3 => self.x_3 = value,
|
||||
0x4 => self.x_4 = value,
|
||||
0x5 => self.x_5 = value,
|
||||
0x6 => self.x_6 = value,
|
||||
0x7 => self.x_7 = value,
|
||||
0x8 => self.x_8 = value,
|
||||
0x9 => self.x_9 = value,
|
||||
0xA => self.x_a = value,
|
||||
0xB => self.x_b = value,
|
||||
0xC => self.x_c = value,
|
||||
0xD => self.x_d = value,
|
||||
0xE => self.x_e = value,
|
||||
0xF => self.x_f = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -82,63 +142,83 @@ impl Registers {
|
|||
impl Ram {
|
||||
fn init() -> Ram {
|
||||
Ram {
|
||||
0: [0x00; 4 * 1024]
|
||||
ram: [0x00; 4 * 1024],
|
||||
font_address: 0x50 as usize,
|
||||
rom_address: 0x200 as usize,
|
||||
}
|
||||
}
|
||||
|
||||
fn init_fonts(&mut self) {
|
||||
let font_address = 0x50;
|
||||
let fonts: [u8; 80] = [
|
||||
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
||||
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
||||
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
||||
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
||||
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
||||
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
||||
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
||||
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
||||
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
||||
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
||||
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
||||
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
||||
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||||
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||||
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
||||
0xF0, 0x80, 0xF0, 0x80, 0x80]; // F
|
||||
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
||||
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
||||
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
||||
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
||||
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
||||
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
||||
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
||||
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
||||
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
||||
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
||||
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
||||
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
||||
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||||
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||||
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
||||
0xF0, 0x80, 0xF0, 0x80, 0x80, // F
|
||||
];
|
||||
for i in 0..fonts.len() {
|
||||
self.0[i + font_address] = fonts[i];
|
||||
self.ram[i + self.font_address] = fonts[i];
|
||||
}
|
||||
}
|
||||
|
||||
fn load_rom(&mut self, rom: &[u8] ) {
|
||||
assert!(rom.len() <= self.0.len() - 0x200, "ROM is bigger than Chip-8 RAM");
|
||||
fn load_rom(&mut self, rom: &[u8]) {
|
||||
assert!(
|
||||
rom.len() <= self.ram.len() - 0x200,
|
||||
"ROM is bigger than Chip-8 RAM"
|
||||
);
|
||||
for i in 0..rom.len() {
|
||||
self.0[0x200 + i] = rom[i];
|
||||
self.ram[self.rom_address + i] = rom[i];
|
||||
}
|
||||
}
|
||||
|
||||
fn read8(&self, addr: usize) -> u8 {
|
||||
assert!(addr <= self.0.len(), "addr = {}, self.0.len() = {}", addr, self.0.len());
|
||||
self.0[addr]
|
||||
assert!(
|
||||
addr <= self.ram.len(),
|
||||
"addr = {}, self.0.len() = {}",
|
||||
addr,
|
||||
self.ram.len()
|
||||
);
|
||||
self.ram[addr]
|
||||
}
|
||||
|
||||
fn read16(&self, addr: usize) -> u16 {
|
||||
assert!(addr < self.0.len(), "addr = {}, self.0.len() = {}", addr, self.0.len());
|
||||
(self.0[addr] as u16) << 8 | self.0[addr+1] as u16
|
||||
assert!(
|
||||
addr < self.ram.len(),
|
||||
"addr = {}, self.0.len() = {}",
|
||||
addr,
|
||||
self.ram.len()
|
||||
);
|
||||
(self.ram[addr] as u16) << 8 | self.ram[addr + 1] as u16
|
||||
}
|
||||
|
||||
fn write(&mut self, addr: usize, value: u8) {
|
||||
assert!(addr < self.0.len());
|
||||
self.0[addr] = value;
|
||||
assert!(
|
||||
addr < self.ram.len(),
|
||||
"addr = {}, self.0.len() = {}",
|
||||
addr,
|
||||
self.ram.len()
|
||||
);
|
||||
self.ram[addr] = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Clock {
|
||||
fn init() -> Clock {
|
||||
Clock {
|
||||
tick: 255,
|
||||
clock_hz: 60,
|
||||
elapsed: std::time::SystemTime::now()
|
||||
tick: 0xFF,
|
||||
clock_hz: 60.,
|
||||
elapsed: std::time::SystemTime::now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,8 +226,10 @@ impl Clock {
|
|||
let mut res: bool = false;
|
||||
match self.elapsed.elapsed() {
|
||||
Ok(elapsed) => {
|
||||
if elapsed.as_secs_f32() >= 1./(self.clock_hz as f32) {
|
||||
if self.tick > 0 { self.tick -= 1; }
|
||||
if elapsed.as_secs_f64() >= self.clock_hz_as_secs_f64() {
|
||||
if self.tick > 0 {
|
||||
self.tick -= 1;
|
||||
}
|
||||
self.reset_elapsed();
|
||||
res = true;
|
||||
}
|
||||
|
@ -162,36 +244,44 @@ impl Clock {
|
|||
fn reset_elapsed(&mut self) {
|
||||
self.elapsed = std::time::SystemTime::now();
|
||||
}
|
||||
|
||||
fn clock_hz_as_secs_f64(&self) -> f64 {
|
||||
1. / self.clock_hz
|
||||
}
|
||||
}
|
||||
|
||||
impl Keypad {
|
||||
fn init() -> Keypad {
|
||||
Keypad {
|
||||
key_status: [false; 0x10],
|
||||
keys: [(sdl2::keyboard::Keycode::Num1, 0x1),
|
||||
(sdl2::keyboard::Keycode::Num2, 0x2),
|
||||
(sdl2::keyboard::Keycode::Num3, 0x3),
|
||||
(sdl2::keyboard::Keycode::Num4, 0xC),
|
||||
(sdl2::keyboard::Keycode::Q, 0x4),
|
||||
(sdl2::keyboard::Keycode::W, 0x5),
|
||||
(sdl2::keyboard::Keycode::E, 0x6),
|
||||
(sdl2::keyboard::Keycode::R, 0xD),
|
||||
(sdl2::keyboard::Keycode::A, 0x7),
|
||||
(sdl2::keyboard::Keycode::S, 0x8),
|
||||
(sdl2::keyboard::Keycode::D, 0x9),
|
||||
(sdl2::keyboard::Keycode::F, 0xE),
|
||||
(sdl2::keyboard::Keycode::Z, 0xA),
|
||||
(sdl2::keyboard::Keycode::X, 0x0),
|
||||
(sdl2::keyboard::Keycode::C, 0xB),
|
||||
(sdl2::keyboard::Keycode::V, 0xF)
|
||||
].iter().cloned().collect()
|
||||
keys: [
|
||||
(sdl2::keyboard::Keycode::Num1, 0x1),
|
||||
(sdl2::keyboard::Keycode::Num2, 0x2),
|
||||
(sdl2::keyboard::Keycode::Num3, 0x3),
|
||||
(sdl2::keyboard::Keycode::Num4, 0xC),
|
||||
(sdl2::keyboard::Keycode::Q, 0x4),
|
||||
(sdl2::keyboard::Keycode::W, 0x5),
|
||||
(sdl2::keyboard::Keycode::E, 0x6),
|
||||
(sdl2::keyboard::Keycode::R, 0xD),
|
||||
(sdl2::keyboard::Keycode::A, 0x7),
|
||||
(sdl2::keyboard::Keycode::S, 0x8),
|
||||
(sdl2::keyboard::Keycode::D, 0x9),
|
||||
(sdl2::keyboard::Keycode::F, 0xE),
|
||||
(sdl2::keyboard::Keycode::Z, 0xA),
|
||||
(sdl2::keyboard::Keycode::X, 0x0),
|
||||
(sdl2::keyboard::Keycode::C, 0xB),
|
||||
(sdl2::keyboard::Keycode::V, 0xF),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_keycode(&self, keycode: sdl2::keyboard::Keycode) -> Option<usize> {
|
||||
match self.keys.get(&keycode) {
|
||||
Some(chip8_key) => Some(*chip8_key),
|
||||
None => None
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +292,7 @@ impl Keypad {
|
|||
fn being_pressed(&self) -> Option<u8> {
|
||||
for key in 0x0..0x10 {
|
||||
if self.key_status[key] {
|
||||
return Some(key as u8)
|
||||
return Some(key as u8);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -220,7 +310,7 @@ impl Keypad {
|
|||
impl DisplayBuffer {
|
||||
fn init() -> DisplayBuffer {
|
||||
DisplayBuffer {
|
||||
0: [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH]
|
||||
0: [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,20 +321,49 @@ impl DisplayBuffer {
|
|||
|
||||
impl OpCodes {
|
||||
fn init(opcode: u16) -> OpCodes {
|
||||
let n1 = (opcode & 0xF000) >> 12;
|
||||
let n2 = (opcode & 0xF00) >> 8;
|
||||
let n3 = (opcode & 0xF0) >> 4;
|
||||
let n4 = opcode & 0xF;
|
||||
let nn = opcode & 0xFF;
|
||||
let nnn = opcode & 0xFFF;
|
||||
let n1 = (opcode & 0xF000) >> 12;
|
||||
let n2 = (opcode & 0xF00) >> 8;
|
||||
let n3 = (opcode & 0xF0) >> 4;
|
||||
let n4 = opcode & 0xF;
|
||||
let nn = opcode & 0xFF;
|
||||
let nnn = opcode & 0xFFF;
|
||||
|
||||
OpCodes {
|
||||
opcode: opcode,
|
||||
n1: n1 as u8, n2: n2 as u8, n3: n3 as u8, n4: n4 as u8,
|
||||
x: n2 as usize, y: n3 as usize,
|
||||
n: n4 as u8, nn: nn as u8, nnn: nnn as usize
|
||||
n1: n1 as u8,
|
||||
n2: n2 as u8,
|
||||
n3: n3 as u8,
|
||||
n4: n4 as u8,
|
||||
x: n2 as usize,
|
||||
y: n3 as usize,
|
||||
n: n4 as u8,
|
||||
nn: nn as u8,
|
||||
nnn: nnn as usize,
|
||||
|
||||
str_to_hex_helper: [
|
||||
('0', Some(0x0)),
|
||||
('1', Some(0x1)),
|
||||
('2', Some(0x2)),
|
||||
('3', Some(0x3)),
|
||||
('4', Some(0x4)),
|
||||
('5', Some(0x5)),
|
||||
('6', Some(0x6)),
|
||||
('7', Some(0x7)),
|
||||
('8', Some(0x8)),
|
||||
('9', Some(0x9)),
|
||||
('A', Some(0xA)),
|
||||
('B', Some(0xB)),
|
||||
('C', Some(0xC)),
|
||||
('D', Some(0xD)),
|
||||
('E', Some(0xE)),
|
||||
('F', Some(0xF)),
|
||||
('?', None),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CPU {
|
||||
|
@ -259,8 +378,6 @@ struct CPU {
|
|||
keypad: Keypad, // Keypad
|
||||
db: DisplayBuffer, // Display Buffer
|
||||
op: OpCodes, // Operation Code
|
||||
|
||||
str_to_hex_helper: std::collections::HashMap<char, Option<u8>> // Helper
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
|
@ -277,12 +394,6 @@ impl CPU {
|
|||
keypad: Keypad::init(),
|
||||
db: DisplayBuffer::init(),
|
||||
op: OpCodes::init(0000),
|
||||
|
||||
str_to_hex_helper: [('0', Some(0x0)), ('1', Some(0x1)), ('2', Some(0x2)), ('3', Some(0x3)),
|
||||
('4', Some(0x4)), ('5', Some(0x5)), ('6', Some(0x6)), ('7', Some(0x7)),
|
||||
('8', Some(0x8)), ('9', Some(0x9)), ('A', Some(0xA)), ('B', Some(0xB)),
|
||||
('C', Some(0xC)), ('D', Some(0xD)), ('E', Some(0xE)), ('F', Some(0xF)),
|
||||
('?', None)].iter().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,108 +404,179 @@ impl CPU {
|
|||
|
||||
fn decode(&mut self) {
|
||||
//TODO: function pointers
|
||||
if self.decode_match("00E0") { op_00e0(self);
|
||||
} else if self.decode_match("1???") { op_1nnn(self);
|
||||
} else if self.decode_match("00EE") { op_00ee(self);
|
||||
} else if self.decode_match("2???") { op_2nnn(self);
|
||||
} else if self.decode_match("3???") { op_3xnn(self);
|
||||
} else if self.decode_match("4???") { op_4xnn(self);
|
||||
} else if self.decode_match("5??0") { op_5xy0(self);
|
||||
} else if self.decode_match("9??0") { op_9xy0(self);
|
||||
} else if self.decode_match("6???") { op_6xnn(self);
|
||||
} else if self.decode_match("7???") { op_7xnn(self);
|
||||
} else if self.decode_match("8??0") { op_8xy0(self);
|
||||
} else if self.decode_match("8??1") { op_8xy1(self);
|
||||
} else if self.decode_match("8??2") { op_8xy2(self);
|
||||
} else if self.decode_match("8??3") { op_8xy3(self);
|
||||
} else if self.decode_match("8??4") { op_8xy4(self);
|
||||
} else if self.decode_match("8??5") { op_8xy5(self);
|
||||
} else if self.decode_match("8??6") { op_8xy6(self);
|
||||
} else if self.decode_match("8??7") { op_8xy7(self);
|
||||
} else if self.decode_match("8??E") { op_8xye(self);
|
||||
} else if self.decode_match("A???") { op_annn(self);
|
||||
} else if self.decode_match("B???") { op_bnnn(self);
|
||||
} else if self.decode_match("C???") { op_cxnn(self);
|
||||
} else if self.decode_match("D???") { op_dxyn(self);
|
||||
} else if self.decode_match("E?9E") { op_ex9e(self);
|
||||
} else if self.decode_match("E?A1") { op_exa1(self);
|
||||
} else if self.decode_match("F??7") { op_fx07(self);
|
||||
} else if self.decode_match("F?15") { op_fx15(self);
|
||||
} else if self.decode_match("F?18") { op_fx18(self);
|
||||
} else if self.decode_match("F?1E") { op_fx1e(self);
|
||||
} else if self.decode_match("F?0A") { op_fx0a(self);
|
||||
} else if self.decode_match("F?29") { op_fx29(self);
|
||||
} else if self.decode_match("F?33") { op_fx33(self);
|
||||
} else if self.decode_match("F?55") { op_fx55(self);
|
||||
} else if self.decode_match("F?65") { op_fx65(self);
|
||||
if self.decode_match("00E0") {
|
||||
op_00e0(self);
|
||||
} else if self.decode_match("1???") {
|
||||
op_1nnn(self);
|
||||
} else if self.decode_match("00EE") {
|
||||
op_00ee(self);
|
||||
} else if self.decode_match("2???") {
|
||||
op_2nnn(self);
|
||||
} else if self.decode_match("3???") {
|
||||
op_3xnn(self);
|
||||
} else if self.decode_match("4???") {
|
||||
op_4xnn(self);
|
||||
} else if self.decode_match("5??0") {
|
||||
op_5xy0(self);
|
||||
} else if self.decode_match("9??0") {
|
||||
op_9xy0(self);
|
||||
} else if self.decode_match("6???") {
|
||||
op_6xnn(self);
|
||||
} else if self.decode_match("7???") {
|
||||
op_7xnn(self);
|
||||
} else if self.decode_match("8??0") {
|
||||
op_8xy0(self);
|
||||
} else if self.decode_match("8??1") {
|
||||
op_8xy1(self);
|
||||
} else if self.decode_match("8??2") {
|
||||
op_8xy2(self);
|
||||
} else if self.decode_match("8??3") {
|
||||
op_8xy3(self);
|
||||
} else if self.decode_match("8??4") {
|
||||
op_8xy4(self);
|
||||
} else if self.decode_match("8??5") {
|
||||
op_8xy5(self);
|
||||
} else if self.decode_match("8??6") {
|
||||
op_8xy6(self);
|
||||
} else if self.decode_match("8??7") {
|
||||
op_8xy7(self);
|
||||
} else if self.decode_match("8??E") {
|
||||
op_8xye(self);
|
||||
} else if self.decode_match("A???") {
|
||||
op_annn(self);
|
||||
} else if self.decode_match("B???") {
|
||||
op_bnnn(self);
|
||||
} else if self.decode_match("C???") {
|
||||
op_cxnn(self);
|
||||
} else if self.decode_match("D???") {
|
||||
op_dxyn(self);
|
||||
} else if self.decode_match("E?9E") {
|
||||
op_ex9e(self);
|
||||
} else if self.decode_match("E?A1") {
|
||||
op_exa1(self);
|
||||
} else if self.decode_match("F??7") {
|
||||
op_fx07(self);
|
||||
} else if self.decode_match("F?15") {
|
||||
op_fx15(self);
|
||||
} else if self.decode_match("F?18") {
|
||||
op_fx18(self);
|
||||
} else if self.decode_match("F?1E") {
|
||||
op_fx1e(self);
|
||||
} else if self.decode_match("F?0A") {
|
||||
op_fx0a(self);
|
||||
} else if self.decode_match("F?29") {
|
||||
op_fx29(self);
|
||||
} else if self.decode_match("F?33") {
|
||||
op_fx33(self);
|
||||
} else if self.decode_match("F?55") {
|
||||
op_fx55(self);
|
||||
} else if self.decode_match("F?65") {
|
||||
op_fx65(self);
|
||||
} else {
|
||||
println!{"Unknown instruction: {:04x}", self.op.opcode};
|
||||
println! {"Unknown instruction: {:04x}", self.op.opcode};
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_match(&self, hex_code: &str) -> bool {
|
||||
let mut res: bool = true;
|
||||
assert!(
|
||||
hex_code.len() == 4,
|
||||
"Instruction with wrong size. All chip-8 instructions have 16 bits"
|
||||
);
|
||||
assert!(hex_code.ne("????"), "???? is a invalid instruction");
|
||||
let mut res: bool = false;
|
||||
for (i, c) in hex_code.chars().enumerate() {
|
||||
match self.str_to_hex_helper.get(&c) {
|
||||
Some(Some(hex)) => res = res && self.compare_nibble(i, &hex),
|
||||
Some(None) => res = res && true,
|
||||
_ => res = res && false
|
||||
match self.op.str_to_hex_helper.get(&c) {
|
||||
Some(None) => {
|
||||
res = true;
|
||||
}
|
||||
Some(Some(hex)) => {
|
||||
if !self.compare_nibble(i, &hex) {
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn compare_nibble(&self, pos: usize, nibble: &u8) -> bool{
|
||||
fn compare_nibble(&self, pos: usize, nibble: &u8) -> bool {
|
||||
match pos {
|
||||
0 => *nibble == self.op.n1,
|
||||
1 => *nibble == self.op.n2,
|
||||
2 => *nibble == self.op.n3,
|
||||
3 => *nibble == self.op.n4,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() {
|
||||
let mut cpu = CPU::init();
|
||||
cpu.ram.init_fonts();
|
||||
load_rom("src/chip_8/roms/Trip8 Demo (2008) [Revival Studios].ch8", &mut cpu);
|
||||
|
||||
cpu.ram.init_fonts(); //TODO: load in the RAM
|
||||
cpu.clock.clock_hz = 60.;
|
||||
load_rom("src/chip_8/roms/CAVE.ch8", &mut cpu);
|
||||
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
let mut display = crate::chip_8::display::Display::init(&sdl_context, DISPLAY_SCALE);
|
||||
let mut event_listener = sdl_context.event_pump().unwrap();
|
||||
cpu.clock.clock_hz = 60;
|
||||
|
||||
'runner: loop {
|
||||
for event in event_listener.poll_iter() {
|
||||
match event {
|
||||
sdl2::event::Event::Quit {..} => break 'runner,
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::Escape), .. } => {break 'runner},
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::RightBracket), .. } => {
|
||||
println!("Increasing cpu clock from {} Hz to {} Hz", cpu.clock.clock_hz, cpu.clock.clock_hz + 10);
|
||||
cpu.clock.clock_hz += 10;
|
||||
},
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::LeftBracket), .. } => {
|
||||
println!("Decreasing cpu clock from {} Hz to {} Hz", cpu.clock.clock_hz, cpu.clock.clock_hz - 10);
|
||||
cpu.clock.clock_hz -= 10;
|
||||
},
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::Backspace), .. } => {
|
||||
sdl2::event::Event::Quit { .. } => break 'runner,
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::Escape),
|
||||
..
|
||||
} => break 'runner,
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::RightBracket),
|
||||
..
|
||||
} => {
|
||||
println!(
|
||||
"Increasing cpu clock from {:5} Hz to {:5} Hz",
|
||||
cpu.clock.clock_hz,
|
||||
cpu.clock.clock_hz + 10.
|
||||
);
|
||||
cpu.clock.clock_hz += 10.;
|
||||
}
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::LeftBracket),
|
||||
..
|
||||
} => {
|
||||
println!(
|
||||
"Decreasing cpu clock from {:5} Hz to {:5} Hz",
|
||||
cpu.clock.clock_hz,
|
||||
cpu.clock.clock_hz - 10.
|
||||
);
|
||||
cpu.clock.clock_hz -= 10.;
|
||||
}
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(sdl2::keyboard::Keycode::Backspace),
|
||||
..
|
||||
} => {
|
||||
cpu.pc.0 = 0x200;
|
||||
},
|
||||
sdl2::event::Event::KeyDown { keycode: Some(keycode), ..} => {
|
||||
}
|
||||
sdl2::event::Event::KeyDown {
|
||||
keycode: Some(keycode),
|
||||
..
|
||||
} => {
|
||||
if let Some(key_index) = cpu.keypad.compute_keycode(keycode) {
|
||||
cpu.keypad.press(key_index);
|
||||
}
|
||||
},
|
||||
sdl2::event::Event::KeyUp { keycode: Some(keycode), ..} => {
|
||||
}
|
||||
sdl2::event::Event::KeyUp {
|
||||
keycode: Some(keycode),
|
||||
..
|
||||
} => {
|
||||
if let Some(key_index) = cpu.keypad.compute_keycode(keycode) {
|
||||
cpu.keypad.release(key_index);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -508,12 +690,12 @@ fn op_8xy5(cpu: &mut CPU) {
|
|||
let vx = cpu.registers.get(cpu.op.x);
|
||||
let vy = cpu.registers.get(cpu.op.y);
|
||||
cpu.registers.set(cpu.op.x, vx.wrapping_sub(vy));
|
||||
cpu.registers.x_f = if vx > vy {1} else {0};
|
||||
cpu.registers.x_f = if vx > vy { 1 } else { 0 };
|
||||
}
|
||||
|
||||
fn op_8xy6(cpu: &mut CPU) {
|
||||
let vy = cpu.registers.get(cpu.op.x);
|
||||
let vx = cpu.registers.get(cpu.op.y);
|
||||
let vx = cpu.registers.get(cpu.op.x);
|
||||
let vy = cpu.registers.get(cpu.op.y);
|
||||
cpu.registers.set(cpu.op.x, vy >> 1);
|
||||
cpu.registers.x_f = vx & 0x1;
|
||||
}
|
||||
|
@ -522,7 +704,7 @@ fn op_8xy7(cpu: &mut CPU) {
|
|||
let vx = cpu.registers.get(cpu.op.x);
|
||||
let vy = cpu.registers.get(cpu.op.y);
|
||||
cpu.registers.set(cpu.op.x, vy.wrapping_sub(vx));
|
||||
cpu.registers.x_f = if vy > vx {1} else {0};
|
||||
cpu.registers.x_f = if vy > vx { 1 } else { 0 };
|
||||
}
|
||||
|
||||
fn op_8xye(cpu: &mut CPU) {
|
||||
|
@ -530,7 +712,6 @@ fn op_8xye(cpu: &mut CPU) {
|
|||
let vy = cpu.registers.get(cpu.op.y);
|
||||
cpu.registers.set(cpu.op.x, vy << 1);
|
||||
cpu.registers.x_f = (vx & 0x80) >> 7;
|
||||
|
||||
}
|
||||
|
||||
fn op_annn(cpu: &mut CPU) {
|
||||
|
@ -543,7 +724,8 @@ fn op_bnnn(cpu: &mut CPU) {
|
|||
|
||||
fn op_cxnn(cpu: &mut CPU) {
|
||||
let mut rng = rand::thread_rng();
|
||||
cpu.registers.set(cpu.op.x, rng.gen_range(0x0..0xFF) & cpu.op.nn);
|
||||
cpu.registers
|
||||
.set(cpu.op.x, rng.gen_range(0x0..0xFF) & cpu.op.nn);
|
||||
}
|
||||
|
||||
fn op_dxyn(cpu: &mut CPU) {
|
||||
|
@ -571,7 +753,7 @@ fn op_dxyn(cpu: &mut CPU) {
|
|||
vf = (memory_pixel && display_pixel) || vf;
|
||||
}
|
||||
}
|
||||
cpu.registers.x_f = if vf {1} else {0};
|
||||
cpu.registers.x_f = if vf { 1 } else { 0 };
|
||||
}
|
||||
|
||||
fn op_ex9e(cpu: &mut CPU) {
|
||||
|
@ -604,14 +786,18 @@ fn op_fx1e(cpu: &mut CPU) {
|
|||
|
||||
fn op_fx0a(cpu: &mut CPU) {
|
||||
match cpu.keypad.being_pressed() {
|
||||
Some(key) => { cpu.registers.set(cpu.op.x, key); },
|
||||
_ => { cpu.pc.decrement(); }
|
||||
Some(key) => {
|
||||
cpu.registers.set(cpu.op.x, key);
|
||||
}
|
||||
_ => {
|
||||
cpu.pc.decrement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn op_fx29(cpu: &mut CPU) {
|
||||
let char = (cpu.registers.get(cpu.op.x) & 0xF) as usize;
|
||||
cpu.i = 0x50 + char * 5;
|
||||
cpu.i = cpu.ram.font_address + char * 5;
|
||||
}
|
||||
|
||||
fn op_fx33(cpu: &mut CPU) {
|
||||
|
@ -633,4 +819,4 @@ fn op_fx65(cpu: &mut CPU) {
|
|||
for regs in 0x0..(cpu.op.x + 1) {
|
||||
cpu.registers.set(regs, cpu.ram.read8(i + regs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -5,15 +5,15 @@ pub struct Display {
|
|||
canvas: sdl2::render::Canvas<sdl2::video::Window>,
|
||||
scale: u32,
|
||||
off_color: sdl2::pixels::Color,
|
||||
on_color: sdl2::pixels::Color
|
||||
on_color: sdl2::pixels::Color,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn init(sdl_context: &sdl2::Sdl, scale: u32) -> Display {
|
||||
let video_subsystem = sdl_context.video().unwrap();
|
||||
|
||||
let window = video_subsystem.window("Chip-8", WIDTH as u32 * scale,
|
||||
HEIGHT as u32 * scale)
|
||||
|
||||
let window = video_subsystem
|
||||
.window("Chip-8", WIDTH as u32 * scale, HEIGHT as u32 * scale)
|
||||
.position_centered()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
@ -23,8 +23,8 @@ impl Display {
|
|||
Display {
|
||||
canvas: canvas,
|
||||
scale: scale,
|
||||
off_color: sdl2::pixels::Color::RGB(0, 0, 0),
|
||||
on_color: sdl2::pixels::Color::RGB(255, 255, 255)
|
||||
off_color: sdl2::pixels::Color::RGB(125, 23, 123),
|
||||
on_color: sdl2::pixels::Color::RGB(180, 180, 255),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,8 @@ impl Display {
|
|||
let y = (y as u32 * self.scale) as i32;
|
||||
let width = self.scale;
|
||||
let height = self.scale;
|
||||
self.canvas.fill_rect(sdl2::rect::Rect::new(x, y, width, height))
|
||||
self.canvas
|
||||
.fill_rect(sdl2::rect::Rect::new(x, y, width, height))
|
||||
.expect("Failed to draw pixel");
|
||||
}
|
||||
}
|
||||
|
@ -48,4 +49,4 @@ impl Display {
|
|||
|
||||
self.canvas.present();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
pub mod chip_8_base_interpreter;
|
||||
pub mod cosmac_vip_interpreter;
|
||||
pub mod display;
|
||||
pub mod super_chip_interpreter;
|
||||
pub mod display;
|
|
@ -0,0 +1 @@
|
|||
|
Loading…
Reference in New Issue