use instant::Duration;
use crate::cpu::{
mos6502::{MemoryIO, Mos6502, Mos6502Variant},
Cpu,
};
use crate::keyboard::KeyPosition;
use crate::memory::{ActiveInterrupt, BlockMemory, BranchMemory, Memory};
use crate::platform::{Color, PlatformProvider, WindowConfig};
use crate::roms::RomFile;
use crate::systems::{BuildableSystem, System};
use std::sync::Arc;
const WIDTH: u32 = 32;
const SCALE: u32 = 8;
struct EasyIO {
platform: Arc<dyn PlatformProvider>,
}
impl EasyIO {
pub fn new(platform: Arc<dyn PlatformProvider>) -> Self {
Self { platform }
}
}
impl Memory for EasyIO {
fn read(&mut self, address: u16) -> u8 {
match address % 2 {
0 => self.platform.random(),
_ => {
let state = self.platform.get_key_state();
if state.is_pressed(KeyPosition::W) {
b'W'
} else if state.is_pressed(KeyPosition::A) {
b'A'
} else if state.is_pressed(KeyPosition::S) {
b'S'
} else if state.is_pressed(KeyPosition::D) {
b'D'
} else {
0
}
}
}
}
fn write(&mut self, _address: u16, _value: u8) {}
fn reset(&mut self) {}
fn poll(&mut self, _cycles_since_poll: u64, _total_cycle_count: u64) -> ActiveInterrupt {
ActiveInterrupt::None
}
}
impl BuildableSystem<RomFile, ()> for Easy6502System {
fn build(rom: RomFile, _config: (), platform: Arc<dyn PlatformProvider>) -> Box<dyn System> {
platform.request_window(WindowConfig::new(WIDTH, WIDTH, SCALE as f64));
let zero_page = BlockMemory::ram(0x0100);
let io = EasyIO::new(platform.clone());
let stack_ram = BlockMemory::ram(0x0100);
let vram = BlockMemory::ram(0x0400);
let high_ram = BlockMemory::ram(0x7A00);
let rom = BlockMemory::from_file(0x8000, rom);
let memory = BranchMemory::new()
.map(0x0000, zero_page)
.map(0x00fe, io)
.map(0x0100, stack_ram)
.map(0x0200, vram)
.map(0x0600, high_ram)
.map(0x8000, rom);
let cpu = Mos6502::new(memory, Mos6502Variant::NMOS);
Box::new(Easy6502System { cpu })
}
}
pub struct Easy6502System {
cpu: Mos6502,
}
impl System for Easy6502System {
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) {
for y in 0..WIDTH {
for x in 0..WIDTH {
let index = (y * WIDTH + x) as u16;
let color = self.cpu.read(0x0200 + index);
let color = match color & 0x0F {
0 => Color::new(0x00, 0x00, 0x00),
1 => Color::new(0xFF, 0xFF, 0xFF),
2 => Color::new(0x88, 0x00, 0x00),
3 => Color::new(0xAA, 0xFF, 0xEE),
4 => Color::new(0xCC, 0x44, 0xCC),
5 => Color::new(0x00, 0xCC, 0x55),
6 => Color::new(0x00, 0x00, 0xAA),
7 => Color::new(0xEE, 0xEE, 0x77),
8 => Color::new(0xDD, 0x88, 0x55),
9 => Color::new(0x66, 0x44, 0x00),
10 => Color::new(0xFF, 0x77, 0x77),
11 => Color::new(0x33, 0x33, 0x33),
12 => Color::new(0x77, 0x77, 0x77),
13 => Color::new(0xAA, 0xFF, 0x66),
14 => Color::new(0x00, 0x88, 0xFF),
15 => Color::new(0xBB, 0xBB, 0xBB),
_ => Color::new(0x00, 0x00, 0x00),
};
let index = ((y * config.width + x) * 4) as usize;
let pixel = &mut framebuffer[index..(index + 4)];
pixel.copy_from_slice(&color.to_rgba());
}
}
}
}