#![feature(exclusive_range_pattern)] use clap::Parser; use std::fs; /// 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, } type Register = u16; type ROM = Vec; 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: u16) -> 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 => { panic!("ram mirror") } 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"); } } } } #[derive(Debug)] 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: 0x01B0, bc: 0x0013, de: 0x00D8, hl: 0x014D, sp: 0xFFFE, pc: 0x0100, } } } struct CPU { memory: Memory, state: State, } impl CPU { fn execute(&mut self, opcode: u8) { match opcode { 0 => { // noop } _ => { panic!("unimplemented opcode: {:#X}", opcode); } }; } } fn main() { let args = Args::parse(); let rom: ROM = fs::read(args.rom).expect("Could not load ROM"); let mut cpu = CPU { memory: Memory::init(rom), state: State::default(), }; loop { let op = cpu.memory.get(cpu.state.pc); cpu.state.pc += 1; cpu.execute(op); } }