diff --git a/programs/ibm_logo.ch8 b/programs/ibm_logo.ch8 new file mode 100644 index 0000000..113338e Binary files /dev/null and b/programs/ibm_logo.ch8 differ diff --git a/programs/test.ch8 b/programs/test.ch8 new file mode 100644 index 0000000..feda8b1 Binary files /dev/null and b/programs/test.ch8 differ diff --git a/src/chip8.rs b/src/chip8.rs index ccaeae2..2247365 100644 --- a/src/chip8.rs +++ b/src/chip8.rs @@ -1,7 +1,103 @@ -// Miscellanious registers -static mut program_counter: u16 = 0; -static mut stack_ptr: u8 = 0; +// chip8.rs +// Implementation of chip8 machine, registers, and memory makeup -// General purpose registers -static mut registers: [u8; 16] = [0; 16]; +use crate::util; +// Memory map constants +pub const PRGRM_START: usize = 512; +pub const MAX_MEM_SIZE: usize = 4096; +pub const MAX_PRG_SIZE: usize = 3584; + +// Instruction constants +const INSTR_NOOP: u16 = 0x0000; +const INSTR_EXIT: u16 = 0x00FD; + +#[derive(Debug)] +struct EmulationState { + // Miscellanious registers + program_counter: u16, + stack_ptr: u8, + + // General purpose registers + registers: [u8; 16], + + // Memory Map: + // +---------------+= 0xFFF (4095) End of Chip-8 RAM + // | | + // | | + // | | + // | | + // | | + // | 0x200 to 0xFFF| + // | Chip-8 | + // | Program / Data| + // | Space | + // | | + // | | + // | | + // +- - - - - - - -+= 0x600 (1536) Start of ETI 660 Chip-8 programs + // | | + // | | + // | | + // +---------------+= 0x200 (512) Start of most Chip-8 programs + // | 0x000 to 0x1FF| + // | Reserved for | + // | interpreter | + // +---------------+= 0x000 (0) Start of Chip-8 RAM + memory: [u8; 4096] +} + +pub fn start_emulation(data: [u8; MAX_PRG_SIZE]) { + let mut state: EmulationState = EmulationState{ + program_counter: 0, + stack_ptr: 0, + registers: [0; 16], + memory: [0; MAX_MEM_SIZE] + }; + + load_program(data, &mut state); + exec_program(&mut state); +} + +// Load the program into virtual memory +fn load_program(data: [u8; MAX_PRG_SIZE], state: &mut EmulationState) { + println!("Copying program data to memory"); + for i in 0..MAX_PRG_SIZE { + state.memory[i+PRGRM_START] = data[i]; + } +} + +// Execute the program starting at the userspace address +fn exec_program(state: &mut EmulationState) { + println!("Starting emulation"); + + let mut head_byte: u8; + let mut tail_byte: u8; + let mut instruction_tuple: (u8, u8); + + for _i in PRGRM_START+usize::from(state.program_counter)..MAX_MEM_SIZE { + // Grab the first byte of instruction + head_byte = state.memory[PRGRM_START + usize::from(state.program_counter)]; + state.program_counter += 1; + + // Grab the second byte of instruction + tail_byte = state.memory[PRGRM_START + usize::from(state.program_counter)]; + state.program_counter += 1; + + instruction_tuple = (head_byte, tail_byte); + + println!("0x{:02X?}{:02X?}", head_byte, tail_byte); + + if util::u8_tuple_to_u16(instruction_tuple) == INSTR_EXIT { + println!("Read exit instruction, stopping emulation"); + return; + } + + if util::u8_tuple_to_u16(instruction_tuple) == INSTR_NOOP { + println!("Read no-op instruction, stopping emulation"); + return; + } + } + + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index eb6161e..f01706c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use std::process::exit; // Module imports mod util; +mod chip8; fn main() { @@ -31,8 +32,24 @@ fn main() if contents.is_ok() { - let _bytes: &Vec = &contents.expect(""); - // let magic_num: &[u8] = &bytes[0..4]; + let file_data: &Vec = &contents.expect(""); + if file_data.len() > chip8::MAX_PRG_SIZE.into() { + eprintln!("Error loading file, program size too large!"); + exit(1); + } + else if file_data.len() == 0 { + eprintln!("Error loading file, no program data found!"); + exit(1); + } + + let mut program: [u8; chip8::MAX_PRG_SIZE] = [0; chip8::MAX_PRG_SIZE]; + for i in 0..file_data.len() { + program[i] = file_data[i]; + } + + println!("Read {} bytes of program data", file_data.len()); + chip8::start_emulation(program); + } } else { diff --git a/src/util.rs b/src/util.rs index 1504663..c6c6ac5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,9 @@ pub fn print_help() { print!("Usage: saltnvinegar [CHIP8_FILE]\n"); +} + +pub fn u8_tuple_to_u16(u8_in: (u8, u8)) -> u16 { + let head_byte: u16 = u16::from(u8_in.0) << 8; + let tail_byte: u16 = u16::from(u8_in.1); + return head_byte + tail_byte; } \ No newline at end of file