use instant::Duration;
use crate::cpu::{
mos6502::{Mos6502, Mos6502Variant},
Cpu,
};
use crate::memory::{ActiveInterrupt, Memory};
use crate::memory::{BlockMemory, BranchMemory};
use crate::platform::{PlatformProvider, WindowConfig};
use crate::roms::RomFile;
use crate::systems::{BuildableSystem, System};
use std::io::Write;
use std::sync::Arc;
struct MappedStdIO {
provider: Arc<dyn PlatformProvider>,
}
impl MappedStdIO {
pub fn new(provider: Arc<dyn PlatformProvider>) -> Self {
Self { provider }
}
}
impl Memory for MappedStdIO {
fn read(&mut self, address: u16) -> u8 {
let input = self.provider.input();
match address & 0x03 {
0x00 => input.trim().parse().expect("Invalid input for u8"),
0x01 => {
let char = input.chars().next().expect("String is empty");
((char as u32) & 0xFF) as u8
}
0x02 => u8::from_str_radix(input.trim(), 16).expect("Invalid input for u8"),
0x03 => panic!("Invalid address for MappedStdIO"),
_ => unreachable!("Invalid address"),
}
}
fn write(&mut self, address: u16, value: u8) {
match address & 0x03 {
0x00 => self.provider.print(&format!("{value}\n")),
0x01 => self.provider.print(&format!("{}\n", value as char)),
0x02 => self.provider.print(&format!("{value:02X}\n")),
0x03 => {
print!("{}", value as char);
std::io::stdout().flush().unwrap();
}
_ => unreachable!(),
}
}
fn reset(&mut self) {}
fn poll(&mut self, _cycles_since_poll: u64, _total_cycle_count: u64) -> ActiveInterrupt {
ActiveInterrupt::None
}
}
impl BuildableSystem<RomFile, ()> for BasicSystem {
fn build(rom: RomFile, _config: (), platform: Arc<dyn PlatformProvider>) -> Box<dyn System> {
let ram = BlockMemory::ram(0x4000);
let io = MappedStdIO::new(platform);
let rom = BlockMemory::from_file(0x8000, rom);
let memory = BranchMemory::new()
.map(0x0000, ram)
.map(0x4000, io)
.map(0x8000, rom);
let cpu = Mos6502::new(memory, Mos6502Variant::NMOS);
Box::new(BasicSystem { cpu })
}
}
pub struct BasicSystem {
cpu: Mos6502,
}
impl System for BasicSystem {
fn get_cpu_mut(&mut self) -> Box<&mut dyn Cpu> {
Box::new(&mut self.cpu)
}
fn tick(&mut self) -> Duration {
Duration::from_secs_f64(1.0 / 20_000.0) * self.cpu.tick().into()
}
fn reset(&mut self) {
self.cpu.reset();
}
fn render(&mut self, _framebuffer: &mut [u8], _config: WindowConfig) {}
}