#![feature(exclusive_range_pattern)] use clap::Parser; use std::{fs, io}; /// Simple program to greet a person #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { /// ROM path #[arg(short, long)] rom: String, /// BootROM path #[arg(short, long)] bootrom: String, } type Address = u16; type ROM = Vec; #[derive(Clone, Copy)] struct Inner { left: u8, right: u8, } union Register { as_u8s: Inner, as_u16: u16, } struct Memory { rom: ROM, vram: [u8; 8192], ram: [u8; 8192], } impl Memory { fn init(rom: ROM) -> Self { Self { rom, vram: [0x0; 8192], ram: [0x0; 8192], } } fn get(&self, address: Address) -> u8 { match address { 0x0..0x8000 => { // rom access // todo - switchable rom banks return self.rom[address as usize]; } 0x8000..0xA000 => { return self.vram[(address - 0x8000) as usize]; } 0xA000..0xC000 => { panic!("switchable ram bank"); } 0xC000..0xE000 => { return self.ram[(address - 0xC000) as usize]; } 0xE000..0xFE00 => { return self.ram[(address - 0xE000) as usize]; } 0xFE00..0xFEA0 => { panic!("sprite attrib memory"); } 0xFEA0..0xFF00 => { panic!("empty") } 0xFF00..0xFF4C => { panic!("I/O"); } 0xFF4C..0xFF80 => { panic!("empty"); } 0xFF80..0xFFFF => { panic!("internal ram"); } 0xFFFF => { panic!("interrupt enable register"); } } } } struct State { af: Register, bc: Register, de: Register, hl: Register, sp: Register, pc: Register, } impl Default for State { fn default() -> Self { // default post-bootrom values Self { af: Register { as_u16: 0x01B0 }, bc: Register { as_u16: 0x0013 }, de: Register { as_u16: 0x00D8 }, hl: Register { as_u16: 0x014D }, sp: Register { as_u16: 0xFFFE }, pc: Register { as_u16: 0x0100 }, } } } struct CPU { memory: Memory, state: State, } impl CPU { fn exec_next(&mut self) -> u8 { let opcode = self.next_opcode(); match opcode { 0x0 => { // noop } 0x01 => { self.state.bc = self.ld_immediate_word(); } 0x11 => { self.state.de = self.ld_immediate_word(); } 0x21 => { self.state.hl = self.ld_immediate_word(); } 0x2C => { unsafe { self.state.hl.as_u8s.right += 1; }; } 0x66 => { unsafe { self.state.hl.as_u8s.left = self.memory.get(self.state.hl.as_u16); }; } 0xC3 => { self.state.pc = self.ld_immediate_word(); } _ => { panic!("unimplemented opcode: {:#X}", opcode); } }; return opcode; } fn next_opcode(&mut self) -> u8 { unsafe { let opcode = self.memory.get(self.state.pc.as_u16); self.state.pc.as_u16 += 0x1; return opcode; }; } fn ld_immediate_word(&mut self) -> Register { Register { as_u8s: Inner { left: self.next_opcode(), right: self.next_opcode(), }, } } } fn main() { let args = Args::parse(); let rom: ROM = fs::read(args.rom).expect("Could not load ROM"); let _bootrom: ROM = fs::read(args.bootrom).expect("Could not load BootROM"); let mut cpu = CPU { memory: Memory::init(rom), state: State::default(), }; loop { cpu.exec_next(); } } #[allow(dead_code)] fn pause() { io::stdin().read_line(&mut String::new()).unwrap(); }