1use core::fmt;
14use core::ops::{Deref, DerefMut};
15use core::marker::PhantomData;
16
17#[cfg(feature = "snapshot")]
18use serde::{Serialize, Deserialize};
19
20pub mod audio;
21pub mod serial128;
22
23use spectrusty_core::clock::FTs;
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
27#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
28#[repr(u8)]
29pub enum AyRegister {
30 ToneFineA = 0,
31 ToneCoarseA = 1,
32 ToneFineB = 2,
33 ToneCoarseB = 3,
34 ToneFineC = 4,
35 ToneCoarseC = 5,
36 NoisePeriod = 6,
37 MixerControl = 7,
38 AmpLevelA = 8,
39 AmpLevelB = 9,
40 AmpLevelC = 10,
41 EnvPerFine = 11,
42 EnvPerCoarse = 12,
43 EnvShape = 13,
44 IoA = 14,
45 IoB = 15,
46}
47
48pub const NUM_SOUND_GEN_REGISTERS: usize = 14;
49
50const REG_MASKS: [u8;16] = [
51 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0xff,
52 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff
53];
54
55pub trait AyPortDecode: fmt::Debug {
57 const PORT_MASK: u16;
59 const PORT_SELECT: u16;
61 const PORT_DATA_READ: u16;
63 const PORT_DATA_WRITE: u16;
65 #[inline]
67 fn is_select(port: u16) -> bool {
68 port & Self::PORT_MASK == Self::PORT_SELECT & Self::PORT_MASK
69 }
70 #[inline]
72 fn is_data_read(port: u16) -> bool {
73 port & Self::PORT_MASK == Self::PORT_DATA_READ & Self::PORT_MASK
74 }
75 #[inline]
77 fn is_data_write(port: u16) -> bool {
78 port & Self::PORT_MASK == Self::PORT_DATA_WRITE & Self::PORT_MASK
79 }
80 #[inline]
82 fn write_ay_io<T,R,A,B>(
83 ay_io: &mut Ay3_891xIo<T,R,A,B>,
84 port: u16,
85 data: u8,
86 timestamp: T
87 ) -> bool
88 where A: AyIoPort<Timestamp=T>,
89 B: AyIoPort<Timestamp=T>,
90 R: AyRegRecorder<Timestamp=T>
91 {
92 match port & Self::PORT_MASK {
93 p if p == Self::PORT_SELECT => {
94 ay_io.select_port_write(data);
95 true
96 }
97 p if p == Self::PORT_DATA_WRITE => {
98 ay_io.data_port_write(port, data, timestamp);
99 true
100 }
101 _ => false
102 }
103 }
104}
105
106#[derive(Clone, Copy, Default, Debug)]
108pub struct Ay128kPortDecode;
109impl AyPortDecode for Ay128kPortDecode {
110 const PORT_MASK : u16 = 0b1100_0000_0000_0010;
111 const PORT_SELECT : u16 = 0b1100_0000_0000_0000;
112 const PORT_DATA_READ : u16 = 0b1100_0000_0000_0000;
113 const PORT_DATA_WRITE: u16 = 0b1000_0000_0000_0000;
114}
115
116#[derive(Clone, Copy, Default, Debug)]
118pub struct AyFullerBoxPortDecode;
119impl AyPortDecode for AyFullerBoxPortDecode {
120 const PORT_MASK : u16 = 0x00ff;
121 const PORT_SELECT : u16 = 0x003f;
122 const PORT_DATA_READ : u16 = 0x003f;
123 const PORT_DATA_WRITE: u16 = 0x005f;
124}
125
126#[derive(Clone, Copy, Default, Debug)]
128pub struct AyTC2068PortDecode;
129impl AyPortDecode for AyTC2068PortDecode {
130 const PORT_MASK : u16 = 0x00ff;
131 const PORT_SELECT : u16 = 0x00f5;
132 const PORT_DATA_READ : u16 = 0x00f6;
133 const PORT_DATA_WRITE: u16 = 0x00f6;
134}
135
136#[derive(Clone, Copy, Debug)]
141pub struct AyRegChange {
142 pub time: FTs,
144 pub reg: AyRegister,
146 pub val: u8
150}
151
152pub trait AyIoPort {
154 type Timestamp: Sized;
155 #[inline]
157 fn ay_io_reset(&mut self, _timestamp: Self::Timestamp) {}
158 #[inline]
160 fn ay_io_write(&mut self, _addr: u16, _data: u8, _timestamp: Self::Timestamp) {}
161 #[inline]
163 fn ay_io_read(&mut self, _addr: u16, _timestamp: Self::Timestamp) -> u8 { 0xff }
164 #[inline]
167 fn end_frame(&mut self, _timestamp: Self::Timestamp) {}
168}
169
170#[derive(Default, Clone, Copy, Debug)]
172#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
173pub struct AyIoNullPort<T>(PhantomData<T>);
174
175pub trait AyRegRecorder {
177 type Timestamp;
178 fn record_ay_reg_change(&mut self, reg: AyRegister, val: u8, timestamp: Self::Timestamp);
182 fn clear_ay_reg_changes(&mut self);
184}
185
186pub type Ay3_8910Io<T,A=AyIoNullPort<T>,B=AyIoNullPort<T>> = Ay3_891xIo<T, AyRegVecRecorder<T>, A, B>;
188pub type Ay3_8912Io<T,A> = Ay3_8910Io<T, A>;
190pub type Ay3_8913Io<T> = Ay3_8910Io<T>;
192
193#[derive(Default, Clone, Debug)]
202#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
203#[cfg_attr(feature = "snapshot", serde(rename_all = "camelCase"))]
204pub struct Ay3_891xIo<T, R, A, B> {
205 #[cfg_attr(feature = "snapshot", serde(skip))]
208 pub recorder: R,
209 #[cfg_attr(feature = "snapshot", serde(default))]
211 pub port_a: A,
212 #[cfg_attr(feature = "snapshot", serde(default))]
214 pub port_b: B,
215 regs: [u8; 16],
216 selected_reg: AyRegister,
217 #[cfg_attr(feature = "snapshot", serde(skip))]
218 _ts: PhantomData<T>
219}
220
221#[derive(Default, Clone, Debug)]
225pub struct AyRegNullRecorder<T>(PhantomData<T>);
226
227#[derive(Default, Clone, Debug)]
229pub struct AyRegVecRecorder<T>(pub Vec<(T,AyRegister,u8)>);
230
231impl<T,R,A,B> Ay3_891xIo<T,R,A,B>
232where A: AyIoPort<Timestamp=T>,
233 B: AyIoPort<Timestamp=T>,
234 R: AyRegRecorder<Timestamp=T>
235{
236 pub fn reset(&mut self, timestamp: T) where T: Copy {
241 self.regs = Default::default();
242 self.selected_reg = Default::default();
243 self.port_a.ay_io_reset(timestamp);
244 self.port_b.ay_io_reset(timestamp);
245 }
246 pub fn next_frame(&mut self, timestamp: T) where T: Copy {
249 self.recorder.clear_ay_reg_changes();
250 self.port_a.end_frame(timestamp);
251 self.port_b.end_frame(timestamp);
252 }
253 #[inline]
255 pub fn get(&self, reg: AyRegister) -> u8 {
256 let index = usize::from(reg);
257 self.regs[index]
258 }
259 #[inline]
261 pub fn registers(&self) -> &[u8;16] {
262 &self.regs
263 }
264 #[inline]
266 pub fn iter_regs(&'_ self) -> impl Iterator<Item=(AyRegister, u8)> + '_ {
267 self.regs.iter().enumerate().map(|(n, val)| ((n as u8).into(), *val))
268 }
269 #[inline]
272 pub fn iter_sound_gen_regs(&'_ self) -> impl Iterator<Item=(AyRegister, u8)> + '_ {
273 self.iter_regs().take(NUM_SOUND_GEN_REGISTERS)
274 }
275 #[inline]
277 pub fn set(&mut self, reg: AyRegister, val: u8) {
278 let index = usize::from(reg);
279 self.regs[index] = val & REG_MASKS[index];
280 }
281 #[inline]
283 pub fn is_ioa_input(&self) -> bool {
284 self.get(AyRegister::MixerControl) & 0x40 == 0
285 }
286 #[inline]
288 pub fn is_iob_input(&self) -> bool {
289 self.get(AyRegister::MixerControl) & 0x80 == 0
290 }
291 #[inline]
293 pub fn is_ioa_output(&self) -> bool {
294 !self.is_ioa_input()
295 }
296 #[inline]
298 pub fn is_iob_output(&self) -> bool {
299 !self.is_iob_input()
300 }
301 #[inline]
303 pub fn selected_register(&self) -> AyRegister {
304 self.selected_reg
305 }
306 #[inline]
310 pub fn select_port_write(&mut self, data: u8) {
311 self.selected_reg = AyRegister::from(data)
312 }
313 #[inline]
318 pub fn data_port_write(&mut self, port: u16, data: u8, timestamp: T) {
319 self.set(self.selected_reg, data); match self.selected_reg {
321 AyRegister::IoA => {
322 self.port_a.ay_io_write(port, data, timestamp)
323 }
324 AyRegister::IoB => {
325 self.port_b.ay_io_write(port, data, timestamp)
326 }
327 reg => self.recorder.record_ay_reg_change(reg, data, timestamp)
328 }
329 }
330 #[inline]
334 pub fn data_port_read(&mut self, port: u16, timestamp: T) -> u8 {
335 match self.selected_reg {
336 AyRegister::IoA => {
337 let port_input = self.port_a.ay_io_read(port, timestamp);
338 if self.is_ioa_input() {
339 port_input
340 }
341 else {
342 port_input & self.get(AyRegister::IoA)
343 }
344 }
345 AyRegister::IoB => {
346 let port_input = self.port_b.ay_io_read(port, timestamp);
347 if self.is_iob_input() {
348 port_input
349 }
350 else {
351 port_input & self.get(AyRegister::IoB)
352 }
353 }
354 reg => self.get(reg)
355 }
356 }
357}
358
359impl AyRegister {
360 pub fn enumerate() -> impl Iterator<Item=AyRegister> {
362 (0..15).map(AyRegister::from)
363 }
364}
365
366impl Default for AyRegister {
367 fn default() -> Self {
368 AyRegister::ToneFineA
369 }
370}
371
372impl From<u8> for AyRegister {
373 fn from(value: u8) -> Self {
374 unsafe { core::mem::transmute(value & 0x0F) }
375 }
376}
377
378macro_rules! impl_from_ay_reg {
379 ($($ty:ty),*) => { $(
380 impl From<AyRegister> for $ty {
381 #[inline(always)]
382 fn from(reg: AyRegister) -> $ty {
383 reg as $ty
384 }
385 }
386 )* };
387}
388impl_from_ay_reg!(u8, u16, u32, u64, usize);
389
390impl AyRegChange {
391 #[inline]
393 pub const fn new(time: FTs, reg: AyRegister, val: u8) -> Self {
394 AyRegChange { time, reg, val }
395 }
396 pub fn new_from_ts<T: Into<FTs>>(timestamp: T, reg: AyRegister, val: u8) -> Self {
398 let time = timestamp.into();
399 Self::new(time, reg, val)
400 }
401}
402
403impl<T> AyIoPort for AyIoNullPort<T> {
404 type Timestamp = T;
405}
406
407impl<T> AyRegRecorder for AyRegNullRecorder<T> {
408 type Timestamp = T;
409 #[inline]
410 fn record_ay_reg_change(&mut self, _reg: AyRegister, _val: u8, _timestamp: T) {}
411 #[inline]
412 fn clear_ay_reg_changes(&mut self) {}
413}
414
415impl<T> AyRegRecorder for AyRegVecRecorder<T> {
416 type Timestamp = T;
417 #[inline]
418 fn record_ay_reg_change(&mut self, reg: AyRegister, val: u8, timestamp: T) {
419 self.0.push((timestamp, reg, val));
420 }
421 #[inline]
422 fn clear_ay_reg_changes(&mut self) {
423 self.0.clear()
424 }
425}
426
427impl<T: Into<FTs>> AyRegVecRecorder<T> {
428 pub fn drain_ay_reg_changes(&'_ mut self) -> impl Iterator<Item=AyRegChange> + '_ {
430 self.0.drain(..).map(|(timestamp,reg,val)| AyRegChange::new_from_ts(timestamp,reg,val))
431 }
432}
433
434impl<T> Deref for AyRegVecRecorder<T> {
435 type Target = Vec<(T,AyRegister,u8)>;
436 fn deref(&self) -> &Self::Target {
437 &self.0
438 }
439}
440
441impl<T> DerefMut for AyRegVecRecorder<T> {
442 fn deref_mut(&mut self) -> &mut Self::Target {
443 &mut self.0
444 }
445}