forked from Lea/invadeez
132 lines
3.7 KiB
Rust
132 lines
3.7 KiB
Rust
use instructions::arithmetic;
|
|
use std::{env, fs};
|
|
|
|
use crate::structs::*;
|
|
|
|
mod instructions;
|
|
mod structs;
|
|
|
|
pub const MEMORY_SIZE: usize = 8192;
|
|
|
|
fn main() {
|
|
let mut state = EmulatorState {
|
|
a: 0,
|
|
b: 0,
|
|
c: 0,
|
|
d: 0,
|
|
e: 0,
|
|
h: 0,
|
|
l: 0,
|
|
sp: 0,
|
|
cc: ConditionCodes {
|
|
z: true,
|
|
s: true,
|
|
p: true,
|
|
c: true,
|
|
},
|
|
pc: 0,
|
|
ei: true,
|
|
memory: [0; MEMORY_SIZE],
|
|
};
|
|
|
|
// Load the ROM into memory
|
|
let mut args = env::args();
|
|
let filename = args
|
|
.nth(1)
|
|
.expect("Provide a path to a ROM file to emulate as an argument");
|
|
let file = fs::read(filename).expect("where file");
|
|
|
|
let to_copy = MEMORY_SIZE.min(file.len());
|
|
state.memory[..to_copy].copy_from_slice(&file[..to_copy]);
|
|
|
|
while state.pc < MEMORY_SIZE as u16 {
|
|
tick(&mut state);
|
|
}
|
|
|
|
println!("Program counter reached end of memory; exiting");
|
|
print_state(&state);
|
|
}
|
|
|
|
fn tick(state: &mut EmulatorState) {
|
|
let instruction = state.memory[state.pc as usize];
|
|
|
|
let mut next_byte = || {
|
|
state.pc += 1;
|
|
state.memory[state.pc as usize]
|
|
};
|
|
|
|
match instruction {
|
|
0x00 => {} // NOP
|
|
|
|
/* Special */
|
|
0xfb => state.ei = true, // EI
|
|
0xf3 => state.ei = false, // DI
|
|
0x76 => {
|
|
// HLT
|
|
if state.ei {
|
|
todo!()
|
|
} else {
|
|
println!("HLT called after DI; exiting.");
|
|
print_state(state);
|
|
std::process::exit(0);
|
|
}
|
|
}
|
|
|
|
/* Maths */
|
|
// INR
|
|
0x04 => arithmetic::inr(Register::B, state),
|
|
0x0c => arithmetic::inr(Register::C, state),
|
|
0x14 => arithmetic::inr(Register::D, state),
|
|
0x1c => arithmetic::inr(Register::E, state),
|
|
0x24 => arithmetic::inr(Register::H, state),
|
|
0x2c => arithmetic::inr(Register::L, state),
|
|
0x34 => arithmetic::inr(Register::M, state),
|
|
0x3c => arithmetic::inr(Register::A, state),
|
|
|
|
// DCR
|
|
0x05 => arithmetic::dcr(Register::B, state),
|
|
0x0d => arithmetic::dcr(Register::C, state),
|
|
0x15 => arithmetic::dcr(Register::D, state),
|
|
0x1d => arithmetic::dcr(Register::E, state),
|
|
0x25 => arithmetic::dcr(Register::H, state),
|
|
0x2d => arithmetic::dcr(Register::L, state),
|
|
0x35 => arithmetic::dcr(Register::M, state),
|
|
0x3d => arithmetic::dcr(Register::A, state),
|
|
|
|
// DAD
|
|
0x09 => arithmetic::dad(Register::B, state),
|
|
0x19 => arithmetic::dad(Register::D, state),
|
|
0x29 => arithmetic::dad(Register::H, state),
|
|
0x39 => arithmetic::dad(Register::SP, state),
|
|
|
|
// INX
|
|
0x03 => arithmetic::inx(Register::B, state),
|
|
0x13 => arithmetic::inx(Register::D, state),
|
|
0x23 => arithmetic::inx(Register::H, state),
|
|
0x33 => arithmetic::inx(Register::SP, state),
|
|
|
|
// DCX
|
|
0x0b => arithmetic::dcx(Register::B, state),
|
|
0x1b => arithmetic::dcx(Register::D, state),
|
|
0x2b => arithmetic::dcx(Register::H, state),
|
|
0x3b => arithmetic::dcx(Register::SP, state),
|
|
|
|
0x80..=0x87 => arithmetic::add(register_from_num(instruction & 0xf), false, state), // ADD
|
|
0x88..=0x8f => arithmetic::add(register_from_num(instruction & 0xf), state.cc.c, state), // ADC
|
|
0xc6 => arithmetic::adi(next_byte(), false, state), // ADI
|
|
0xce => arithmetic::adi(next_byte(), state.cc.c, state), // ACI
|
|
|
|
_ => not_implemented(state),
|
|
}
|
|
|
|
state.pc += 1;
|
|
}
|
|
|
|
fn not_implemented(state: &EmulatorState) {
|
|
let instruction = state.memory[state.pc as usize];
|
|
panic!(
|
|
"Unimplemented instruction {:#02X} at {:#04X}",
|
|
instruction, state.pc
|
|
);
|
|
}
|