Add ROM loading and basic opcode support

This commit is contained in:
Michael Kohl 2021-04-06 18:52:33 +07:00
parent 408480a4ef
commit b105e8ca1e
4 changed files with 60 additions and 14 deletions

View File

@ -1,13 +1,13 @@
use crate::chip8::audio::Speaker;
use crate::chip8::display::Screen;
use crate::chip8::keyboard::Keyboard;
use crate::chip8::memory::Memory;
use crate::chip8::memory::{Memory, MEMORY_SIZE, PROGRAM_LOAD_ADDRESS};
use crate::chip8::registers::{Register, Registers};
use crate::chip8::stack::Stack;
use sdl2::AudioSubsystem;
use std::{thread, time::Duration};
use std::{fs, thread, time::Duration};
pub struct Chip8 {
pub memory: Memory,
@ -30,11 +30,6 @@ impl Chip8 {
}
}
pub fn handle_timers(&mut self) -> () {
self.handle_delay_timer();
self.handle_sound_timer();
}
pub fn handle_delay_timer(&mut self) -> () {
let delay_timer = self.registers.get(Register::DT);
if delay_timer > 0 {
@ -52,4 +47,26 @@ impl Chip8 {
self.registers.set(Register::ST, sound_timer - 1);
}
}
pub fn load_rom(&mut self, file: &str) -> usize {
let rom = fs::read(file).expect("Cannot read ROM");
let rom_length = rom.len();
if rom_length > MEMORY_SIZE - PROGRAM_LOAD_ADDRESS {
panic!("ROM too big, aborting")
}
for (i, byte) in rom.iter().enumerate() {
self.memory.set(PROGRAM_LOAD_ADDRESS + i, *byte);
}
rom_length
}
pub fn exec(&mut self) {
let pc = self.registers.get(Register::PC);
let opcode = self.memory.read_opcode(pc as usize);
println!("{}", opcode);
self.registers.set(Register::PC, pc + 2);
}
}

View File

@ -1,4 +1,5 @@
const MEMORY_SIZE: usize = 4096;
pub const MEMORY_SIZE: usize = 4096;
pub const PROGRAM_LOAD_ADDRESS: usize = 0x200;
const DEFAULT_CHARACTER_SET_START: usize = 0;
@ -53,6 +54,11 @@ impl Memory {
pub fn read(&self, start: usize, bytes: u8) -> &[u8] {
&self.memory[start..start + bytes as usize]
}
pub fn read_opcode(&self, start: usize) -> u16 {
let bytes = self.read(start, 2);
(bytes[0] as u16) << 8 | bytes[1] as u16
}
}
#[cfg(test)]

View File

@ -1,3 +1,5 @@
use super::memory::PROGRAM_LOAD_ADDRESS;
const DATA_REGISTERS: usize = 16;
pub enum Register {
@ -62,7 +64,7 @@ impl Registers {
i: 0,
delay_timer: 0,
sound_timer: 0,
pc: 0,
pc: PROGRAM_LOAD_ADDRESS as u16,
sp: 0,
}
}

View File

@ -8,18 +8,37 @@ use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use std::env;
const EMULATOR_WINDOW_TITLE: &str = "Rust CHIP-8";
fn main() -> Result<(), String> {
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("USAGE: {} <path to ROM>", &args[0]);
std::process::exit(0);
}
std::process::exit(match run(&args[1]) {
Ok(_) => 0,
Err(err) => {
eprintln!("ERROR: {:?}", err);
1
}
});
}
fn run(rom: &str) -> Result<(), String> {
print!("Initializing SDL: ");
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let audio_subsystem = sdl_context.audio()?;
println!("Done");
let mut chip8 = Chip8::new(&audio_subsystem);
chip8.screen.draw_sprite(24, 13, chip8.memory.read(20, 5));
chip8.screen.draw_sprite(29, 13, chip8.memory.read(10, 5));
chip8.screen.draw_sprite(34, 13, chip8.memory.read(40, 5));
chip8.registers.set(chip8::registers::Register::ST, 5);
print!("Loading ROM: {}: ", &rom);
let bytes = chip8.load_rom(rom);
println!("Done ({} bytes)", bytes);
let window = video_subsystem
.window(
@ -89,6 +108,8 @@ fn main() -> Result<(), String> {
canvas.present();
chip8.handle_delay_timer();
chip8.handle_sound_timer();
chip8.exec();
}
Ok(())