mirror of https://github.com/Ivsucram/ivsemu.git
Function refactor 2
Code functions, words and overall organization was refactored
This commit is contained in:
parent
5c90a93239
commit
3d694139f1
|
@ -10,35 +10,26 @@ const DISPLAY_HEIGHT: usize = 32;
|
||||||
const DISPLAY_SCALE: u32 = 10;
|
const DISPLAY_SCALE: u32 = 10;
|
||||||
|
|
||||||
pub struct ProgramCounter(usize);
|
pub struct ProgramCounter(usize);
|
||||||
|
pub struct Ram([u8; 4 * 1024]);
|
||||||
|
pub struct DisplayBuffer([[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH]);
|
||||||
pub struct Registers{
|
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_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
|
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([u8; 4 * 1024]);
|
pub struct Clock{
|
||||||
pub struct DisplayBuffer([[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH]);
|
|
||||||
|
|
||||||
pub struct Timer{
|
|
||||||
tick: u8,
|
tick: u8,
|
||||||
clock_hz: u128,
|
clock_hz: u128,
|
||||||
elapsed: std::time::SystemTime
|
elapsed: std::time::SystemTime
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Keypad {
|
pub struct Keypad {
|
||||||
key_status: [bool; 0x10],
|
key_status: [bool; 0x10],
|
||||||
keys: std::collections::HashMap<sdl2::keyboard::Keycode, usize>
|
keys: std::collections::HashMap<sdl2::keyboard::Keycode, usize>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OpCodes {
|
pub struct OpCodes {
|
||||||
opcode: u16,
|
opcode: u16,
|
||||||
n1: u8,
|
n1: u8, n2: u8, n3: u8, n4: u8,
|
||||||
n2: u8,
|
x: usize, y: usize,
|
||||||
n3: u8,
|
n: u8, nn: u8, nnn: usize
|
||||||
n4: u8,
|
|
||||||
x: usize,
|
|
||||||
y: usize,
|
|
||||||
n: u8,
|
|
||||||
nn: u8,
|
|
||||||
nnn: usize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgramCounter {
|
impl ProgramCounter {
|
||||||
|
@ -48,21 +39,13 @@ impl ProgramCounter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increase(&mut self) {
|
fn increment(&mut self) {
|
||||||
self.0 += 2;
|
self.0 += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrement(&mut self) {
|
fn decrement(&mut self) {
|
||||||
self.0 -= 2;
|
self.0 -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, value: usize) {
|
|
||||||
self.0 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self) -> usize {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registers {
|
impl Registers {
|
||||||
|
@ -128,7 +111,7 @@ impl Ram {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_rom(&mut self, rom: &[u8] ) {
|
fn load_rom(&mut self, rom: &[u8] ) {
|
||||||
assert!(rom.len() <= self.0.len() - 0x200);
|
assert!(rom.len() <= self.0.len() - 0x200, "ROM is bigger than Chip-8 RAM");
|
||||||
for i in 0..rom.len() {
|
for i in 0..rom.len() {
|
||||||
self.0[0x200 + i] = rom[i];
|
self.0[0x200 + i] = rom[i];
|
||||||
}
|
}
|
||||||
|
@ -141,22 +124,18 @@ impl Ram {
|
||||||
|
|
||||||
fn read16(&self, addr: usize) -> u16 {
|
fn read16(&self, addr: usize) -> u16 {
|
||||||
assert!(addr < self.0.len(), "addr = {}, self.0.len() = {}", addr, self.0.len());
|
assert!(addr < self.0.len(), "addr = {}, self.0.len() = {}", addr, self.0.len());
|
||||||
// byteorder::LittleEndian::read_u16(&self.0[addr]);
|
|
||||||
|
|
||||||
// u16::from_le_bytes(self.ram[addr..addr+2])
|
|
||||||
// self.ram[addr..addr+2]
|
|
||||||
(self.0[addr] as u16) << 8 | self.0[addr+1] as u16
|
(self.0[addr] as u16) << 8 | self.0[addr+1] as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write8(&mut self, addr: usize, value: u8) {
|
fn write(&mut self, addr: usize, value: u8) {
|
||||||
assert!(addr < self.0.len());
|
assert!(addr < self.0.len());
|
||||||
self.0[addr] = value;
|
self.0[addr] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Clock {
|
||||||
fn init() -> Timer {
|
fn init() -> Clock {
|
||||||
Timer {
|
Clock {
|
||||||
tick: 255,
|
tick: 255,
|
||||||
clock_hz: 60,
|
clock_hz: 60,
|
||||||
elapsed: std::time::SystemTime::now()
|
elapsed: std::time::SystemTime::now()
|
||||||
|
@ -261,51 +240,45 @@ impl OpCodes {
|
||||||
|
|
||||||
OpCodes {
|
OpCodes {
|
||||||
opcode: opcode,
|
opcode: opcode,
|
||||||
n1: n1 as u8,
|
n1: n1 as u8, n2: n2 as u8, n3: n3 as u8, n4: n4 as u8,
|
||||||
n2: n2 as u8,
|
x: n2 as usize, y: n3 as usize,
|
||||||
n3: n3 as u8,
|
n: n4 as u8, nn: nn as u8, nnn: nnn as usize
|
||||||
n4: n4 as u8,
|
|
||||||
x: n2 as usize,
|
|
||||||
y: n3 as usize,
|
|
||||||
n: n4 as u8,
|
|
||||||
nn: nn as u8,
|
|
||||||
nnn: nnn as usize
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CPU {
|
struct CPU {
|
||||||
pc: ProgramCounter,
|
pc: ProgramCounter, // Program Counter
|
||||||
index_register: usize,
|
i: usize, // Index Register
|
||||||
stack: Vec<usize>,
|
stack: Vec<usize>, // Function Stack
|
||||||
delay_timer: Timer,
|
dt: Clock, // Delay Timer
|
||||||
sound_timer: Timer,
|
st: Clock, // Sound Timer
|
||||||
clock: Timer,
|
clock: Clock, // CPU Clock
|
||||||
registers: Registers,
|
registers: Registers, // Registers
|
||||||
ram: Ram,
|
ram: Ram, // RAM
|
||||||
keypad: Keypad,
|
keypad: Keypad, // Keypad
|
||||||
display_buffer: DisplayBuffer,
|
db: DisplayBuffer, // Display Buffer
|
||||||
opcode: OpCodes,
|
op: OpCodes, // Operation Code
|
||||||
|
|
||||||
str_to_hex_map: std::collections::HashMap<char, Option<u8>>
|
str_to_hex_helper: std::collections::HashMap<char, Option<u8>> // Helper
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CPU {
|
impl CPU {
|
||||||
fn init() -> CPU {
|
fn init() -> CPU {
|
||||||
CPU {
|
CPU {
|
||||||
pc: ProgramCounter::init(),
|
pc: ProgramCounter::init(),
|
||||||
index_register: 0,
|
i: 0,
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
delay_timer: Timer::init(),
|
dt: Clock::init(),
|
||||||
sound_timer: Timer::init(),
|
st: Clock::init(),
|
||||||
clock: Timer::init(),
|
clock: Clock::init(),
|
||||||
registers: Registers::init(),
|
registers: Registers::init(),
|
||||||
ram: Ram::init(),
|
ram: Ram::init(),
|
||||||
keypad: Keypad::init(),
|
keypad: Keypad::init(),
|
||||||
display_buffer: DisplayBuffer::init(),
|
db: DisplayBuffer::init(),
|
||||||
opcode: OpCodes::init(0000),
|
op: OpCodes::init(0000),
|
||||||
|
|
||||||
str_to_hex_map: [('0', Some(0x0)), ('1', Some(0x1)), ('2', Some(0x2)), ('3', Some(0x3)),
|
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)),
|
('4', Some(0x4)), ('5', Some(0x5)), ('6', Some(0x6)), ('7', Some(0x7)),
|
||||||
('8', Some(0x8)), ('9', Some(0x9)), ('A', Some(0xA)), ('B', Some(0xB)),
|
('8', Some(0x8)), ('9', Some(0x9)), ('A', Some(0xA)), ('B', Some(0xB)),
|
||||||
('C', Some(0xC)), ('D', Some(0xD)), ('E', Some(0xE)), ('F', Some(0xF)),
|
('C', Some(0xC)), ('D', Some(0xD)), ('E', Some(0xE)), ('F', Some(0xF)),
|
||||||
|
@ -314,11 +287,12 @@ impl CPU {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(&mut self) {
|
fn fetch(&mut self) {
|
||||||
self.opcode = OpCodes::init(self.ram.read16(self.pc.get()));
|
self.op = OpCodes::init(self.ram.read16(self.pc.0));
|
||||||
self.pc.increase();
|
self.pc.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self) {
|
fn decode(&mut self) {
|
||||||
|
//TODO: function pointers
|
||||||
if self.decode_match("00E0") { op_00e0(self);
|
if self.decode_match("00E0") { op_00e0(self);
|
||||||
} else if self.decode_match("1???") { op_1nnn(self);
|
} else if self.decode_match("1???") { op_1nnn(self);
|
||||||
} else if self.decode_match("00EE") { op_00ee(self);
|
} else if self.decode_match("00EE") { op_00ee(self);
|
||||||
|
@ -354,14 +328,14 @@ impl CPU {
|
||||||
} else if self.decode_match("F?55") { op_fx55(self);
|
} else if self.decode_match("F?55") { op_fx55(self);
|
||||||
} else if self.decode_match("F?65") { op_fx65(self);
|
} else if self.decode_match("F?65") { op_fx65(self);
|
||||||
} else {
|
} else {
|
||||||
println!{"Unknown instruction: {:04x}", self.opcode.opcode};
|
println!{"Unknown instruction: {:04x}", self.op.opcode};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_match(&self, hex_code: &str) -> bool {
|
fn decode_match(&self, hex_code: &str) -> bool {
|
||||||
let mut res: bool = true;
|
let mut res: bool = true;
|
||||||
for (i, c) in hex_code.chars().enumerate() {
|
for (i, c) in hex_code.chars().enumerate() {
|
||||||
match self.str_to_hex_map.get(&c) {
|
match self.str_to_hex_helper.get(&c) {
|
||||||
Some(Some(hex)) => res = res && self.compare_nibble(i, &hex),
|
Some(Some(hex)) => res = res && self.compare_nibble(i, &hex),
|
||||||
Some(None) => res = res && true,
|
Some(None) => res = res && true,
|
||||||
_ => res = res && false
|
_ => res = res && false
|
||||||
|
@ -372,10 +346,10 @@ impl CPU {
|
||||||
|
|
||||||
fn compare_nibble(&self, pos: usize, nibble: &u8) -> bool{
|
fn compare_nibble(&self, pos: usize, nibble: &u8) -> bool{
|
||||||
match pos {
|
match pos {
|
||||||
0 => *nibble == self.opcode.n1,
|
0 => *nibble == self.op.n1,
|
||||||
1 => *nibble == self.opcode.n2,
|
1 => *nibble == self.op.n2,
|
||||||
2 => *nibble == self.opcode.n3,
|
2 => *nibble == self.op.n3,
|
||||||
3 => *nibble == self.opcode.n4,
|
3 => *nibble == self.op.n4,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -384,24 +358,7 @@ impl CPU {
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let mut cpu = CPU::init();
|
let mut cpu = CPU::init();
|
||||||
cpu.ram.init_fonts();
|
cpu.ram.init_fonts();
|
||||||
// load_rom("src/chip_8/roms/ibm_logo.ch8", &mut cpu);
|
load_rom("src/chip_8/roms/Trip8 Demo (2008) [Revival Studios].ch8", &mut cpu);
|
||||||
// load_rom("src/chip_8/roms/BC_test.ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/Keypad_Test_Hap_2006.ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/Trip8 Demo (2008) [Revival Studios].ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/Zero Demo [zeroZshadow, 2007].ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/Particle Demo [zeroZshadow, 2008].ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/Sierpinski [Sergey Naydenov, 2010].ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/Chip8 emulator Logo [Garstyciuks].ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/Stars [Sergey Naydenov, 2010].ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/test_opcode.ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/HIDDEN.ch8", &mut cpu); // Good to test keyboard
|
|
||||||
load_rom("src/chip_8/roms/CAVE.ch8", &mut cpu); // Good to test keyboard
|
|
||||||
// load_rom("src/chip_8/roms/TRON.ch8", &mut cpu); // Good to test keyboard
|
|
||||||
// load_rom("src/chip_8/roms/PUZZLE.ch8", &mut cpu); // Good to test keyboard?
|
|
||||||
// load_rom("src/chip_8/roms/TETRIS.ch8", &mut cpu); // Good to test keyboard?
|
|
||||||
// load_rom("src/chip_8/roms/delay_timer_test.ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/random_number_test.ch8", &mut cpu);
|
|
||||||
// load_rom("src/chip_8/roms/SNAKE.ch8", &mut cpu);
|
|
||||||
|
|
||||||
let sdl_context = sdl2::init().unwrap();
|
let sdl_context = sdl2::init().unwrap();
|
||||||
let mut display = crate::chip_8::display::Display::init(&sdl_context, DISPLAY_SCALE);
|
let mut display = crate::chip_8::display::Display::init(&sdl_context, DISPLAY_SCALE);
|
||||||
|
@ -426,7 +383,7 @@ pub fn run() {
|
||||||
},
|
},
|
||||||
sdl2::event::Event::KeyDown {
|
sdl2::event::Event::KeyDown {
|
||||||
keycode: Some(sdl2::keyboard::Keycode::Backspace), .. } => {
|
keycode: Some(sdl2::keyboard::Keycode::Backspace), .. } => {
|
||||||
cpu.pc.set(0x200);
|
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) {
|
if let Some(key_index) = cpu.keypad.compute_keycode(keycode) {
|
||||||
|
@ -442,13 +399,13 @@ pub fn run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu.delay_timer.tick();
|
cpu.dt.tick();
|
||||||
cpu.sound_timer.tick();
|
cpu.st.tick();
|
||||||
if cpu.clock.tick() {
|
if cpu.clock.tick() {
|
||||||
cpu.fetch();
|
cpu.fetch();
|
||||||
cpu.decode();
|
cpu.decode();
|
||||||
if cpu.decode_match("D???") {
|
if cpu.decode_match("D???") {
|
||||||
display.draw(&cpu.display_buffer.0)
|
display.draw(&cpu.db.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,140 +419,138 @@ fn load_rom(filename: &str, cpu: &mut CPU) {
|
||||||
cpu.ram.load_rom(&buffer);
|
cpu.ram.load_rom(&buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn op_0NNN() {}//ignore
|
|
||||||
|
|
||||||
fn op_00e0(cpu: &mut CPU) {
|
fn op_00e0(cpu: &mut CPU) {
|
||||||
cpu.display_buffer.clear();
|
cpu.db.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_1nnn(cpu: &mut CPU) {
|
fn op_1nnn(cpu: &mut CPU) {
|
||||||
cpu.pc.set(cpu.opcode.nnn);
|
cpu.pc.0 = cpu.op.nnn;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_00ee(cpu: &mut CPU) {
|
fn op_00ee(cpu: &mut CPU) {
|
||||||
let value = cpu.stack.pop();
|
let value = cpu.stack.pop();
|
||||||
match value {
|
match value {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
cpu.pc.set(value);
|
cpu.pc.0 = value;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_2nnn(cpu: &mut CPU) {
|
fn op_2nnn(cpu: &mut CPU) {
|
||||||
cpu.stack.push(cpu.pc.get());
|
cpu.stack.push(cpu.pc.0);
|
||||||
cpu.pc.set(cpu.opcode.nnn);
|
cpu.pc.0 = cpu.op.nnn;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_3xnn(cpu: &mut CPU) {
|
fn op_3xnn(cpu: &mut CPU) {
|
||||||
if cpu.registers.get(cpu.opcode.x) == cpu.opcode.nn {
|
if cpu.registers.get(cpu.op.x) == cpu.op.nn {
|
||||||
cpu.pc.increase();
|
cpu.pc.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_4xnn(cpu: &mut CPU) {
|
fn op_4xnn(cpu: &mut CPU) {
|
||||||
if cpu.registers.get(cpu.opcode.x) != cpu.opcode.nn {
|
if cpu.registers.get(cpu.op.x) != cpu.op.nn {
|
||||||
cpu.pc.increase();
|
cpu.pc.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_5xy0(cpu: &mut CPU) {
|
fn op_5xy0(cpu: &mut CPU) {
|
||||||
if cpu.registers.get(cpu.opcode.x) == cpu.registers.get(cpu.opcode.y) {
|
if cpu.registers.get(cpu.op.x) == cpu.registers.get(cpu.op.y) {
|
||||||
cpu.pc.increase();
|
cpu.pc.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_9xy0(cpu: &mut CPU) {
|
fn op_9xy0(cpu: &mut CPU) {
|
||||||
if cpu.registers.get(cpu.opcode.x) != cpu.registers.get(cpu.opcode.y) {
|
if cpu.registers.get(cpu.op.x) != cpu.registers.get(cpu.op.y) {
|
||||||
cpu.pc.increase();
|
cpu.pc.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_6xnn(cpu: &mut CPU) {
|
fn op_6xnn(cpu: &mut CPU) {
|
||||||
cpu.registers.set(cpu.opcode.x, cpu.opcode.nn);
|
cpu.registers.set(cpu.op.x, cpu.op.nn);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_7xnn(cpu: &mut CPU) {
|
fn op_7xnn(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
cpu.registers.set(cpu.opcode.x, cpu.opcode.nn.wrapping_add(vx));
|
cpu.registers.set(cpu.op.x, cpu.op.nn.wrapping_add(vx));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_8xy0(cpu: &mut CPU) {
|
fn op_8xy0(cpu: &mut CPU) {
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vy);
|
cpu.registers.set(cpu.op.x, vy);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_8xy1(cpu: &mut CPU) {
|
fn op_8xy1(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vx | vy);
|
cpu.registers.set(cpu.op.x, vx | vy);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_8xy2(cpu: &mut CPU) {
|
fn op_8xy2(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vx & vy);
|
cpu.registers.set(cpu.op.x, vx & vy);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_8xy3(cpu: &mut CPU) {
|
fn op_8xy3(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vx ^ vy);
|
cpu.registers.set(cpu.op.x, vx ^ vy);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_8xy4(cpu: &mut CPU) {
|
fn op_8xy4(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vx.wrapping_add(vy));
|
cpu.registers.set(cpu.op.x, vx.wrapping_add(vy));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_8xy5(cpu: &mut CPU) {
|
fn op_8xy5(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vx.wrapping_sub(vy));
|
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) {
|
fn op_8xy6(cpu: &mut CPU) {
|
||||||
let vy = cpu.registers.get(cpu.opcode.x);
|
let vy = cpu.registers.get(cpu.op.x);
|
||||||
let vx = cpu.registers.get(cpu.opcode.y);
|
let vx = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vy >> 1);
|
cpu.registers.set(cpu.op.x, vy >> 1);
|
||||||
cpu.registers.x_f = vx & 0x1;
|
cpu.registers.x_f = vx & 0x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_8xy7(cpu: &mut CPU) {
|
fn op_8xy7(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vy.wrapping_sub(vx));
|
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) {
|
fn op_8xye(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
let vy = cpu.registers.get(cpu.opcode.y);
|
let vy = cpu.registers.get(cpu.op.y);
|
||||||
cpu.registers.set(cpu.opcode.x, vy << 1);
|
cpu.registers.set(cpu.op.x, vy << 1);
|
||||||
cpu.registers.x_f = (vx & 0x80) >> 7;
|
cpu.registers.x_f = (vx & 0x80) >> 7;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_annn(cpu: &mut CPU) {
|
fn op_annn(cpu: &mut CPU) {
|
||||||
cpu.index_register = cpu.opcode.nnn;
|
cpu.i = cpu.op.nnn;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_bnnn(cpu: &mut CPU) {
|
fn op_bnnn(cpu: &mut CPU) {
|
||||||
cpu.pc.set(cpu.opcode.nnn + cpu.registers.x_0 as usize);
|
cpu.pc.0 = cpu.op.nnn + cpu.registers.x_0 as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_cxnn(cpu: &mut CPU) {
|
fn op_cxnn(cpu: &mut CPU) {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
cpu.registers.set(cpu.opcode.x, rng.gen_range(0x0..0xFF) & cpu.opcode.nn);
|
cpu.registers.set(cpu.op.x, rng.gen_range(0x0..0xFF) & cpu.op.nn);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_dxyn(cpu: &mut CPU) {
|
fn op_dxyn(cpu: &mut CPU) {
|
||||||
let mut vf: bool = false;
|
let mut vf: bool = false;
|
||||||
let value = cpu.opcode.n as usize;
|
let value = cpu.op.n as usize;
|
||||||
let ori_x = cpu.registers.get(cpu.opcode.x) as usize % DISPLAY_WIDTH;
|
let ori_x = cpu.registers.get(cpu.op.x) as usize % DISPLAY_WIDTH;
|
||||||
let ori_y = cpu.registers.get(cpu.opcode.y) as usize % DISPLAY_HEIGHT;
|
let ori_y = cpu.registers.get(cpu.op.y) as usize % DISPLAY_HEIGHT;
|
||||||
|
|
||||||
for row in 0..value {
|
for row in 0..value {
|
||||||
let y = ori_y + row;
|
let y = ori_y + row;
|
||||||
|
@ -603,7 +558,7 @@ fn op_dxyn(cpu: &mut CPU) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sprite = cpu.ram.read8(cpu.index_register + row);
|
let sprite = cpu.ram.read8(cpu.i + row);
|
||||||
for pixel_position in 0..8 {
|
for pixel_position in 0..8 {
|
||||||
let x = ori_x + pixel_position;
|
let x = ori_x + pixel_position;
|
||||||
if x >= DISPLAY_WIDTH {
|
if x >= DISPLAY_WIDTH {
|
||||||
|
@ -611,8 +566,8 @@ fn op_dxyn(cpu: &mut CPU) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0;
|
let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0;
|
||||||
let display_pixel: bool = cpu.display_buffer.0[x][y];
|
let display_pixel: bool = cpu.db.0[x][y];
|
||||||
cpu.display_buffer.0[x][y] = memory_pixel ^ display_pixel;
|
cpu.db.0[x][y] = memory_pixel ^ display_pixel;
|
||||||
vf = (memory_pixel && display_pixel) || vf;
|
vf = (memory_pixel && display_pixel) || vf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -620,62 +575,62 @@ fn op_dxyn(cpu: &mut CPU) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_ex9e(cpu: &mut CPU) {
|
fn op_ex9e(cpu: &mut CPU) {
|
||||||
if cpu.keypad.get(cpu.registers.get(cpu.opcode.x) as usize) {
|
if cpu.keypad.get(cpu.registers.get(cpu.op.x) as usize) {
|
||||||
cpu.pc.increase();
|
cpu.pc.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_exa1(cpu: &mut CPU) {
|
fn op_exa1(cpu: &mut CPU) {
|
||||||
if !cpu.keypad.get(cpu.registers.get(cpu.opcode.x) as usize) {
|
if !cpu.keypad.get(cpu.registers.get(cpu.op.x) as usize) {
|
||||||
cpu.pc.increase();
|
cpu.pc.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx07(cpu: &mut CPU) {
|
fn op_fx07(cpu: &mut CPU) {
|
||||||
cpu.registers.set(cpu.opcode.x, cpu.delay_timer.tick);
|
cpu.registers.set(cpu.op.x, cpu.dt.tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx15(cpu: &mut CPU) {
|
fn op_fx15(cpu: &mut CPU) {
|
||||||
cpu.delay_timer.tick = cpu.registers.get(cpu.opcode.x);
|
cpu.dt.tick = cpu.registers.get(cpu.op.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx18(cpu: &mut CPU) {
|
fn op_fx18(cpu: &mut CPU) {
|
||||||
cpu.sound_timer.tick = cpu.registers.get(cpu.opcode.x);
|
cpu.st.tick = cpu.registers.get(cpu.op.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx1e(cpu: &mut CPU) {
|
fn op_fx1e(cpu: &mut CPU) {
|
||||||
cpu.index_register += cpu.registers.get(cpu.opcode.x) as usize;
|
cpu.i += cpu.registers.get(cpu.op.x) as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx0a(cpu: &mut CPU) {
|
fn op_fx0a(cpu: &mut CPU) {
|
||||||
match cpu.keypad.being_pressed() {
|
match cpu.keypad.being_pressed() {
|
||||||
Some(key) => { cpu.registers.set(cpu.opcode.x, key); },
|
Some(key) => { cpu.registers.set(cpu.op.x, key); },
|
||||||
_ => { cpu.pc.decrement(); }
|
_ => { cpu.pc.decrement(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx29(cpu: &mut CPU) {
|
fn op_fx29(cpu: &mut CPU) {
|
||||||
let char = (cpu.registers.get(cpu.opcode.x) & 0xF) as usize;
|
let char = (cpu.registers.get(cpu.op.x) & 0xF) as usize;
|
||||||
cpu.index_register = 0x50 + char * 5;
|
cpu.i = 0x50 + char * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx33(cpu: &mut CPU) {
|
fn op_fx33(cpu: &mut CPU) {
|
||||||
let vx = cpu.registers.get(cpu.opcode.x);
|
let vx = cpu.registers.get(cpu.op.x);
|
||||||
cpu.ram.write8(cpu.index_register, vx / 100);
|
cpu.ram.write(cpu.i, vx / 100);
|
||||||
cpu.ram.write8(cpu.index_register + 1, vx / 10 % 10);
|
cpu.ram.write(cpu.i + 1, vx / 10 % 10);
|
||||||
cpu.ram.write8(cpu.index_register + 2, vx % 10);
|
cpu.ram.write(cpu.i + 2, vx % 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx55(cpu: &mut CPU) {
|
fn op_fx55(cpu: &mut CPU) {
|
||||||
let i = cpu.index_register;
|
let i = cpu.i;
|
||||||
for regs in 0x0..(cpu.opcode.x + 1) {
|
for regs in 0x0..(cpu.op.x + 1) {
|
||||||
cpu.ram.write8(i + regs, cpu.registers.get(regs));
|
cpu.ram.write(i + regs, cpu.registers.get(regs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_fx65(cpu: &mut CPU) {
|
fn op_fx65(cpu: &mut CPU) {
|
||||||
let i = cpu.index_register;
|
let i = cpu.i;
|
||||||
for regs in 0x0..(cpu.opcode.x + 1) {
|
for regs in 0x0..(cpu.op.x + 1) {
|
||||||
cpu.registers.set(regs, cpu.ram.read8(i + regs));
|
cpu.registers.set(regs, cpu.ram.read8(i + regs));
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue