1use core::num::NonZeroU16;
10use core::marker::PhantomData;
11use core::num::Wrapping;
12
13use crate::z80emu::{
14 Cpu, Clock, Io, Memory, CpuDebug, CpuDebugFn, BreakCause,
15 opconsts,
16 host::{TsCounter, Result, cycles::M1_CYCLE_TS}
17};
18#[cfg(feature = "snapshot")]
19use serde::{Serialize, Deserialize};
20
21use crate::audio::*;
22use crate::peripherals::ay::{audio::*, Ay3_8913Io, AyPortDecode, AyRegRecorder};
23use crate::clock::{FTs, FTsData2};
24use crate::memory::{ZxMemory, Memory64k};
25use crate::bus::{BusDevice, NullDevice};
26use crate::chip::{
27 FrameState, ControlUnit, ZxSpectrum128Config, HostConfig,
28 nanos_from_frame_tc_cpu_hz
29};
30
31#[derive(Clone)]
32#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
33#[cfg_attr(feature = "snapshot", serde(rename_all = "camelCase"))]
34pub struct AyPlayer<P> {
35 pub frames: Wrapping<u64>,
36 pub tsc: TsCounter<FTs>,
37 pub memory: Memory64k,
38 pub ay_sound: Ay3_891xAudio,
39 pub ay_io: Ay3_8913Io<FTs>,
40 #[cfg_attr(feature = "snapshot", serde(skip))]
41 pub earmic_changes: Vec<FTsData2>,
42 pub last_earmic: u8,
43 pub prev_earmic: u8,
44 cpu_rate: u32,
45 frame_tstates: FTs,
46 bus: NullDevice<FTs>,
47 #[cfg_attr(feature = "snapshot", serde(skip))]
48 _port_decode: PhantomData<P>
49}
50
51impl<P> Default for AyPlayer<P> {
52 fn default() -> Self {
53 AyPlayer {
54 frames: Wrapping(0),
55 tsc: TsCounter::default(),
56 memory: Memory64k::default(),
57 ay_sound: Ay3_891xAudio::default(),
58 ay_io: Ay3_8913Io::default(),
59 earmic_changes: Vec::new(),
60 last_earmic: 3,
61 prev_earmic: 3,
62 cpu_rate: ZxSpectrum128Config::CPU_HZ,
63 frame_tstates: ZxSpectrum128Config::FRAME_TSTATES,
64 bus: NullDevice::default(),
65 _port_decode: PhantomData
66 }
67 }
68}
69
70impl<P, A: Blep> AudioFrame<A> for AyPlayer<P> {
71 fn ensure_audio_frame_time(&self, blep: &mut A, sample_rate: u32, cpu_hz: f64) {
72 blep.ensure_frame_time(sample_rate, cpu_hz, self.frame_tstates, MARGIN_TSTATES)
73 }
74
75 fn get_audio_frame_end_time(&self) -> FTs {
76 let ts = self.tsc.as_timestamp();
77 assert!(ts >= self.frame_tstates, "AyPlayer::get_audio_frame_end_time:: frame execution didn't finish yet: {} < {}", ts, self.frame_tstates);
78 ts
79 }
80}
81
82impl<P, A> AyAudioFrame<A> for AyPlayer<P>
83 where A: Blep
84{
85 fn render_ay_audio_frame<V: AmpLevels<A::SampleDelta>>(&mut self, blep: &mut A, chans: [usize; 3]) {
86 let end_ts = self.tsc.as_timestamp();
87 let changes = self.ay_io.recorder.drain_ay_reg_changes();
88 self.ay_sound.render_audio::<V,_,A>(changes, blep, end_ts, self.frame_tstates, chans)
89 }
90}
91
92impl<P, A, L> EarMicOutAudioFrame<A> for AyPlayer<P>
93 where A: Blep<SampleDelta=L>,
94 L: SampleDelta
95{
96 #[inline(always)]
97 fn render_earmic_out_audio_frame<V: AmpLevels<L>>(&self, blep: &mut A, channel: usize) {
98 render_audio_frame_ts::<V,L,A,_>(self.prev_earmic,
99 None,
100 &self.earmic_changes,
101 blep, channel)
102 }
103}
104
105impl<P: AyPortDecode> FrameState for AyPlayer<P> {
106 fn current_frame(&self) -> u64 {
107 self.frames.0
108 }
109
110 fn set_frame_counter(&mut self, fc: u64) {
111 self.frames = Wrapping(fc);
112 }
113
114 fn frame_tstate(&self) -> (u64, FTs) {
115 let mut frames = self.frames;
116 let ts = self.tsc.as_timestamp();
117 let ts_norm = ts.rem_euclid(self.frame_tstates);
118 if ts_norm != ts {
119 frames = if ts < 0 {
120 frames - Wrapping(1)
121 }
122 else {
123 frames + Wrapping(1)
124 }
125 }
126 (frames.0, ts_norm)
127 }
128
129 fn current_tstate(&self) -> FTs {
130 self.tsc.as_timestamp()
131 }
132
133 fn set_frame_tstate(&mut self, ts: FTs) {
134 *self.tsc = Wrapping(ts);
135 }
136
137 fn is_frame_over(&self) -> bool {
138 self.tsc.as_timestamp() >= self.frame_tstates
139 }
140}
141
142impl<P: AyPortDecode> ControlUnit for AyPlayer<P> {
143 type BusDevice = NullDevice<FTs>;
144
145 fn bus_device_mut(&mut self) -> &mut Self::BusDevice {
146 &mut self.bus
147 }
148
149 fn bus_device_ref(&self) -> &Self::BusDevice {
150 &self.bus
151 }
152
153 fn into_bus_device(self) -> Self::BusDevice {
154 self.bus
155 }
156
157 fn reset<C: Cpu>(&mut self, cpu: &mut C, hard: bool) {
158 if hard {
159 cpu.reset();
160 self.ay_sound.reset();
161 let ts = self.tsc.as_timestamp();
162 self.ay_io.reset(ts);
163 self.bus.reset(ts);
164 }
165 else {
166 self.execute_instruction(cpu, opconsts::RST_00H_OPCODE).unwrap();
167 }
168 }
169
170 fn nmi<C: Cpu>(&mut self, cpu: &mut C) -> bool {
171 let mut tsc = self.ensure_next_frame_tsc();
172 let res = cpu.nmi(self, &mut tsc);
173 self.tsc = tsc;
174 res
175 }
176
177 fn execute_next_frame<C: Cpu>(&mut self, cpu: &mut C) {
178 let mut tsc = self.ensure_next_frame_tsc();
179 loop {
180 match cpu.execute_with_limit(self, &mut tsc, self.frame_tstates) {
181 Ok(()) => break,
182 Err(BreakCause::Halt) => {
183 assert_eq!(0, self.frame_tstates.rem_euclid(M1_CYCLE_TS as FTs));
184 let ts = self.frame_tstates + tsc.as_timestamp()
185 .rem_euclid(M1_CYCLE_TS as FTs);
186 let r_incr = (ts - tsc.as_timestamp()) / M1_CYCLE_TS as i32;
187 cpu.add_r(r_incr);
188 tsc.0 = Wrapping(ts);
189 break;
190 }
191 Err(_) => {}
192 }
193 }
194 self.bus.update_timestamp(tsc.as_timestamp());
195 self.tsc = tsc;
196 }
197
198 fn ensure_next_frame(&mut self) {
199 self.ensure_next_frame_tsc();
200 }
201
202 fn execute_single_step<C: Cpu, F>(&mut self,
203 cpu: &mut C,
204 debug: Option<F>
205 ) -> Result<(), ()>
206 where F: FnOnce(CpuDebug)
207 {
208 let mut tsc = self.ensure_next_frame_tsc();
209 let res = cpu.execute_next(self, &mut tsc, debug);
210 self.tsc = tsc;
211 res
212 }
213}
214
215impl<P: AyPortDecode> AyPlayer<P> {
216 pub fn cpu_clock_rate(&self) -> u32 {
217 self.cpu_rate
218 }
219
220 pub fn frame_cycle_count(&self) -> FTs {
221 self.frame_tstates
222 }
223
224 pub fn frame_duration_nanos(&self) -> u32 {
225 nanos_from_frame_tc_cpu_hz(self.frame_tstates as u32, self.cpu_rate) as u32
226 }
227
228 pub fn ensure_audio_frame_time<B: Blep>(&self, blep: &mut B, sample_rate: u32) {
229 <Self as AudioFrame<B>>::ensure_audio_frame_time(self, blep, sample_rate, self.cpu_rate as f64)
230 }
231
232 fn ensure_next_frame_tsc(&mut self) -> TsCounter<FTs> {
233 let ts = self.tsc.as_timestamp();
234 if ts >= self.frame_tstates {
235 self.bus.next_frame(self.frame_tstates);
236 self.frames += Wrapping(1);
237 self.ay_io.recorder.clear();
238 self.earmic_changes.clear();
239 self.prev_earmic = self.last_earmic;
240 self.tsc.0 = Wrapping(ts) - Wrapping(self.frame_tstates);
241 }
242 self.tsc
243 }
244
245 fn execute_instruction<C: Cpu>(&mut self, cpu: &mut C, code: u8) -> Result<(), ()> {
246 const DEBUG: Option<CpuDebugFn> = None;
247 let mut tsc = self.ensure_next_frame_tsc();
248 let res = cpu.execute_instruction(self, &mut tsc, DEBUG, code);
249 self.tsc = tsc;
250 res
251 }
252 pub fn set_host_config<H: HostConfig>(&mut self) {
254 self.ensure_next_frame();
255 self.cpu_rate = H::CPU_HZ;
256 self.frame_tstates = H::FRAME_TSTATES;
257 }
258 pub fn set_config(&mut self, cpu_rate: u32, frame_tstates: FTs) {
260 assert!(frame_tstates > 0 && frame_tstates as u32 <= cpu_rate);
261 self.ensure_next_frame();
262 self.cpu_rate = cpu_rate;
263 self.frame_tstates = frame_tstates;
264 }
265 pub fn reset_frames(&mut self) {
267 self.frames.0 = 0;
268 }
269 pub fn write_ay(&mut self, timestamp: FTs, reg: u8, val: u8) {
276 assert!(timestamp >= self.tsc.as_timestamp());
277 *self.tsc = Wrapping(timestamp);
278 let reg = reg.into();
279 self.ay_io.set(reg, val);
280 self.ay_io.recorder.record_ay_reg_change(reg, val, timestamp);
281 }
282}
283
284impl<P> Io for AyPlayer<P> where P: AyPortDecode {
285 type Timestamp = FTs;
286 type WrIoBreak = ();
287 type RetiBreak = ();
288
289 #[inline(always)]
290 fn is_irq(&mut self, ts: FTs) -> bool {
291 ts & !31 == 0
292 }
293
294 fn read_io(&mut self, port: u16, ts: FTs) -> (u8, Option<NonZeroU16>) {
295 let val = if P::is_data_read(port) {
296 self.ay_io.data_port_read(port, ts)
297 }
298 else {
299 0xff
300 };
301 (val, None)
302 }
303
304 fn write_io(&mut self, port: u16, data: u8, ts: FTs) -> (Option<()>, Option<NonZeroU16>) {
305 if port & 1 == 0 {
306 let earmic = data >> 3 & 3;
307 if self.last_earmic != earmic {
308 self.last_earmic = earmic;
309 self.earmic_changes.push((ts, earmic).into());
310 }
311 }
312 else {
313 P::write_ay_io(&mut self.ay_io, port, data, ts);
314 }
315 (None, None)
316 }
317}
318
319impl<P> Memory for AyPlayer<P> {
320 type Timestamp = FTs;
321
322 #[inline]
323 fn read_debug(&self, addr: u16) -> u8 {
324 self.memory.read(addr)
325 }
326
327 #[inline]
328 fn read_mem(&self, addr: u16, _ts: FTs) -> u8 {
329 self.memory.read(addr)
330 }
331
332 #[inline]
333 fn read_mem16(&self, addr: u16, _ts: FTs) -> u16 {
334 self.memory.read16(addr)
335 }
336
337 #[inline]
338 fn read_opcode(&mut self, pc: u16, _ir: u16, _ts: FTs) -> u8 {
339 self.memory.read(pc)
340 }
341
342 #[inline]
343 fn write_mem(&mut self, addr: u16, val: u8, _ts: FTs) {
344 self.memory.write(addr, val);
345 }
346}