#![feature(exclusive_range_pattern)] mod processor; use clap::Parser; use processor::CPU; 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, /// Just run BootROM #[arg(long)] run_bootrom: bool, } type Address = u16; type ROM = Vec; #[derive(Clone, Copy)] struct Inner { left: u8, right: u8, } #[derive(Clone, Copy)] union Register { as_u8s: Inner, as_u16: u16, } pub struct Memory { rom: ROM, vram: [u8; 8192], ram: [u8; 8192], switchable_ram: [u8; 8192], cpu_ram: [u8; 128], } impl Memory { fn init(rom: ROM) -> Self { Self { rom, vram: [0x0; 8192], ram: [0x0; 8192], switchable_ram: [0x0; 8192], cpu_ram: [0x0; 128], } } 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 => { return self.switchable_ram[(address - 0xA000) as usize]; } 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 => { return self.cpu_ram[(address - 0xFF80) as usize]; } 0xFFFF => { panic!("interrupt enable register"); } } } fn set(&mut self, address: Address, data: u8) { match address { 0x0..0x8000 => { // change this with MBC code... println!("tried to write {:#5X} at {:#X}", data, address); } 0x8000..0xA000 => { self.vram[(address - 0x8000) as usize] = data; } 0xA000..0xC000 => { self.switchable_ram[(address - 0xA000) as usize] = data; } 0xC000..0xE000 => { self.ram[(address - 0xC000) as usize] = data; } 0xE000..0xFE00 => { self.ram[(address - 0xE000) as usize] = data; } 0xFE00..0xFEA0 => { panic!("sprite attrib memory"); } 0xFEA0..0xFF00 => { panic!("empty") } 0xFF00..0xFF4C => { panic!("I/O"); } 0xFF4C..0xFF80 => { panic!("empty"); } 0xFF80..0xFFFF => { self.cpu_ram[(address - 0xFF80) as usize] = data; } 0xFFFF => { panic!("interrupt enable register"); } } } } pub 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 }, } } } 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 state = State::default(); let run_rom = if args.run_bootrom { state.pc = Register { as_u16: 0x0 }; bootrom } else { rom }; let mut cpu = CPU { memory: Memory::init(run_rom), state, }; loop { for _ in 0..10 { cpu.exec_next(); } pause(); } } #[allow(dead_code)] fn pause() { io::stdin().read_line(&mut String::new()).unwrap(); }