Add basic program loading, memory map, etc
This commit is contained in:
parent
808d51918f
commit
0b0353c923
BIN
programs/ibm_logo.ch8
Normal file
BIN
programs/ibm_logo.ch8
Normal file
Binary file not shown.
BIN
programs/test.ch8
Normal file
BIN
programs/test.ch8
Normal file
Binary file not shown.
106
src/chip8.rs
106
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
21
src/main.rs
21
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<u8> = &contents.expect("");
|
||||
// let magic_num: &[u8] = &bytes[0..4];
|
||||
let file_data: &Vec<u8> = &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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user