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 ); }