use iz80::Machine;
use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;
use sha2::{Digest, Sha256};
use super::chips::kr580vg75::Kr580Vg75;
use super::chips::kr580vi53::Kr580Vi53;
use super::chips::kr580vt57::Kr580Vt57;
use super::chips::kr580vv55a::Kr580Vv55a;
use super::peripherals::UserPeripheral;
use super::peripherals::keyboard::Keyboard;
pub mod memory_map {
pub const RAM_START: u16 = 0x0000;
pub const RAM_END: u16 = 0xEBFF;
pub const PIT_BASE: u16 = 0xEC00;
pub const PIT_END: u16 = 0xECFF;
pub const PPI_SYS_BASE: u16 = 0xED00;
pub const PPI_SYS_END: u16 = 0xEDFF;
pub const PPI_USR_BASE: u16 = 0xEE00;
pub const PPI_USR_END: u16 = 0xEEFF;
pub const CRTC_BASE: u16 = 0xEF00;
pub const CRTC_END: u16 = 0xEFFF;
pub const DMA_ROM_BASE: u16 = 0xF000;
pub const DMA_ROM_END: u16 = 0xFFFF;
}
fn serialize_ram_hash<S: serde::Serializer>(
ram: &[u8; 0x10000],
serializer: S,
) -> Result<S::Ok, S::Error> {
let hash = Sha256::digest(ram);
serializer.serialize_str(&hex::encode(hash))
}
#[derive(Serialize, Deserialize)]
pub struct FontBanks {
#[serde(with = "BigArray")]
pub rows: [bool; 64],
pub previous_row: usize,
}
impl Default for FontBanks {
fn default() -> Self {
Self {
rows: [false; 64],
previous_row: 0,
}
}
}
#[derive(Serialize)]
pub struct Bus {
#[serde(serialize_with = "serialize_ram_hash", rename = "ram_hash")]
pub(crate) ram: Box<[u8; 0x10000]>,
#[serde(skip)]
pub(crate) monitor_rom: Vec<u8>,
pub(crate) vi53: Kr580Vi53,
pub(crate) vt57: Kr580Vt57,
pub(crate) vg75: Kr580Vg75,
pub(crate) sys_vv55: Kr580Vv55a,
pub(crate) user_vv55: Kr580Vv55a,
pub(crate) keyboard: Keyboard,
pub(crate) user_slot: UserPeripheral,
pub(crate) font_banks: FontBanks,
#[serde(skip)]
pub(crate) current_cycle: u64,
}
impl Bus {
pub fn new(monitor_rom: Vec<u8>) -> Self {
Self {
ram: vec![0; 0x10000].into_boxed_slice().try_into().unwrap(),
monitor_rom,
vi53: Kr580Vi53::new(),
vt57: Kr580Vt57::new(),
vg75: Kr580Vg75::new(),
sys_vv55: Kr580Vv55a::new(),
user_vv55: Kr580Vv55a::new(),
keyboard: Keyboard::new(),
user_slot: UserPeripheral::None,
font_banks: FontBanks::default(),
current_cycle: 0,
}
}
}
impl Machine for Bus {
fn peek(&mut self, addr: u16) -> u8 {
match addr {
memory_map::RAM_START..=memory_map::RAM_END => self.ram[addr as usize],
memory_map::PIT_BASE..=memory_map::PIT_END => self.vi53.read(addr),
memory_map::PPI_SYS_BASE..=memory_map::PPI_SYS_END => {
let kbd_mask = self.sys_vv55.peripheral_read_a();
let (kbd_res, port_c_in) = self.keyboard.read_matrix(kbd_mask);
self.sys_vv55.peripheral_write_b(kbd_res);
self.sys_vv55.peripheral_write_c(port_c_in);
self.sys_vv55.cpu_read(addr)
}
memory_map::PPI_USR_BASE..=memory_map::PPI_USR_END => {
let port_a_in = self.user_slot.read_port_a();
self.user_vv55.peripheral_write_a(port_a_in);
self.user_vv55.cpu_read(addr)
}
memory_map::CRTC_BASE..=memory_map::CRTC_END => self.vg75.read(addr),
memory_map::DMA_ROM_BASE..=memory_map::DMA_ROM_END => {
let idx = (addr - memory_map::DMA_ROM_BASE) as usize;
if !self.monitor_rom.is_empty() {
self.monitor_rom[idx % self.monitor_rom.len()]
} else {
0xFF
}
}
}
}
fn poke(&mut self, addr: u16, val: u8) {
match addr {
memory_map::RAM_START..=memory_map::RAM_END => self.ram[addr as usize] = val,
memory_map::PIT_BASE..=memory_map::PIT_END => self.vi53.write(addr, val),
memory_map::PPI_SYS_BASE..=memory_map::PPI_SYS_END => {
self.sys_vv55.cpu_write(addr, val);
}
memory_map::PPI_USR_BASE..=memory_map::PPI_USR_END => {
self.user_vv55.cpu_write(addr, val);
let port_a = self.user_vv55.peripheral_read_a();
let port_b = self.user_vv55.peripheral_read_b();
let port_c = self.user_vv55.peripheral_read_c();
if self
.user_slot
.update(port_a, port_b, port_c, self.current_cycle)
{
self.user_vv55.peripheral_write_c(!0x40);
self.user_vv55.peripheral_write_c(0xFF);
}
}
memory_map::CRTC_BASE..=memory_map::CRTC_END => self.vg75.write(addr, val),
memory_map::DMA_ROM_BASE..=memory_map::DMA_ROM_END => self.vt57.write(addr, val),
}
}
#[inline]
fn port_in(&mut self, port: u16) -> u8 {
let lo = port as u8;
let addr = u16::from_le_bytes([lo, lo]);
self.peek(addr)
}
#[inline]
fn port_out(&mut self, port: u16, val: u8) {
let lo = port as u8;
let addr = u16::from_le_bytes([lo, lo]);
self.poke(addr, val);
}
}