mirror of
https://github.com/arnaucube/chip8-rs.git
synced 2026-02-06 18:56:47 +01:00
Add Sdl rendering, Add keyboard input
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# chip8-rs
|
# chip8-rs
|
||||||
|
|
||||||
CHIP-8 emulator written in Rust.
|
CHIP-8 emulator written in Rust.
|
||||||
(Done from the Go implementation: https://github.com/arnaucube/go-chip8)
|
(Done with the Go implementation: https://github.com/arnaucube/go-chip8)
|
||||||
|
|
||||||
https://en.wikipedia.org/wiki/CHIP-8
|
https://en.wikipedia.org/wiki/CHIP-8
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub struct Chip8 {
|
|||||||
sound_timer: u8,
|
sound_timer: u8,
|
||||||
stack: [u16; 16],
|
stack: [u16; 16],
|
||||||
sp: isize,
|
sp: isize,
|
||||||
key: [u8; 16],
|
pub key: [u8; 16],
|
||||||
pub draw_flag: bool,
|
pub draw_flag: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,12 +71,13 @@ impl Chip8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn emulate_cycle(&mut self) {
|
pub fn emulate_cycle(&mut self) {
|
||||||
self.opcode = (self.memory[self.pc as usize] as u16) << 8
|
self.opcode = ((self.memory[self.pc as usize] as u16) << 8)
|
||||||
| self.memory[(self.pc + 1) as usize] as u16;
|
| (self.memory[(self.pc + 1) as usize] as u16);
|
||||||
let x: usize = ((self.opcode & 0x0F00) >> 8) as usize;
|
let x: usize = ((self.opcode & 0x0F00) >> 8) as usize;
|
||||||
let y: usize = ((self.opcode & 0x00F0) >> 4) as usize;
|
let y: usize = ((self.opcode & 0x00F0) >> 4) as usize;
|
||||||
let nn: u8 = (self.opcode & 0x00FF) as u8;
|
let nn: u8 = (self.opcode & 0x00FF) as u8;
|
||||||
let nnn: u16 = (self.opcode & 0x0FFF) as u16;
|
let nnn: u16 = (self.opcode & 0x0FFF) as u16;
|
||||||
|
// println!("{:?} {:?}", self.opcode, self.pc);
|
||||||
|
|
||||||
// Decode Opcode
|
// Decode Opcode
|
||||||
// https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
|
// https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
|
||||||
@@ -275,7 +276,7 @@ impl Chip8 {
|
|||||||
if self.gfx[pos] == 1 {
|
if self.gfx[pos] == 1 {
|
||||||
self.v[0xF] = 1;
|
self.v[0xF] = 1;
|
||||||
} else {
|
} else {
|
||||||
self.v[0xF] ^= 1;
|
self.gfx[pos] ^= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +368,7 @@ impl Chip8 {
|
|||||||
}
|
}
|
||||||
self.pc += 2;
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
0x0064 => {
|
0x0065 => {
|
||||||
// 0xFX65 Fills V0 to VX (including VX) with values
|
// 0xFX65 Fills V0 to VX (including VX) with values
|
||||||
// from memory starting at address I. The offset from I
|
// from memory starting at address I. The offset from I
|
||||||
// is increased by 1 for each value written, but I
|
// is increased by 1 for each value written, but I
|
||||||
@@ -382,6 +383,15 @@ impl Chip8 {
|
|||||||
}
|
}
|
||||||
_ => println!("opc {:x}", self.opcode),
|
_ => println!("opc {:x}", self.opcode),
|
||||||
}
|
}
|
||||||
|
if self.delay_timer > 0 {
|
||||||
|
self.delay_timer -= 1;
|
||||||
|
}
|
||||||
|
if self.sound_timer > 0 {
|
||||||
|
if self.sound_timer == 1 {
|
||||||
|
println!("Beep");
|
||||||
|
}
|
||||||
|
self.sound_timer -= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
roms/TETRIS
Normal file
BIN
roms/TETRIS
Normal file
Binary file not shown.
BIN
roms/chip8-picture.ch8
Normal file
BIN
roms/chip8-picture.ch8
Normal file
Binary file not shown.
BIN
roms/invaders.c8
Executable file
BIN
roms/invaders.c8
Executable file
Binary file not shown.
BIN
roms/pong.c8
Executable file
BIN
roms/pong.c8
Executable file
Binary file not shown.
BIN
roms/slipperyslope.ch8
Normal file
BIN
roms/slipperyslope.ch8
Normal file
Binary file not shown.
90
src/main.rs
90
src/main.rs
@@ -1,6 +1,11 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::{thread, time};
|
||||||
extern crate sdl2;
|
extern crate sdl2;
|
||||||
|
|
||||||
|
use sdl2::event::Event;
|
||||||
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::Rect;
|
||||||
use sdl2::render::Canvas;
|
use sdl2::render::Canvas;
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
@@ -11,7 +16,9 @@ struct SdlEmulator {
|
|||||||
w: usize,
|
w: usize,
|
||||||
h: usize,
|
h: usize,
|
||||||
zoom: usize,
|
zoom: usize,
|
||||||
|
sdl_context: sdl2::Sdl,
|
||||||
canvas: Canvas<sdl2::video::Window>,
|
canvas: Canvas<sdl2::video::Window>,
|
||||||
|
vkeys: HashMap<Keycode, u8>,
|
||||||
chip8: Chip8,
|
chip8: Chip8,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,26 +30,97 @@ impl SdlEmulator {
|
|||||||
let video_subsystem = sdl_context.video().unwrap();
|
let video_subsystem = sdl_context.video().unwrap();
|
||||||
|
|
||||||
let window = video_subsystem
|
let window = video_subsystem
|
||||||
.window("rust-sdl2 demo", 800, 600)
|
.window("rust-sdl2 demo", (w * zoom) as u32, (h * zoom) as u32)
|
||||||
.position_centered()
|
.position_centered()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut canvas = window.into_canvas().build().unwrap();
|
let mut canvas = window.into_canvas().build().unwrap();
|
||||||
|
|
||||||
|
let mut vkeys: HashMap<Keycode, u8> = HashMap::new();
|
||||||
|
vkeys.insert(Keycode::Num1, 0x01);
|
||||||
|
vkeys.insert(Keycode::Num2, 0x02);
|
||||||
|
vkeys.insert(Keycode::Num3, 0x03);
|
||||||
|
vkeys.insert(Keycode::Num4, 0x0c);
|
||||||
|
vkeys.insert(Keycode::Q, 0x04);
|
||||||
|
vkeys.insert(Keycode::W, 0x05);
|
||||||
|
vkeys.insert(Keycode::E, 0x06);
|
||||||
|
vkeys.insert(Keycode::R, 0x07);
|
||||||
|
vkeys.insert(Keycode::A, 0x08);
|
||||||
|
vkeys.insert(Keycode::S, 0x09);
|
||||||
|
vkeys.insert(Keycode::D, 0x0E);
|
||||||
|
vkeys.insert(Keycode::F, 0x0A);
|
||||||
|
vkeys.insert(Keycode::Z, 0x00);
|
||||||
|
vkeys.insert(Keycode::X, 0x0B);
|
||||||
|
vkeys.insert(Keycode::V, 0x0F);
|
||||||
|
|
||||||
SdlEmulator {
|
SdlEmulator {
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
zoom,
|
zoom,
|
||||||
|
sdl_context,
|
||||||
canvas,
|
canvas,
|
||||||
|
vkeys,
|
||||||
chip8: c,
|
chip8: c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn draw_graphics(&mut self) {
|
fn draw_graphics(&mut self) {
|
||||||
// TODO
|
self.canvas.set_draw_color(Color::RGB(0, 0, 0));
|
||||||
|
self.canvas.clear();
|
||||||
|
self.canvas.set_draw_color(Color::RGB(255, 255, 255));
|
||||||
|
for y in 0..self.h {
|
||||||
|
for x in 0..self.w {
|
||||||
|
let pixel = self.chip8.gfx[y * self.w + x];
|
||||||
|
if pixel != 0 {
|
||||||
|
self.canvas.fill_rect(Rect::new(
|
||||||
|
(x * self.zoom) as i32,
|
||||||
|
(y * self.zoom) as i32,
|
||||||
|
(self.zoom) as u32,
|
||||||
|
(self.zoom) as u32,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.canvas.present();
|
||||||
|
self.chip8.draw_flag = false;
|
||||||
}
|
}
|
||||||
fn set_keys(&mut self) {
|
fn set_keys(&mut self) -> Result<(), String> {
|
||||||
// TODO
|
let mut events = self.sdl_context.event_pump()?;
|
||||||
|
for event in events.poll_iter() {
|
||||||
|
match event {
|
||||||
|
Event::Quit { .. } => {
|
||||||
|
println!("Quit");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
Event::KeyDown {
|
||||||
|
keycode: Some(keycode),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
println!("k {:?}", keycode);
|
||||||
|
if self.vkeys.contains_key(&keycode) {
|
||||||
|
let k_hex = self.vkeys.get(&keycode).unwrap();
|
||||||
|
self.chip8.key[*k_hex as usize] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::KeyUp {
|
||||||
|
keycode: Some(keycode),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
println!("k {:?}", keycode);
|
||||||
|
if self.vkeys.contains_key(&keycode) {
|
||||||
|
let k_hex = self.vkeys.get(&keycode).unwrap();
|
||||||
|
self.chip8.key[*k_hex as usize] = 0;
|
||||||
|
}
|
||||||
|
if keycode == Keycode::Escape {
|
||||||
|
println!("EXIT");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,12 +144,14 @@ fn main() {
|
|||||||
println!("{:?}", file);
|
println!("{:?}", file);
|
||||||
|
|
||||||
let mut e = SdlEmulator::new(64, 32, 8);
|
let mut e = SdlEmulator::new(64, 32, 8);
|
||||||
|
e.chip8.load_game(file);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
e.chip8.emulate_cycle();
|
e.chip8.emulate_cycle();
|
||||||
if e.chip8.draw_flag {
|
if e.chip8.draw_flag {
|
||||||
e.draw_graphics();
|
e.draw_graphics();
|
||||||
}
|
}
|
||||||
e.set_keys();
|
e.set_keys();
|
||||||
// delay
|
std::thread::sleep(time::Duration::from_millis(1000 / 60));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user