commit - 5210a85ad5036c3aff9bbcc757763582d5bea59a
commit + ebf97be247eb7e27b2df1adf663ae48c9accd391
blob - 51185056fdf6742a81bcb84add7490c87fd0d846
blob + a354d0166c46432769fc74e545d7a6bde293d80b
--- src/chip8.rs
+++ src/chip8.rs
use crate::drivers::VideoDriver;
+const PROGRAM_START: u16 = 0x200;
+
#[derive(Debug)]
/// Represents a Chip8 machine
pub struct Chip8 {
video_driver: VideoDriver,
}
-#[derive(Debug, Clone)]
-/// Instructions of the Chip8.
-pub enum Instruction {
- /// Clears the screen.
- CLS,
- /// Default type for empty instruction field.
- /// This is not an actual instruction.
- EMPTY,
-}
-
impl Chip8 {
pub fn new() -> Self {
Self {
mem: vec![0; 4096],
regs: vec![0; 16],
i_reg: 0,
- pc: 0,
+ pc: PROGRAM_START,
stack: vec![0; 16],
stack_pointer: 0,
delay_timer: 0,
}
/// Execute a given instruction.
- pub fn execute(&mut self, instruction: Instruction) -> Result<(), String> {
+ pub fn execute(&mut self, instruction: u16) -> Result<(), String> {
match instruction {
// CLS
- Instruction::CLS => {
+ 0x00E0 => {
self.video_driver.clear();
},
_ => {
- return Err(String::from("unknown instruction"));
+ return Err(format!("{:#06x}: not an instruction", instruction));
}
};
Ok(())
}
+ fn execute_next_instruction(&mut self) -> Result<(), String> {
+ let hi = self.mem[self.pc as usize] as u16;
+ let lo = self.mem[self.pc as usize + 1] as u16;
+ let ins: u16 = (hi << 8) | lo;
+
+ self.execute(ins)?;
+ self.pc = self.pc + 2;
+
+ Ok(())
+ }
+
pub fn run(&mut self, file_path: &Path) -> Result<(), String> {
+ self.init_program(file_path)?;
+
+ while self.pc < self.mem.len() as u16 {
+ self.execute_next_instruction()?;
+ }
+
+ Ok(())
+ }
+
+ fn init_program(&mut self, file_path: &Path) -> Result<(), String> {
let bytes = std::fs::read(file_path).expect("reading file");
- let instructions = convert_to_instructions(bytes)?;
+ if bytes.len() > self.mem.len() - PROGRAM_START as usize {
+ return Err(String::from("Program too big"));
+ }
- for i in instructions {
- println!("executing instruction {:?} at line {}", i, self.pc);
- self.execute(i)?;
- self.pc = self.pc + 1;
+ for i in 0..bytes.len() {
+ self.mem[PROGRAM_START as usize + i] = bytes[i];
}
Ok(())
}
}
-
-// this makes the code easier to read
-/// Convert a raw u16 instruction to an Instruction enum.
-pub fn raw_to_instruction(instruction: u16) -> Result<Instruction, String> {
- match instruction {
- // CLS
- 0x00E0 => return Ok(Instruction::CLS),
- _ => {
- return Err(format!("{:x}: not an instruction", instruction));
- }
- }
-}
-
-fn convert_to_instructions(bytes: Vec<u8>) -> Result<Vec<Instruction>, String> {
- // since 2 bytes make up 1 instruction this vec only needs to be half as big
- let mut instructions: Vec<Instruction> = vec![Instruction::EMPTY; bytes.len() / 2];
-
- let iter = bytes.chunks(2);
-
- for (i, e) in iter.enumerate() {
- let t: u16 = (e[0] as u16) << 8 | (e[1] as u16);
- instructions[i] = raw_to_instruction(t)?;
- }
-
- Ok(instructions)
-}