refactor: use mod for machine
This commit is contained in:
parent
c63224b90e
commit
d92bd30587
2 changed files with 432 additions and 385 deletions
337
src/machine.rs
Normal file
337
src/machine.rs
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
/*
|
||||||
|
* Chip8 emulator
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 rick G. <rick@gnous.eu>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const FONT: [u8; 80] = [
|
||||||
|
0xF0, 0x90, 0x90, 0x90, 0xF0,
|
||||||
|
0x20, 0x60, 0x20, 0x20, 0x70,
|
||||||
|
0xF0, 0x10, 0xF0, 0x80, 0xF0,
|
||||||
|
0xF0, 0x10, 0xF0, 0x10, 0xF0,
|
||||||
|
0x90, 0x90, 0xF0, 0x10, 0x10,
|
||||||
|
0xF0, 0x80, 0xF0, 0x10, 0xF0,
|
||||||
|
0xF0, 0x80, 0xF0, 0x90, 0xF0,
|
||||||
|
0xF0, 0x10, 0x20, 0x40, 0x40,
|
||||||
|
0xF0, 0x90, 0xF0, 0x90, 0xF0,
|
||||||
|
0xF0, 0x90, 0xF0, 0x10, 0xF0,
|
||||||
|
0xF0, 0x90, 0xF0, 0x90, 0x90,
|
||||||
|
0xE0, 0x90, 0xE0, 0x90, 0xE0,
|
||||||
|
0xF0, 0x80, 0x80, 0x80, 0xF0,
|
||||||
|
0xE0, 0x90, 0x90, 0x90, 0xE0,
|
||||||
|
0xF0, 0x80, 0xF0, 0x80, 0xF0,
|
||||||
|
0xF0, 0x80, 0xF0, 0x80, 0x80
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const HEIGHT: usize = 32;
|
||||||
|
pub const WIDTH: usize = 64;
|
||||||
|
|
||||||
|
extern crate sdl2;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
pub use sdl2::pixels::Color;
|
||||||
|
pub use sdl2::event::Event;
|
||||||
|
pub use sdl2::EventPump;
|
||||||
|
pub use sdl2::keyboard::Keycode;
|
||||||
|
pub use sdl2::video::Window;
|
||||||
|
pub use sdl2::rect::Point;
|
||||||
|
pub use sdl2::render::Canvas;
|
||||||
|
|
||||||
|
pub use std::fs::File;
|
||||||
|
pub use std::path::Path;
|
||||||
|
pub use std::io;
|
||||||
|
pub use std::io::Read;
|
||||||
|
|
||||||
|
pub struct Machine {
|
||||||
|
memory: [u8; 4096],
|
||||||
|
pub key_inputs: [u8; 16],
|
||||||
|
pub display_buffer: [[i32; WIDTH]; HEIGHT],
|
||||||
|
gpio: [u8; 16],
|
||||||
|
index: u16,
|
||||||
|
pc: usize,
|
||||||
|
stack: Vec<u16>,
|
||||||
|
dt: u8,
|
||||||
|
st: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Machine {
|
||||||
|
/// Initialise une machine en mettant tout à 0 (RAM, PC...)
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
memory: [0; 4096],
|
||||||
|
key_inputs: [0; 16],
|
||||||
|
display_buffer: [[0; WIDTH]; HEIGHT],
|
||||||
|
gpio: [0; 16],
|
||||||
|
index: 0,
|
||||||
|
pc: 0,
|
||||||
|
stack: Vec::new(),
|
||||||
|
dt: 0,
|
||||||
|
st: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
for i in 0..FONT.len() {
|
||||||
|
self.memory[i] = FONT[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pc = 0x200;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// charge une ROM en mémoire
|
||||||
|
pub fn load_rom(&mut self, p: &Path) -> io::Result<()> {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let mut f = File::open(p)?;
|
||||||
|
f.read_to_end(&mut buffer)?;
|
||||||
|
|
||||||
|
for i in 0..buffer.len() {
|
||||||
|
self.memory[i + 0x200] = buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self, screen: &mut Canvas<Window>, events: &mut EventPump) {
|
||||||
|
let opcode = ((self.memory[self.pc] as u16) << 8)
|
||||||
|
+ (self.memory[self.pc + 1] as u16);
|
||||||
|
|
||||||
|
let vx: usize = ((opcode & 0x0f00) >> 8) as usize;
|
||||||
|
let vy: usize = ((opcode & 0x00f0) >> 4) as usize;
|
||||||
|
let k: u8 = (opcode & 0x00ff) as u8;
|
||||||
|
|
||||||
|
self.pc += 2;
|
||||||
|
|
||||||
|
if self.dt > 0 {
|
||||||
|
self.dt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.st > 0 {
|
||||||
|
self.st -= 1;
|
||||||
|
if self.st == 0 {
|
||||||
|
println!("BUZZZ!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (opcode & 0xf000) >> 12 {
|
||||||
|
0 => match opcode {
|
||||||
|
0x00E0 => {
|
||||||
|
self.display_buffer = [[0; 64]; 32];
|
||||||
|
screen.set_draw_color(Color::RGB(0, 0, 0));
|
||||||
|
screen.clear();
|
||||||
|
screen.present();
|
||||||
|
},
|
||||||
|
0x00EE => self.pc = self.stack.pop().unwrap() as usize,
|
||||||
|
_ => println!("SYS"),
|
||||||
|
}
|
||||||
|
1 => self.pc = (opcode & 0x0fff) as usize,
|
||||||
|
2 => {
|
||||||
|
self.stack.push(self.pc as u16);
|
||||||
|
self.pc = (opcode & 0x0fff) as usize
|
||||||
|
},
|
||||||
|
3 => if self.gpio[vx] == k as u8 {
|
||||||
|
self.pc += 2;
|
||||||
|
},
|
||||||
|
4 => if self.gpio[vx] != k as u8 {
|
||||||
|
self.pc += 2;
|
||||||
|
},
|
||||||
|
5 => if self.gpio[vx] == self.gpio[vy] {
|
||||||
|
self.pc += 2;
|
||||||
|
}
|
||||||
|
6 => self.gpio[vx] = k,
|
||||||
|
7 => self.gpio[vx] = self.gpio[vx].saturating_add(k),
|
||||||
|
8 => {
|
||||||
|
match opcode & 0x000f {
|
||||||
|
0 => self.gpio[vx] = self.gpio[vy],
|
||||||
|
1 => self.gpio[vx] |= self.gpio[vy],
|
||||||
|
2 => self.gpio[vx] &= self.gpio[vy],
|
||||||
|
3 => self.gpio[vx] ^= self.gpio[vy],
|
||||||
|
4 => {
|
||||||
|
self.gpio[vx] = self.gpio[vx].saturating_add(self.gpio[vy]);
|
||||||
|
let (_, overflow) = self.gpio[vx].overflowing_add(self.gpio[vy]);
|
||||||
|
if overflow {
|
||||||
|
self.gpio[0xf] = 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
5 => {
|
||||||
|
if self.gpio[vx] > self.gpio[vy] {
|
||||||
|
self.gpio[0xf] = 1;
|
||||||
|
} else {
|
||||||
|
self.gpio[0xf] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (t, _) = self.gpio[vx].overflowing_sub(self.gpio[vy]);
|
||||||
|
self.gpio[vx] = t;
|
||||||
|
},
|
||||||
|
6 => {
|
||||||
|
if self.gpio[vx].trailing_ones() > 0 {
|
||||||
|
self.gpio[0xf] = 1;
|
||||||
|
} else {
|
||||||
|
self.gpio[0xf] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.gpio[vx] >>= 1;
|
||||||
|
},
|
||||||
|
7 => {
|
||||||
|
if self.gpio[vx] < self.gpio[vy] {
|
||||||
|
self.gpio[0xf] = 1;
|
||||||
|
} else {
|
||||||
|
self.gpio[0xf] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.gpio[vx] = self.gpio[vy] - self.gpio[vx];
|
||||||
|
},
|
||||||
|
0xE => {
|
||||||
|
if self.gpio[vx].leading_ones() > 0 {
|
||||||
|
self.gpio[0xf] = 1;
|
||||||
|
} else {
|
||||||
|
self.gpio[0xf] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.gpio[vx] <<= 1;
|
||||||
|
},
|
||||||
|
_ => println!("error 8")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
9 => if self.gpio[vx] != self.gpio[vy] {
|
||||||
|
self.pc += 2;
|
||||||
|
},
|
||||||
|
0xA => self.index = opcode & 0x0fff,
|
||||||
|
0xB => self.pc = ((self.gpio[0]) as u16 + (opcode & 0x0fff)) as usize,
|
||||||
|
0xC => self.gpio[vx] = rand::random::<u8>() & k,
|
||||||
|
0xD => {
|
||||||
|
let x = self.gpio[vx] as u16;
|
||||||
|
let y = self.gpio[vy] as u16;
|
||||||
|
for i in 0..(opcode & 0x000f) {
|
||||||
|
//println!("{:?}", self.memory);
|
||||||
|
let mut sprite = self.memory[(self.index + i as u16) as usize];
|
||||||
|
for j in 0..8 {
|
||||||
|
let mut case = 0;
|
||||||
|
if sprite.leading_ones() > 0 { case = 1; }
|
||||||
|
//println!("I :: {}", self.index + i);
|
||||||
|
//println!("D :: {} - {}", sprite, case);
|
||||||
|
sprite = sprite << 1;
|
||||||
|
|
||||||
|
let ty: usize = (i + y) as usize % HEIGHT;
|
||||||
|
let tx: usize = (j + x) as usize % WIDTH;
|
||||||
|
|
||||||
|
let tmp = self.display_buffer[ty][tx];
|
||||||
|
self.display_buffer[ty][tx] ^= case;
|
||||||
|
if self.display_buffer[ty][tx] == 0 && tmp == 1 {
|
||||||
|
self.gpio[0xf] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0xE => {
|
||||||
|
match opcode & 0x00ff {
|
||||||
|
0x9E => {
|
||||||
|
if self.key_inputs[self.gpio[vx] as usize] == 1 {
|
||||||
|
self.pc += 2;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0xA1 => {
|
||||||
|
if self.key_inputs[self.gpio[vx] as usize] == 0 {
|
||||||
|
self.pc += 2;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => println!("error E")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0xF => {
|
||||||
|
match opcode & 0x00ff {
|
||||||
|
0x07 => self.gpio[vx] = self.dt,
|
||||||
|
0x0A => self.check_touch(vx, events),
|
||||||
|
0x15 => self.dt = self.gpio[vx],
|
||||||
|
0x18 => self.st = self.gpio[vx],
|
||||||
|
0x1E => self.index += self.gpio[vx] as u16,
|
||||||
|
0x29 => self.index = (self.gpio[vx] as u16) * 5,
|
||||||
|
0x33 => {
|
||||||
|
self.memory[self.index as usize] = self.gpio[vx] / 100 as u8;
|
||||||
|
self.memory[(self.index + 1) as usize] = (self.gpio[vx] % 100) /10 as u8;
|
||||||
|
self.memory[(self.index + 2) as usize] = self.gpio[vx] % 10 as u8;
|
||||||
|
},
|
||||||
|
0x55 =>
|
||||||
|
{
|
||||||
|
for i in 0..(vx + 1) {
|
||||||
|
self.memory[(self.index as usize) + i] = self.gpio[i];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0x65 => {
|
||||||
|
for i in 0..(vx + 1) {
|
||||||
|
self.gpio[i] = self.memory[(self.index as usize) + i];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => println!("error F")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => println!("error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_touch(&mut self, vx: usize, events: &mut EventPump) {
|
||||||
|
let touch = events.wait_event();
|
||||||
|
match touch {
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num0), .. } => {
|
||||||
|
self.gpio[vx] = 0;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
|
||||||
|
self.gpio[vx] = 1;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num2), .. } => {
|
||||||
|
self.gpio[vx] = 2;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num3), .. } => {
|
||||||
|
self.gpio[vx] = 3;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num4), .. } => {
|
||||||
|
self.gpio[vx] = 4;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num5), .. } => {
|
||||||
|
self.gpio[vx] = 5;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num6), .. } => {
|
||||||
|
self.gpio[vx] = 6;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num7), .. } => {
|
||||||
|
self.gpio[vx] = 7;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num8), .. } => {
|
||||||
|
self.gpio[vx] = 8;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::Num9), .. } => {
|
||||||
|
self.gpio[vx] = 9;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::A), .. } => {
|
||||||
|
self.gpio[vx] = 0xa;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::B), .. } => {
|
||||||
|
self.gpio[vx] = 0xb;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::C), .. } => {
|
||||||
|
self.gpio[vx] = 0xc;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::D), .. } => {
|
||||||
|
self.gpio[vx] = 0xd;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::E), .. } => {
|
||||||
|
self.gpio[vx] = 0xe;
|
||||||
|
},
|
||||||
|
Event::KeyDown { keycode: Some(Keycode::F), .. } => {
|
||||||
|
self.gpio[vx] = 0xf;
|
||||||
|
},
|
||||||
|
_ => self.check_touch(vx, events),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
480
src/main.rs
480
src/main.rs
|
@ -16,407 +16,31 @@
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
mod machine;
|
||||||
extern crate sdl2;
|
extern crate sdl2;
|
||||||
extern crate rand;
|
|
||||||
|
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
use sdl2::EventPump;
|
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::video::Window;
|
|
||||||
use sdl2::rect::Point;
|
use sdl2::rect::Point;
|
||||||
use sdl2::render::Canvas;
|
|
||||||
|
use machine::HEIGHT;
|
||||||
|
use machine::WIDTH;
|
||||||
|
use machine::Machine;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
const FONT: [u8; 80] = [
|
|
||||||
0xF0, 0x90, 0x90, 0x90, 0xF0,
|
|
||||||
0x20, 0x60, 0x20, 0x20, 0x70,
|
|
||||||
0xF0, 0x10, 0xF0, 0x80, 0xF0,
|
|
||||||
0xF0, 0x10, 0xF0, 0x10, 0xF0,
|
|
||||||
0x90, 0x90, 0xF0, 0x10, 0x10,
|
|
||||||
0xF0, 0x80, 0xF0, 0x10, 0xF0,
|
|
||||||
0xF0, 0x80, 0xF0, 0x90, 0xF0,
|
|
||||||
0xF0, 0x10, 0x20, 0x40, 0x40,
|
|
||||||
0xF0, 0x90, 0xF0, 0x90, 0xF0,
|
|
||||||
0xF0, 0x90, 0xF0, 0x10, 0xF0,
|
|
||||||
0xF0, 0x90, 0xF0, 0x90, 0x90,
|
|
||||||
0xE0, 0x90, 0xE0, 0x90, 0xE0,
|
|
||||||
0xF0, 0x80, 0x80, 0x80, 0xF0,
|
|
||||||
0xE0, 0x90, 0x90, 0x90, 0xE0,
|
|
||||||
0xF0, 0x80, 0xF0, 0x80, 0xF0,
|
|
||||||
0xF0, 0x80, 0xF0, 0x80, 0x80
|
|
||||||
];
|
|
||||||
|
|
||||||
const HEIGHT: usize = 32;
|
|
||||||
const WIDTH: usize = 64;
|
|
||||||
|
|
||||||
struct Machine {
|
|
||||||
memory: [u8; 4096],
|
|
||||||
key_inputs: [u8; 16],
|
|
||||||
display_buffer: [[i32; WIDTH]; HEIGHT],
|
|
||||||
gpio: [u8; 16],
|
|
||||||
index: u16,
|
|
||||||
pc: usize,
|
|
||||||
stack: Vec<u16>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
/// Initialise une machine en mettant tout à 0 (RAM, PC...)
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
memory: [0; 4096],
|
|
||||||
key_inputs: [0; 16],
|
|
||||||
display_buffer: [[0; WIDTH]; HEIGHT],
|
|
||||||
gpio: [0; 16],
|
|
||||||
index: 0,
|
|
||||||
pc: 0,
|
|
||||||
stack: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(&mut self) {
|
|
||||||
for i in 0..FONT.len() {
|
|
||||||
self.memory[i] = FONT[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.pc = 0x200;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// charge une ROM en mémoire
|
|
||||||
pub fn load_rom(&mut self, p: &Path) -> io::Result<()> {
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
let mut f = File::open(p)?;
|
|
||||||
f.read_to_end(&mut buffer)?;
|
|
||||||
|
|
||||||
for i in 0..buffer.len() {
|
|
||||||
self.memory[i + 0x200] = buffer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cycle(&mut self, screen: &mut Canvas<Window>, events: &mut EventPump) {
|
|
||||||
let opcode = ((self.memory[self.pc] as u16) << 8)
|
|
||||||
+ (self.memory[self.pc + 1] as u16);
|
|
||||||
|
|
||||||
let vx: usize = ((opcode & 0x0f00) >> 8) as usize;
|
|
||||||
let vy: usize = ((opcode & 0x00f0) >> 4) as usize;
|
|
||||||
let k: u8 = (opcode & 0x00ff) as u8;
|
|
||||||
|
|
||||||
self.pc += 2;
|
|
||||||
|
|
||||||
match (opcode & 0xf000) >> 12 {
|
|
||||||
0 => match opcode {
|
|
||||||
0x00E0 => {
|
|
||||||
self.display_buffer = [[0; 64]; 32];
|
|
||||||
screen.set_draw_color(Color::RGB(0, 0, 0));
|
|
||||||
screen.clear();
|
|
||||||
screen.present();
|
|
||||||
},
|
|
||||||
0x00EE => self.pc = self.stack.pop().unwrap() as usize,
|
|
||||||
_ => println!("SYS"),
|
|
||||||
}
|
|
||||||
1 => self.pc = (opcode & 0x0fff) as usize,
|
|
||||||
2 => {
|
|
||||||
self.stack.push(self.pc as u16);
|
|
||||||
self.pc = (opcode & 0x0fff) as usize
|
|
||||||
},
|
|
||||||
3 => if self.gpio[vx] == k as u8 {
|
|
||||||
self.pc += 2;
|
|
||||||
},
|
|
||||||
4 => if self.gpio[vx] != k as u8 {
|
|
||||||
self.pc += 2;
|
|
||||||
},
|
|
||||||
5 => if self.gpio[vx] == self.gpio[vy] {
|
|
||||||
self.pc += 2;
|
|
||||||
}
|
|
||||||
6 => self.gpio[vx] = k,
|
|
||||||
7 => self.gpio[vx] = self.gpio[vx].saturating_add(k),
|
|
||||||
8 => {
|
|
||||||
match opcode & 0x000f {
|
|
||||||
0 => self.gpio[vx] = self.gpio[vy],
|
|
||||||
1 => self.gpio[vx] |= self.gpio[vy],
|
|
||||||
2 => self.gpio[vx] &= self.gpio[vy],
|
|
||||||
3 => self.gpio[vx] ^= self.gpio[vy],
|
|
||||||
4 => {
|
|
||||||
self.gpio[vx] = self.gpio[vx].saturating_add(self.gpio[vy]);
|
|
||||||
let (_, overflow) = self.gpio[vx].overflowing_add(self.gpio[vy]);
|
|
||||||
if overflow {
|
|
||||||
self.gpio[0xf] = 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
5 => {
|
|
||||||
if self.gpio[vx] > self.gpio[vy] {
|
|
||||||
self.gpio[0xf] = 1;
|
|
||||||
} else {
|
|
||||||
self.gpio[0xf] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (t, _) = self.gpio[vx].overflowing_sub(self.gpio[vy]);
|
|
||||||
self.gpio[vx] = t;
|
|
||||||
},
|
|
||||||
6 => {
|
|
||||||
if self.gpio[vx].trailing_ones() > 0 {
|
|
||||||
self.gpio[0xf] = 1;
|
|
||||||
} else {
|
|
||||||
self.gpio[0xf] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.gpio[vx] >>= 1;
|
|
||||||
},
|
|
||||||
7 => {
|
|
||||||
if self.gpio[vx] < self.gpio[vy] {
|
|
||||||
self.gpio[0xf] = 1;
|
|
||||||
} else {
|
|
||||||
self.gpio[0xf] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.gpio[vx] = self.gpio[vy] - self.gpio[vx];
|
|
||||||
},
|
|
||||||
0xE => {
|
|
||||||
if self.gpio[vx].leading_ones() > 0 {
|
|
||||||
self.gpio[0xf] = 1;
|
|
||||||
} else {
|
|
||||||
self.gpio[0xf] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.gpio[vx] <<= 1;
|
|
||||||
},
|
|
||||||
_ => println!("error 8")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9 => if self.gpio[vx] != self.gpio[vy] {
|
|
||||||
self.pc += 2;
|
|
||||||
},
|
|
||||||
0xA => self.index = opcode & 0x0fff,
|
|
||||||
0xB => self.pc = ((self.gpio[0]) as u16 + (opcode & 0x0fff)) as usize,
|
|
||||||
0xC => self.gpio[vx] = rand::random::<u8>() & k,
|
|
||||||
0xD => {
|
|
||||||
let x = self.gpio[vx] as u16;
|
|
||||||
let y = self.gpio[vy] as u16;
|
|
||||||
for i in 0..(opcode & 0x000f) {
|
|
||||||
//println!("{:?}", self.memory);
|
|
||||||
let mut sprite = self.memory[(self.index + i as u16) as usize];
|
|
||||||
for j in 0..8 {
|
|
||||||
let mut case = 0;
|
|
||||||
if sprite.leading_ones() > 0 { case = 1; }
|
|
||||||
//println!("I :: {}", self.index + i);
|
|
||||||
//println!("D :: {} - {}", sprite, case);
|
|
||||||
sprite = sprite << 1;
|
|
||||||
|
|
||||||
let ty: usize = (i + y) as usize % HEIGHT;
|
|
||||||
let tx: usize = (j + x) as usize % WIDTH;
|
|
||||||
|
|
||||||
let tmp = self.display_buffer[ty][tx];
|
|
||||||
self.display_buffer[ty][tx] ^= case;
|
|
||||||
if self.display_buffer[ty][tx] == 0 && tmp == 1 {
|
|
||||||
self.gpio[0xf] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
0xE => {
|
|
||||||
match opcode & 0x00ff {
|
|
||||||
0x9E => {
|
|
||||||
if self.key_inputs[self.gpio[vx] as usize] == 1 {
|
|
||||||
self.pc += 2;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
0xA1 => {
|
|
||||||
if self.key_inputs[self.gpio[vx] as usize] == 0 {
|
|
||||||
self.pc += 2;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => println!("error E")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0xF => {
|
|
||||||
match opcode & 0x00ff {
|
|
||||||
0x07 => println!("LD F 7"),
|
|
||||||
0x0A => self.check_touch(vx, events),
|
|
||||||
0x15 => println!("LD F 15"),
|
|
||||||
0x18 => println!("LD F 18"),
|
|
||||||
0x1E => self.index += self.gpio[vx] as u16,
|
|
||||||
0x29 => self.index = (self.gpio[vx] as u16) * 5,
|
|
||||||
0x33 => {
|
|
||||||
self.memory[self.index as usize] = self.gpio[vx] / 100 as u8;
|
|
||||||
self.memory[(self.index + 1) as usize] = (self.gpio[vx] % 100) /10 as u8;
|
|
||||||
self.memory[(self.index + 2) as usize] = self.gpio[vx] % 10 as u8;
|
|
||||||
},
|
|
||||||
0x55 =>
|
|
||||||
{
|
|
||||||
for i in 0..(vx + 1) {
|
|
||||||
self.memory[(self.index as usize) + i] = self.gpio[i];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
0x65 => {
|
|
||||||
for i in 0..(vx + 1) {
|
|
||||||
self.gpio[i] = self.memory[(self.index as usize) + i];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => println!("error F")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => println!("error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_touch(&mut self, vx: usize, events: &mut EventPump) {
|
|
||||||
let touch = events.wait_event();
|
|
||||||
match touch {
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num0), .. } => {
|
|
||||||
self.gpio[vx] = 0;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
|
|
||||||
self.gpio[vx] = 1;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num2), .. } => {
|
|
||||||
self.gpio[vx] = 2;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num3), .. } => {
|
|
||||||
self.gpio[vx] = 3;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num4), .. } => {
|
|
||||||
self.gpio[vx] = 4;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num5), .. } => {
|
|
||||||
self.gpio[vx] = 5;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num6), .. } => {
|
|
||||||
self.gpio[vx] = 6;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num7), .. } => {
|
|
||||||
self.gpio[vx] = 7;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num8), .. } => {
|
|
||||||
self.gpio[vx] = 8;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::Num9), .. } => {
|
|
||||||
self.gpio[vx] = 9;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::A), .. } => {
|
|
||||||
self.gpio[vx] = 0xa;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::B), .. } => {
|
|
||||||
self.gpio[vx] = 0xb;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::C), .. } => {
|
|
||||||
self.gpio[vx] = 0xc;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::D), .. } => {
|
|
||||||
self.gpio[vx] = 0xd;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::E), .. } => {
|
|
||||||
self.gpio[vx] = 0xe;
|
|
||||||
},
|
|
||||||
Event::KeyDown { keycode: Some(Keycode::F), .. } => {
|
|
||||||
self.gpio[vx] = 0xf;
|
|
||||||
},
|
|
||||||
_ => self.check_touch(vx, events),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code, unused_variables)]
|
|
||||||
fn read_file(p: &Path) -> io::Result<()> {
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
let mut f = File::open(p)?;
|
|
||||||
let mut mem = [0; 4096];
|
|
||||||
f.read_to_end(&mut buffer)?;
|
|
||||||
|
|
||||||
for i in 0..buffer.len() {
|
|
||||||
mem[i] = buffer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{:?}", mem);
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < mem.len() {
|
|
||||||
let opcode = ((mem[i] as u16) << 8)
|
|
||||||
+ (mem[i + 1] as u16);
|
|
||||||
|
|
||||||
let vx: usize = ((opcode & 0x0f00) >> 8) as usize;
|
|
||||||
let vy: usize = ((opcode & 0x00f0) >> 4) as usize;
|
|
||||||
let k: u8 = (opcode & 0x00ff) as u8;
|
|
||||||
|
|
||||||
i += 2;
|
|
||||||
|
|
||||||
match (opcode & 0xf000) >> 12 {
|
|
||||||
0 => match opcode {
|
|
||||||
0x00E0 => println!("CLS"),
|
|
||||||
0x00EE => println!("RET"),
|
|
||||||
_ => println!("SYS"),
|
|
||||||
}
|
|
||||||
1 => println!("JP {}", opcode & 0x0fff),
|
|
||||||
2 => println!("CALL {}", opcode & 0x0fff),
|
|
||||||
3 => println!("3SE {} {}", vx, k),
|
|
||||||
4 => println!("4SNE {} {}", vx, k),
|
|
||||||
5 => println!("5SE {} {}", vx, vy),
|
|
||||||
6 => println!("6LD {} {}", vx, k),
|
|
||||||
7 => println!("7ADD {} {}", vx, k),
|
|
||||||
8 => {
|
|
||||||
match opcode & 0x000f {
|
|
||||||
0 => println!("8LD {} {}", vx, vy),
|
|
||||||
1 => println!("8OR {} {}", vx, vy),
|
|
||||||
2 => println!("8AND {} {}", vx, vy),
|
|
||||||
3 => println!("8XOR {} {}", vx, vy),
|
|
||||||
4 => println!("8ADD {} {}", vx, vy),
|
|
||||||
5 => println!("8SUB {} {}", vx, vy),
|
|
||||||
6 => println!("8SHR {} {}", vx, vy),
|
|
||||||
7 => println!("8SUBN {} {}", vx, vy),
|
|
||||||
0xE => println!("8SHL {} {}", vx, vy),
|
|
||||||
_ => println!("error 8")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9 => println!("9SNE {} {}", vx, vy),
|
|
||||||
0xA => println!("AADD I {}", opcode & 0x0fff),
|
|
||||||
0xB => println!("BJP 0 {}", opcode & 0x0fff),
|
|
||||||
0xC => println!("RND {} {}", vx, k),
|
|
||||||
0xD => println!("DRW {} {} {}", vx, vy, opcode & 0x000f),
|
|
||||||
0xE => {
|
|
||||||
let x = (opcode & 0x0f00) >> 8;
|
|
||||||
match opcode & 0x00ff {
|
|
||||||
0x9E => println!("SKP {}", vx),
|
|
||||||
0xA1 => println!("SKNP {}", vx),
|
|
||||||
_ => println!("error E")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0xF => {
|
|
||||||
let x = (opcode & 0x0f00) >> 8;
|
|
||||||
match opcode & 0x00ff {
|
|
||||||
0x07 => println!("FLD {} DT", vx),
|
|
||||||
0x0A => println!("FLD {} K", vx),
|
|
||||||
0x15 => println!("FLD DT {}", vx),
|
|
||||||
0x18 => println!("FLD ST {}", vx),
|
|
||||||
0x1E => println!("FADD I {}", vx),
|
|
||||||
0x29 => println!("FLD F {}", vx),
|
|
||||||
0x33 => println!("FLD B {}", vx),
|
|
||||||
0x55 => println!("FLD [I] {}", vx),
|
|
||||||
0x65 => println!("FLD {} [I]", vx),
|
|
||||||
_ => println!("error F")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => println!("error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let name_file = &env::args().collect::<Vec<String>>()[1];
|
||||||
//read_file(Path::new("15PUZZLE"));
|
//read_file(Path::new("15PUZZLE"));
|
||||||
//return;
|
//return;
|
||||||
let mut t : Machine = Machine::new();
|
let mut t: Machine = Machine::new();
|
||||||
t.init();
|
t.init();
|
||||||
//t.load_rom(Path::new("15PUZZLE"));
|
t.load_rom(Path::new(name_file));
|
||||||
t.load_rom(Path::new("BLINKY")).unwrap();
|
|
||||||
//t.load_rom(Path::new("GUESS"));
|
|
||||||
//t.load_rom(Path::new("BLITZ"));
|
|
||||||
|
|
||||||
let sdl_context = sdl2::init().unwrap();
|
let sdl_context = sdl2::init().unwrap();
|
||||||
let video_subsystem = sdl_context.video().unwrap();
|
let video_subsystem = sdl_context.video().unwrap();
|
||||||
|
@ -553,3 +177,89 @@ fn main() {
|
||||||
canvas.present();
|
canvas.present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code, unused_variables)]
|
||||||
|
fn read_file(p: &Path) -> io::Result<()> {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let mut f = File::open(p)?;
|
||||||
|
let mut mem = [0; 4096];
|
||||||
|
f.read_to_end(&mut buffer)?;
|
||||||
|
|
||||||
|
for i in 0..buffer.len() {
|
||||||
|
mem[i] = buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", mem);
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < mem.len() {
|
||||||
|
let opcode = ((mem[i] as u16) << 8)
|
||||||
|
+ (mem[i + 1] as u16);
|
||||||
|
|
||||||
|
let vx: usize = ((opcode & 0x0f00) >> 8) as usize;
|
||||||
|
let vy: usize = ((opcode & 0x00f0) >> 4) as usize;
|
||||||
|
let k: u8 = (opcode & 0x00ff) as u8;
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
match (opcode & 0xf000) >> 12 {
|
||||||
|
0 => match opcode {
|
||||||
|
0x00E0 => println!("CLS"),
|
||||||
|
0x00EE => println!("RET"),
|
||||||
|
_ => println!("SYS"),
|
||||||
|
}
|
||||||
|
1 => println!("JP {}", opcode & 0x0fff),
|
||||||
|
2 => println!("CALL {}", opcode & 0x0fff),
|
||||||
|
3 => println!("3SE {} {}", vx, k),
|
||||||
|
4 => println!("4SNE {} {}", vx, k),
|
||||||
|
5 => println!("5SE {} {}", vx, vy),
|
||||||
|
6 => println!("6LD {} {}", vx, k),
|
||||||
|
7 => println!("7ADD {} {}", vx, k),
|
||||||
|
8 => {
|
||||||
|
match opcode & 0x000f {
|
||||||
|
0 => println!("8LD {} {}", vx, vy),
|
||||||
|
1 => println!("8OR {} {}", vx, vy),
|
||||||
|
2 => println!("8AND {} {}", vx, vy),
|
||||||
|
3 => println!("8XOR {} {}", vx, vy),
|
||||||
|
4 => println!("8ADD {} {}", vx, vy),
|
||||||
|
5 => println!("8SUB {} {}", vx, vy),
|
||||||
|
6 => println!("8SHR {} {}", vx, vy),
|
||||||
|
7 => println!("8SUBN {} {}", vx, vy),
|
||||||
|
0xE => println!("8SHL {} {}", vx, vy),
|
||||||
|
_ => println!("error 8")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
9 => println!("9SNE {} {}", vx, vy),
|
||||||
|
0xA => println!("AADD I {}", opcode & 0x0fff),
|
||||||
|
0xB => println!("BJP 0 {}", opcode & 0x0fff),
|
||||||
|
0xC => println!("RND {} {}", vx, k),
|
||||||
|
0xD => println!("DRW {} {} {}", vx, vy, opcode & 0x000f),
|
||||||
|
0xE => {
|
||||||
|
let x = (opcode & 0x0f00) >> 8;
|
||||||
|
match opcode & 0x00ff {
|
||||||
|
0x9E => println!("SKP {}", vx),
|
||||||
|
0xA1 => println!("SKNP {}", vx),
|
||||||
|
_ => println!("error E")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0xF => {
|
||||||
|
let x = (opcode & 0x0f00) >> 8;
|
||||||
|
match opcode & 0x00ff {
|
||||||
|
0x07 => println!("FLD {} DT", vx),
|
||||||
|
0x0A => println!("FLD {} K", vx),
|
||||||
|
0x15 => println!("FLD DT {}", vx),
|
||||||
|
0x18 => println!("FLD ST {}", vx),
|
||||||
|
0x1E => println!("FADD I {}", vx),
|
||||||
|
0x29 => println!("FLD F {}", vx),
|
||||||
|
0x33 => println!("FLD B {}", vx),
|
||||||
|
0x55 => println!("FLD [I] {}", vx),
|
||||||
|
0x65 => println!("FLD {} [I]", vx),
|
||||||
|
_ => println!("error F")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => println!("error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue