use core::fmt;
use core::ops::{Deref, DerefMut};
use core::marker::PhantomData;
#[cfg(feature = "snapshot")]
use serde::{Serialize, Deserialize};
pub mod audio;
pub mod serial128;
use spectrusty_core::clock::FTs;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum AyRegister {
ToneFineA = 0,
ToneCoarseA = 1,
ToneFineB = 2,
ToneCoarseB = 3,
ToneFineC = 4,
ToneCoarseC = 5,
NoisePeriod = 6,
MixerControl = 7,
AmpLevelA = 8,
AmpLevelB = 9,
AmpLevelC = 10,
EnvPerFine = 11,
EnvPerCoarse = 12,
EnvShape = 13,
IoA = 14,
IoB = 15,
}
pub const NUM_SOUND_GEN_REGISTERS: usize = 14;
const REG_MASKS: [u8;16] = [
0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0xff,
0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff
];
pub trait AyPortDecode: fmt::Debug {
const PORT_MASK: u16;
const PORT_SELECT: u16;
const PORT_DATA_READ: u16;
const PORT_DATA_WRITE: u16;
#[inline]
fn is_select(port: u16) -> bool {
port & Self::PORT_MASK == Self::PORT_SELECT & Self::PORT_MASK
}
#[inline]
fn is_data_read(port: u16) -> bool {
port & Self::PORT_MASK == Self::PORT_DATA_READ & Self::PORT_MASK
}
#[inline]
fn is_data_write(port: u16) -> bool {
port & Self::PORT_MASK == Self::PORT_DATA_WRITE & Self::PORT_MASK
}
#[inline]
fn write_ay_io<T,R,A,B>(
ay_io: &mut Ay3_891xIo<T,R,A,B>,
port: u16,
data: u8,
timestamp: T
) -> bool
where A: AyIoPort<Timestamp=T>,
B: AyIoPort<Timestamp=T>,
R: AyRegRecorder<Timestamp=T>
{
match port & Self::PORT_MASK {
p if p == Self::PORT_SELECT => {
ay_io.select_port_write(data);
true
}
p if p == Self::PORT_DATA_WRITE => {
ay_io.data_port_write(port, data, timestamp);
true
}
_ => false
}
}
}
#[derive(Clone, Copy, Default, Debug)]
pub struct Ay128kPortDecode;
impl AyPortDecode for Ay128kPortDecode {
const PORT_MASK : u16 = 0b11000000_00000010;
const PORT_SELECT : u16 = 0b11000000_00000000;
const PORT_DATA_READ : u16 = 0b11000000_00000000;
const PORT_DATA_WRITE: u16 = 0b10000000_00000000;
}
#[derive(Clone, Copy, Default, Debug)]
pub struct AyFullerBoxPortDecode;
impl AyPortDecode for AyFullerBoxPortDecode {
const PORT_MASK : u16 = 0x00ff;
const PORT_SELECT : u16 = 0x003f;
const PORT_DATA_READ : u16 = 0x003f;
const PORT_DATA_WRITE: u16 = 0x005f;
}
#[derive(Clone, Copy, Default, Debug)]
pub struct AyTC2068PortDecode;
impl AyPortDecode for AyTC2068PortDecode {
const PORT_MASK : u16 = 0x00ff;
const PORT_SELECT : u16 = 0x00f5;
const PORT_DATA_READ : u16 = 0x00f6;
const PORT_DATA_WRITE: u16 = 0x00f6;
}
#[derive(Clone, Copy, Debug)]
pub struct AyRegChange {
pub time: FTs,
pub reg: AyRegister,
pub val: u8
}
pub trait AyIoPort: fmt::Debug {
type Timestamp: Sized;
#[inline]
fn ay_io_reset(&mut self, _timestamp: Self::Timestamp) {}
#[inline]
fn ay_io_write(&mut self, _addr: u16, _data: u8, _timestamp: Self::Timestamp) {}
#[inline]
fn ay_io_read(&mut self, _addr: u16, _timestamp: Self::Timestamp) -> u8 { 0xff }
#[inline]
fn end_frame(&mut self, _timestamp: Self::Timestamp) {}
}
#[derive(Default, Clone, Copy, Debug)]
#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
pub struct AyIoNullPort<T>(PhantomData<T>);
pub trait AyRegRecorder {
type Timestamp;
fn record_ay_reg_change(&mut self, reg: AyRegister, val: u8, timestamp: Self::Timestamp);
fn clear_ay_reg_changes(&mut self);
}
pub type Ay3_8910Io<T,A=AyIoNullPort<T>,B=AyIoNullPort<T>> = Ay3_891xIo<T, AyRegVecRecorder<T>, A, B>;
pub type Ay3_8912Io<T,A> = Ay3_8910Io<T, A>;
pub type Ay3_8913Io<T> = Ay3_8910Io<T>;
#[derive(Default, Clone, Debug)]
#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "snapshot", serde(rename_all = "camelCase"))]
pub struct Ay3_891xIo<T, R, A, B> {
#[cfg_attr(feature = "snapshot", serde(skip))]
pub recorder: R,
#[cfg_attr(feature = "snapshot", serde(default))]
pub port_a: A,
#[cfg_attr(feature = "snapshot", serde(default))]
pub port_b: B,
regs: [u8; 16],
selected_reg: AyRegister,
#[cfg_attr(feature = "snapshot", serde(skip))]
_ts: PhantomData<T>
}
#[derive(Default, Clone, Debug)]
pub struct AyRegNullRecorder<T>(PhantomData<T>);
#[derive(Default, Clone, Debug)]
pub struct AyRegVecRecorder<T>(pub Vec<(T,AyRegister,u8)>);
impl<T,R,A,B> Ay3_891xIo<T,R,A,B>
where A: AyIoPort<Timestamp=T>,
B: AyIoPort<Timestamp=T>,
R: AyRegRecorder<Timestamp=T>
{
pub fn reset(&mut self, timestamp: T) where T: Copy {
self.regs = Default::default();
self.selected_reg = Default::default();
self.port_a.ay_io_reset(timestamp);
self.port_b.ay_io_reset(timestamp);
}
pub fn next_frame(&mut self, timestamp: T) where T: Copy {
self.recorder.clear_ay_reg_changes();
self.port_a.end_frame(timestamp);
self.port_b.end_frame(timestamp);
}
#[inline]
pub fn get(&self, reg: AyRegister) -> u8 {
let index = usize::from(reg);
self.regs[index]
}
#[inline]
pub fn registers(&self) -> &[u8;16] {
&self.regs
}
#[inline]
pub fn iter_regs<'a>(&'a self) -> impl Iterator<Item=(AyRegister, u8)> + 'a {
self.regs.iter().enumerate().map(|(n, val)| ((n as u8).into(), *val))
}
#[inline]
pub fn iter_sound_gen_regs<'a>(&'a self) -> impl Iterator<Item=(AyRegister, u8)> + 'a {
self.iter_regs().take(NUM_SOUND_GEN_REGISTERS)
}
#[inline]
pub fn set(&mut self, reg: AyRegister, val: u8) {
let index = usize::from(reg);
self.regs[index] = val & REG_MASKS[index];
}
#[inline]
pub fn is_ioa_input(&self) -> bool {
self.get(AyRegister::MixerControl) & 0x40 == 0
}
#[inline]
pub fn is_iob_input(&self) -> bool {
self.get(AyRegister::MixerControl) & 0x80 == 0
}
#[inline]
pub fn is_ioa_output(&self) -> bool {
!self.is_ioa_input()
}
#[inline]
pub fn is_iob_output(&self) -> bool {
!self.is_iob_input()
}
#[inline]
pub fn selected_register(&self) -> AyRegister {
self.selected_reg
}
#[inline]
pub fn select_port_write(&mut self, data: u8) {
self.selected_reg = AyRegister::from(data)
}
#[inline]
pub fn data_port_write(&mut self, port: u16, data: u8, timestamp: T) {
self.set(self.selected_reg, data); match self.selected_reg {
AyRegister::IoA => {
self.port_a.ay_io_write(port, data, timestamp)
}
AyRegister::IoB => {
self.port_b.ay_io_write(port, data, timestamp)
}
reg => self.recorder.record_ay_reg_change(reg, data, timestamp)
}
}
#[inline]
pub fn data_port_read(&mut self, port: u16, timestamp: T) -> u8 {
match self.selected_reg {
AyRegister::IoA => {
let port_input = self.port_a.ay_io_read(port, timestamp);
if self.is_ioa_input() {
port_input
}
else {
port_input & self.get(AyRegister::IoA)
}
}
AyRegister::IoB => {
let port_input = self.port_b.ay_io_read(port, timestamp);
if self.is_iob_input() {
port_input
}
else {
port_input & self.get(AyRegister::IoB)
}
}
reg => self.get(reg)
}
}
}
impl AyRegister {
pub fn enumerate() -> impl Iterator<Item=AyRegister> {
(0..15).map(AyRegister::from)
}
}
impl Default for AyRegister {
fn default() -> Self {
AyRegister::ToneFineA
}
}
impl From<u8> for AyRegister {
fn from(value: u8) -> Self {
unsafe { core::mem::transmute(value & 0x0F) }
}
}
macro_rules! impl_from_ay_reg {
($($ty:ty),*) => { $(
impl From<AyRegister> for $ty {
#[inline(always)]
fn from(reg: AyRegister) -> $ty {
reg as $ty
}
}
)* };
}
impl_from_ay_reg!(u8, u16, u32, u64, usize);
impl AyRegChange {
#[inline]
pub const fn new(time: FTs, reg: AyRegister, val: u8) -> Self {
AyRegChange { time, reg, val }
}
pub fn new_from_ts<T: Into<FTs>>(timestamp: T, reg: AyRegister, val: u8) -> Self {
let time = timestamp.into();
Self::new(time, reg, val)
}
}
impl<T: fmt::Debug> AyIoPort for AyIoNullPort<T> {
type Timestamp = T;
}
impl<T> AyRegRecorder for AyRegNullRecorder<T> {
type Timestamp = T;
#[inline]
fn record_ay_reg_change(&mut self, _reg: AyRegister, _val: u8, _timestamp: T) {}
#[inline]
fn clear_ay_reg_changes(&mut self) {}
}
impl<T> AyRegRecorder for AyRegVecRecorder<T> {
type Timestamp = T;
#[inline]
fn record_ay_reg_change(&mut self, reg: AyRegister, val: u8, timestamp: T) {
self.0.push((timestamp, reg, val));
}
#[inline]
fn clear_ay_reg_changes(&mut self) {
self.0.clear()
}
}
impl<T: Into<FTs>> AyRegVecRecorder<T> {
pub fn drain_ay_reg_changes<'a>(&'a mut self) -> impl Iterator<Item=AyRegChange> + 'a {
self.0.drain(..).map(|(timestamp,reg,val)| AyRegChange::new_from_ts(timestamp,reg,val))
}
}
impl<T> Deref for AyRegVecRecorder<T> {
type Target = Vec<(T,AyRegister,u8)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for AyRegVecRecorder<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}