invadeez/src/emulator/main.rs
Martin Löffler ed05dd5d30
accumulator rotate instructions
that's the rest of the arithmetics
2023-01-26 04:51:55 +01:00

158 lines
5.3 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),
// Accumulator rotates
0x07 => arithmetic::rlc(state),
0x0f => arithmetic::rrc(state),
0x17 => arithmetic::ral(state),
0x1f => arithmetic::rar(state),
// Carry and complements
0x27 => panic!("Auxiliary Carry not implemented, unable to execute DAA instruction"),
0x2f => state.a = !state.a, // CMA
0x37 => state.cc.c = true, // STC
0x3f => state.cc.c = !state.cc.c, // CMC
0x80..=0x87 => arithmetic::add_reg(register_from_num(instruction & 0x7), false, state), // ADD
0x88..=0x8f => arithmetic::add_reg(register_from_num(instruction & 0x7), state.cc.c, state), // ADC
0xc6 => arithmetic::add(next_byte(), false, state), // ADI
0xce => arithmetic::add(next_byte(), state.cc.c, state), // ACI
0x90..=0x97 => arithmetic::sub_reg(register_from_num(instruction & 0x7), false, state), // SUB
0x98..=0x9f => arithmetic::sub_reg(register_from_num(instruction & 0x7), state.cc.c, state), // SBB
0xd6 => arithmetic::sub(next_byte(), false, state), // SUI
0xde => arithmetic::sub(next_byte(), state.cc.c, state), // SBI
0xa0..=0xa7 => arithmetic::and_reg(register_from_num(instruction & 0x7), state), // ANA
0xa8..=0xaf => arithmetic::xor_reg(register_from_num(instruction & 0x7), state), // XRA
0xb0..=0xb7 => arithmetic::or_reg(register_from_num(instruction & 0x7), state), // ORA
0xb8..=0xbf => arithmetic::cmp_reg(register_from_num(instruction & 0x7), state), // CMP
0xe6 => arithmetic::and(next_byte(), state), // ANI
0xee => arithmetic::xor(next_byte(), state), // XRI
0xf6 => arithmetic::or(next_byte(), state), // ORI
0xfe => arithmetic::cmp(next_byte(), state), // CPI
_ => 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
);
}