Add pixels-rs and winit as dependencies
This commit is contained in:
parent
be4be99c92
commit
4acffdfb6b
|
@ -1,2 +1,3 @@
|
||||||
/target
|
/target
|
||||||
/games
|
/games
|
||||||
|
/.vscode
|
File diff suppressed because it is too large
Load Diff
|
@ -8,3 +8,6 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
|
pixels = "0.0.4"
|
||||||
|
winit = "0.22.2"
|
||||||
|
winit_input_helper = "0.7.0"
|
||||||
|
|
54
src/emu.rs
54
src/emu.rs
|
@ -15,12 +15,12 @@ pub struct Chip8 {
|
||||||
memory: [u8; 4096],
|
memory: [u8; 4096],
|
||||||
delay: Timer,
|
delay: Timer,
|
||||||
sound: Timer,
|
sound: Timer,
|
||||||
display: Display,
|
pub display: Display,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Chip8 {
|
impl Default for Chip8 {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Chip8 {
|
let mut chip8 = Chip8 {
|
||||||
opcode: 0,
|
opcode: 0,
|
||||||
i: 0,
|
i: 0,
|
||||||
pc: 0x200, // Progrm counter starts at 0x200
|
pc: 0x200, // Progrm counter starts at 0x200
|
||||||
|
@ -32,11 +32,33 @@ impl Default for Chip8 {
|
||||||
delay: Default::default(),
|
delay: Default::default(),
|
||||||
sound: Default::default(),
|
sound: Default::default(),
|
||||||
display: Display::default(),
|
display: Display::default(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
chip8.load_font_set();
|
||||||
|
chip8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chip8 {
|
impl Chip8 {
|
||||||
|
const FONT_SET: [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
|
||||||
|
];
|
||||||
|
|
||||||
pub fn execute_cycle(&mut self) {
|
pub fn execute_cycle(&mut self) {
|
||||||
self.opcode = self.get_opcode();
|
self.opcode = self.get_opcode();
|
||||||
println!("{:#x}", self.opcode);
|
println!("{:#x}", self.opcode);
|
||||||
|
@ -46,6 +68,12 @@ impl Chip8 {
|
||||||
self.sound.tick();
|
self.sound.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_font_set(&mut self) {
|
||||||
|
for (i, byte) in Self::FONT_SET.iter().enumerate() {
|
||||||
|
self.memory[i] = *byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_rom<P: AsRef<Path>>(&mut self, path: P) -> Result<(), io::Error> {
|
pub fn load_rom<P: AsRef<Path>>(&mut self, path: P) -> Result<(), io::Error> {
|
||||||
let mut file = File::open(path.as_ref())?;
|
let mut file = File::open(path.as_ref())?;
|
||||||
let mut rom_buf: Vec<u8> = vec![];
|
let mut rom_buf: Vec<u8> = vec![];
|
||||||
|
@ -157,6 +185,7 @@ impl Chip8 {
|
||||||
fn jmp_addr(&mut self, n_1: u16, n_2: u16, n_3: u16) {
|
fn jmp_addr(&mut self, n_1: u16, n_2: u16, n_3: u16) {
|
||||||
// sets the program counter to addr (nnn)
|
// sets the program counter to addr (nnn)
|
||||||
self.pc = Self::convert_to_addr(n_1, n_2, n_3);
|
self.pc = Self::convert_to_addr(n_1, n_2, n_3);
|
||||||
|
println!("{:#x}", self.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ret(&mut self) {
|
fn ret(&mut self) {
|
||||||
|
@ -203,7 +232,7 @@ impl Chip8 {
|
||||||
fn add_vx_byte(&mut self, x: u16, k_1: u16, k_2: u16) {
|
fn add_vx_byte(&mut self, x: u16, k_1: u16, k_2: u16) {
|
||||||
// calculate Vx + kk, then store it in Vx
|
// calculate Vx + kk, then store it in Vx
|
||||||
let x = x as usize;
|
let x = x as usize;
|
||||||
self.v[x] = self.v[x] + Self::convert_to_byte(k_1, k_2);
|
self.v[x] = self.v[x].wrapping_add(Self::convert_to_byte(k_1, k_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ld_vx_vy(&mut self, x: u16, y: u16) {
|
fn ld_vx_vy(&mut self, x: u16, y: u16) {
|
||||||
|
@ -247,7 +276,7 @@ impl Chip8 {
|
||||||
let vy = self.v[y as usize];
|
let vy = self.v[y as usize];
|
||||||
|
|
||||||
self.v[0xF as usize] = if vx > vy { 1 } else { 0 };
|
self.v[0xF as usize] = if vx > vy { 1 } else { 0 };
|
||||||
self.v[x as usize] = vx - vy;
|
self.v[x as usize] = vx.wrapping_sub(vy);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shr_vx(&mut self, x: u16) {
|
fn shr_vx(&mut self, x: u16) {
|
||||||
|
@ -390,8 +419,9 @@ impl Chip8 {
|
||||||
self.i = self.i + self.v[x as usize] as u16;
|
self.i = self.i + self.v[x as usize] as u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ld_f_vx(&mut self, _x: u16) {
|
fn ld_f_vx(&mut self, x: u16) {
|
||||||
todo!("Implement 0xF_29");
|
// set I to location of hex sprite related to Vx
|
||||||
|
self.i = self.v[x as usize] as u16 * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ld_b_vx(&mut self, x: u16) {
|
fn ld_b_vx(&mut self, x: u16) {
|
||||||
|
@ -399,15 +429,15 @@ impl Chip8 {
|
||||||
// take tens digit and place it at I + 1
|
// take tens digit and place it at I + 1
|
||||||
// take ones digit and place it at I + 2
|
// take ones digit and place it at I + 2
|
||||||
let i = self.i as usize;
|
let i = self.i as usize;
|
||||||
let mut iter = Self::digits(self.v[x as usize]);
|
let mut iter = Self::digits(self.v[x as usize] as usize);
|
||||||
|
|
||||||
let ones = iter.next().unwrap(); // Ther has to at least be a ones lol
|
let ones = iter.next().unwrap(); // Ther has to at least be a ones lol
|
||||||
let tens = iter.next().unwrap_or(0);
|
let tens = iter.next().unwrap_or(0);
|
||||||
let hundreds = iter.next().unwrap_or(0);
|
let hundreds = iter.next().unwrap_or(0);
|
||||||
|
|
||||||
self.memory[i] = hundreds;
|
self.memory[i] = hundreds as u8;
|
||||||
self.memory[i + 1] = tens;
|
self.memory[i + 1] = tens as u8;
|
||||||
self.memory[i + 2] = ones;
|
self.memory[i + 2] = ones as u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ld_i_vx(&mut self, x: u16) {
|
fn ld_i_vx(&mut self, x: u16) {
|
||||||
|
@ -436,7 +466,7 @@ impl Chip8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/41536479/how-do-i-split-an-integer-into-individual-digits
|
// https://stackoverflow.com/questions/41536479/how-do-i-split-an-integer-into-individual-digits
|
||||||
fn digits(mut num: u8) -> impl Iterator<Item = u8> {
|
fn digits(mut num: usize) -> impl Iterator<Item = usize> {
|
||||||
let mut divisor = 1;
|
let mut divisor = 1;
|
||||||
while num >= divisor * 10 {
|
while num >= divisor * 10 {
|
||||||
divisor *= 10;
|
divisor *= 10;
|
||||||
|
|
68
src/main.rs
68
src/main.rs
|
@ -4,16 +4,78 @@
|
||||||
use chip8::emu::Chip8;
|
use chip8::emu::Chip8;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use pixels::{wgpu::Surface, Error, Pixels, SurfaceTexture};
|
||||||
|
use winit::dpi::LogicalSize;
|
||||||
|
use winit::event::{Event, VirtualKeyCode};
|
||||||
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
|
use winit::window::WindowBuilder;
|
||||||
|
use winit_input_helper::WinitInputHelper;
|
||||||
|
|
||||||
|
static WIDTH: u32 = 64;
|
||||||
|
static HEIGHT: u32 = 32;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
let mut input = WinitInputHelper::new();
|
||||||
|
let window = {
|
||||||
|
let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
|
||||||
|
WindowBuilder::new()
|
||||||
|
.with_title("Chip8 Emulator")
|
||||||
|
.with_inner_size(size)
|
||||||
|
.with_min_inner_size(size)
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut hidpi_factor = window.scale_factor();
|
||||||
|
|
||||||
|
let mut pixels = {
|
||||||
|
let surface = Surface::create(&window);
|
||||||
|
let surface_texture = SurfaceTexture::new(WIDTH, HEIGHT, surface);
|
||||||
|
Pixels::new(WIDTH, HEIGHT, surface_texture).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut chip8: Chip8 = Default::default();
|
let mut chip8: Chip8 = Default::default();
|
||||||
|
|
||||||
chip8
|
chip8
|
||||||
.load_rom(Path::new("./games/c8games/TICTAC"))
|
.load_rom(Path::new("./games/test_opcode.ch8"))
|
||||||
.expect("Unable to load ROM");
|
.expect("Unable to load ROM");
|
||||||
|
|
||||||
loop {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
chip8.execute_cycle();
|
chip8.execute_cycle();
|
||||||
|
|
||||||
std::thread::sleep(Duration::from_millis(300));
|
draw(&chip8.display.buf, pixels.get_frame());
|
||||||
|
pixels.render().unwrap();
|
||||||
|
window.request_redraw();
|
||||||
|
|
||||||
|
if input.update(&event) {
|
||||||
|
if let Some(factor) = input.scale_factor_changed() {
|
||||||
|
hidpi_factor = factor;
|
||||||
|
};
|
||||||
|
|
||||||
|
if input.key_pressed(VirtualKeyCode::Escape) || input.quit() {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(size) = input.window_resized() {
|
||||||
|
pixels.resize(size.width, size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::thread::sleep(Duration::from_millis(1000));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(chip8_gfx: &[u8], frame: &mut [u8]) {
|
||||||
|
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
||||||
|
let rgba = if chip8_gfx[i] != 0 {
|
||||||
|
[0xFF, 0xFF, 0xFF, 0xFF]
|
||||||
|
} else {
|
||||||
|
[0x00, 0x00, 0x00, 0xFF]
|
||||||
|
};
|
||||||
|
|
||||||
|
pixel.copy_from_slice(&rgba);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue