z80emu/z80/
any.rs

1/*
2    z80emu: ZiLOG Z80 microprocessor emulation library.
3    Copyright (C) 2019-2024  Rafal Michalski
4
5    For the full copyright notice, see the lib.rs file.
6*/
7//! Features an [enum][Z80Any] of [Z80] with any [Flavour].
8use core::fmt;
9
10use crate::cpu::{
11    Cpu,
12    CpuDebug,
13    CpuFlags,
14    InterruptMode,
15    Prefix,
16    Reg8,
17    StkReg16
18};
19use crate::host::{Result, Clock, Memory, Io};
20use super::{Z80, flavours::*};
21
22macro_rules! cpu_dispatch_any {
23    ($cpuany:ident($cpu:ident) => $expr:expr) => {
24        cpu_dispatch_any!(($cpuany)($cpu) => $expr)
25    };
26    ($cpuany:ident(mut $cpu:ident) => $expr:expr) => {
27        cpu_dispatch_any!(($cpuany)(mut $cpu) => $expr)
28    };
29    (($cpuany:expr)($($cpu:tt)*) => $expr:expr) => {
30        match $cpuany {
31            $crate::z80::any::Z80Any::NMOS($($cpu)*) => $expr,
32            $crate::z80::any::Z80Any::CMOS($($cpu)*) => $expr,
33            $crate::z80::any::Z80Any::BM1($($cpu)*) => $expr,
34        }
35    };
36}
37
38/// [Z80] with any [Flavour].
39///
40/// This enum can be used in place of [Z80] when changing of [Flavour] is required in run time.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum Z80Any {
43    NMOS(Z80<NMOS>),
44    CMOS(Z80<CMOS>),
45    BM1(Z80<BM1>),
46}
47
48impl<Q: Flavour> From<Z80<Q>> for Z80Any {
49    fn from(cpu: Z80<Q>) -> Z80Any {
50        Q::cpu_into_any(cpu)
51    }
52}
53
54impl<Q> From<Z80Any> for Z80<Q>
55    where Q: Flavour + From<NMOS> + From<CMOS> + From<BM1>
56{
57    fn from(cpu_any: Z80Any) -> Z80<Q> {
58        cpu_dispatch_any!(cpu_any(cpu) => cpu.into_flavour())
59    }
60}
61
62impl Z80Any {
63    /// Returns the tag of the current Z80 variant as string.
64    pub fn tag(&self) -> &'static str {
65        match self {
66            Z80Any::NMOS(..) => NMOS::tag(),
67            Z80Any::CMOS(..) => CMOS::tag(),
68            Z80Any::BM1(..) => BM1::tag(),
69        }
70    }
71
72    /// Creates a new instance of [Z80Any] with the given `tag` on success with the state just after `RESET`.
73    ///
74    /// Returns `None` if the provided `tag` is unknown.
75    pub fn with_tag(tag: &str) -> Option<Self> {
76        if tag.eq_ignore_ascii_case("NMOS") {
77            Some(Self::new_nmos())
78        }
79        else if tag.eq_ignore_ascii_case("CMOS") {
80            Some(Self::new_cmos())
81        }
82        else if tag.eq_ignore_ascii_case("BM1") {
83            Some(Self::new_bm1())
84        }
85        else {
86            None
87        }
88    }
89
90    /// Creates a new instance of [Z80Any::NMOS] variant with the state just after `RESET`.
91    pub fn new_nmos() -> Z80Any {
92        Z80Any::NMOS(Z80::new())
93    }
94
95    /// Creates a new instance of [Z80Any::CMOS] variant with the state just after `RESET`.
96    pub fn new_cmos() -> Z80Any {
97        Z80Any::CMOS(Z80::new())
98    }
99
100    /// Creates a new instance of [Z80Any::BM1] variant with the state just after `RESET`.
101    pub fn new_bm1() -> Z80Any {
102        Z80Any::BM1(Z80::new())
103    }
104
105    /// Returns `true` if the variant of `self` is [Z80Any::NMOS].
106    pub fn is_nmos(&self) -> bool {
107        if let Z80Any::NMOS(..) = self {
108            return true
109        }
110        false
111    }
112
113    /// Returns `true` if the variant of `self` is [Z80Any::CMOS].
114    pub fn is_cmos(&self) -> bool {
115        if let Z80Any::CMOS(..) = self {
116            return true
117        }
118        false
119    }
120
121    /// Returns `true` if the variant of `self` is [Z80Any::BM1].
122    pub fn is_bm1(&self) -> bool {
123        if let Z80Any::BM1(..) = self {
124            return true
125        }
126        false
127    }
128
129    /// Converts an instance of any variant of [Z80Any] to a [Z80Any::NMOS] variant.
130    pub fn into_nmos(self) -> Z80Any {
131        cpu_dispatch_any!(self(cpu) => Z80Any::NMOS(cpu.into_flavour()))
132    }
133
134    /// Converts an instance of any variant of [Z80Any] to a [Z80Any::CMOS] variant.
135    pub fn into_cmos(self) -> Z80Any {
136        cpu_dispatch_any!(self(cpu) => Z80Any::CMOS(cpu.into_flavour()))
137    }
138
139    /// Converts an instance of any variant of [Z80Any] to a [Z80Any::BM1] variant.
140    pub fn into_bm1(self) -> Z80Any {
141        cpu_dispatch_any!(self(cpu) => Z80Any::BM1(cpu.into_flavour()))
142    }
143
144    /// Returns the contained [`Z80<NMOS>`][Z80] value, consuming the self value.
145    ///
146    /// # Panics
147    /// Panics if the self value is not a [Z80Any::NMOS] variant.
148    pub fn unwrap_nmos(self) -> Z80<NMOS> {
149        if let Z80Any::NMOS(cpu) = self {
150            cpu
151        }
152        else {
153            panic!("called `Z80Any::unwrap_nmos()` on a non `Z80Any::NMOS` variant")
154        }
155    }
156
157    /// Returns the contained [`Z80<CMOS>`][Z80] value, consuming the self value.
158    ///
159    /// # Panics
160    /// Panics if the self value is not a [Z80Any::CMOS] variant.
161    pub fn unwrap_cmos(self) -> Z80<CMOS> {
162        if let Z80Any::CMOS(cpu) = self {
163            cpu
164        }
165        else {
166            panic!("called `Z80Any::unwrap_cmos()` on a non `Z80Any::CMOS` variant")
167        }
168    }
169
170    /// Returns the contained [`Z80<BM1>`][Z80] value, consuming the self value.
171    ///
172    /// # Panics
173    /// Panics if the self value is not a [Z80Any::BM1] variant.
174    pub fn unwrap_bm1(self) -> Z80<BM1> {
175        if let Z80Any::BM1(cpu) = self {
176            cpu
177        }
178        else {
179            panic!("called `Z80Any::unwrap_bm1()` on a non `Z80Any::BM1` variant")
180        }
181    }
182
183    /// Retrieves the internal state of the MEMPTR register.
184    pub fn get_memptr(&self) -> u16 {
185        cpu_dispatch_any!(self(cpu) => cpu.get_memptr())
186    }
187
188    /// Changes the internal state of the MEMPTR register.
189    pub fn set_memptr(&mut self, memptr: u16) {
190        cpu_dispatch_any!(self(cpu) => cpu.set_memptr(memptr))
191    }
192
193    /// The content of the `R` register is lazy evaluated when its value is being set or retrieved.
194    /// This method normalizes the internal state of the `R` register, so e.g. two instances of
195    /// [Z80] can be compared if they represent the same `CPU` state.
196    pub fn normalize_r(&mut self) {
197        cpu_dispatch_any!(self(cpu) => cpu.normalize_r())
198    }
199}
200
201impl Default for Z80Any {
202    fn default() -> Z80Any {
203        Z80Any::NMOS(Default::default())
204    }
205}
206
207/// Displays the tag of the current Z80 variant.
208impl fmt::Display for Z80Any {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        f.write_str(self.tag())
211    }
212}
213
214impl Cpu for Z80Any {
215    fn reset(&mut self) {
216        cpu_dispatch_any!(self(cpu) => cpu.reset())
217    }
218
219    fn get_pc(&self) -> u16 {
220        cpu_dispatch_any!(self(cpu) => cpu.get_pc())
221    }
222
223    fn set_pc(&mut self, pc: u16) {
224        cpu_dispatch_any!(self(cpu) => cpu.set_pc(pc))
225    }
226
227    fn get_sp(&self) -> u16 {
228        cpu_dispatch_any!(self(cpu) => cpu.get_sp())
229    }
230
231    fn set_sp(&mut self, sp: u16) {
232        cpu_dispatch_any!(self(cpu) => cpu.set_sp(sp))
233    }
234
235    fn get_acc(&self) -> u8 {
236        cpu_dispatch_any!(self(cpu) => cpu.get_acc())
237    }
238
239    fn set_acc(&mut self, val: u8) {
240        cpu_dispatch_any!(self(cpu) => cpu.set_acc(val))
241    }
242
243    fn get_flags(&self) -> CpuFlags {
244        cpu_dispatch_any!(self(cpu) => cpu.get_flags())
245    }
246
247    fn set_flags(&mut self, flags: CpuFlags) {
248        cpu_dispatch_any!(self(cpu) => cpu.set_flags(flags))
249    }
250
251    fn inc_r(&mut self) {
252        cpu_dispatch_any!(self(cpu) => cpu.inc_r())
253    }
254
255    fn add_r(&mut self, delta: i32) {
256        cpu_dispatch_any!(self(cpu) => cpu.add_r(delta))
257    }
258
259    fn get_r(&self) -> u8 {
260        cpu_dispatch_any!(self(cpu) => cpu.get_r())
261    }
262
263    fn set_r(&mut self, r: u8) {
264        cpu_dispatch_any!(self(cpu) => cpu.set_r(r))
265    }
266
267    fn get_i(&self) -> u8 {
268        cpu_dispatch_any!(self(cpu) => cpu.get_i())
269    }
270
271    fn set_i(&mut self, i: u8) {
272        cpu_dispatch_any!(self(cpu) => cpu.set_i(i))
273    }
274
275    fn get_ir(&self) -> u16 {
276        cpu_dispatch_any!(self(cpu) => cpu.get_ir())
277    }
278
279    fn get_iffs(&self) -> (bool, bool) {
280        cpu_dispatch_any!(self(cpu) => cpu.get_iffs())
281    }
282
283    fn set_iffs(&mut self, iff1: bool, iff2: bool) {
284        cpu_dispatch_any!(self(cpu) => cpu.set_iffs(iff1, iff2))
285    }
286
287    fn halt(&mut self) {
288        cpu_dispatch_any!(self(cpu) => cpu.halt())
289    }
290
291    fn is_halt(&self) -> bool {
292        cpu_dispatch_any!(self(cpu) => cpu.is_halt())
293    }
294
295    fn get_im(&self) -> InterruptMode {
296        cpu_dispatch_any!(self(cpu) => cpu.get_im())
297    }
298
299    fn set_im(&mut self, im: InterruptMode) {
300        cpu_dispatch_any!(self(cpu) => cpu.set_im(im))
301    }
302
303    fn ex_af_af(&mut self) {
304        cpu_dispatch_any!(self(cpu) => cpu.ex_af_af())
305    }
306
307    fn exx(&mut self) {
308        cpu_dispatch_any!(self(cpu) => cpu.exx())
309    }
310
311    fn get_reg(&self, reg: Reg8, prefix: Option<Prefix>) -> u8 {
312        cpu_dispatch_any!(self(cpu) => cpu.get_reg(reg, prefix))
313    }
314
315    fn set_reg(&mut self, dst: Reg8, prefix: Option<Prefix>, val: u8) {
316        cpu_dispatch_any!(self(cpu) => cpu.set_reg(dst, prefix, val))
317    }
318
319    fn get_reg2(&self, src: StkReg16) -> (u8, u8) {
320        cpu_dispatch_any!(self(cpu) => cpu.get_reg2(src))
321    }
322
323    fn get_alt_reg2(&self, src: StkReg16) -> (u8, u8) {
324        cpu_dispatch_any!(self(cpu) => cpu.get_alt_reg2(src))
325    }
326
327    fn get_reg16(&self, src: StkReg16) -> u16 {
328        cpu_dispatch_any!(self(cpu) => cpu.get_reg16(src))
329    }
330
331    fn get_alt_reg16(&self, src: StkReg16) -> u16 {
332        cpu_dispatch_any!(self(cpu) => cpu.get_alt_reg16(src))
333    }
334
335    fn set_reg2(&mut self, src: StkReg16, hi: u8, lo: u8) {
336        cpu_dispatch_any!(self(cpu) => cpu.set_reg2(src, hi, lo))
337    }
338
339    fn set_reg16(&mut self, src: StkReg16, val: u16) {
340        cpu_dispatch_any!(self(cpu) => cpu.set_reg16(src, val))
341    }
342
343    fn get_index2(&self, prefix: Prefix) -> (u8, u8) {
344        cpu_dispatch_any!(self(cpu) => cpu.get_index2(prefix))
345    }
346
347    fn get_index16(&self, prefix: Prefix) -> u16 {
348        cpu_dispatch_any!(self(cpu) => cpu.get_index16(prefix))
349    }
350
351    fn set_index2(&mut self, prefix: Prefix, hi: u8, lo: u8) {
352        cpu_dispatch_any!(self(cpu) => cpu.set_index2(prefix, hi, lo))
353    }
354
355    fn set_index16(&mut self, prefix: Prefix, val: u16) {
356        cpu_dispatch_any!(self(cpu) => cpu.set_index16(prefix, val))
357    }
358
359    fn is_irq_allowed(&self) -> bool {
360        cpu_dispatch_any!(self(cpu) => cpu.is_irq_allowed())
361    }
362
363    fn is_nmi_allowed(&self) -> bool {
364        cpu_dispatch_any!(self(cpu) => cpu.is_nmi_allowed())
365    }
366
367    fn restore_iff1(&mut self) {
368        cpu_dispatch_any!(self(cpu) => cpu.restore_iff1())
369    }
370
371    fn disable_interrupts(&mut self) {
372        cpu_dispatch_any!(self(cpu) => cpu.disable_interrupts())
373    }
374
375    fn enable_interrupts(&mut self) {
376        cpu_dispatch_any!(self(cpu) => cpu.enable_interrupts())
377    }
378
379    fn is_after_ei(&self) -> bool {
380        cpu_dispatch_any!(self(cpu) => cpu.is_after_ei())
381    }
382
383    fn is_after_prefix(&self) -> bool {
384        cpu_dispatch_any!(self(cpu) => cpu.is_after_prefix())
385    }
386
387    fn get_prefix(&self) -> Option<Prefix> {
388        cpu_dispatch_any!(self(cpu) => cpu.get_prefix())
389    }
390
391    fn irq<M, T, F>(&mut self, control: &mut M, tsc: &mut T, debug: Option<F>) -> Option<Result<M::WrIoBreak, M::RetiBreak>>
392    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
393          T: Clock,
394          F: FnOnce(CpuDebug)
395    {
396        cpu_dispatch_any!(self(cpu) => cpu.irq(control, tsc, debug))
397    }
398
399    fn nmi<M, T>(&mut self, control: &mut M, tsc: &mut T) -> bool
400    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
401          T: Clock
402    {
403        cpu_dispatch_any!(self(cpu) => cpu.nmi(control, tsc))
404    }
405
406    fn execute_instruction<M, T, F>(&mut self, control: &mut M, tsc: &mut T, debug: Option<F>, code: u8) -> Result<M::WrIoBreak, M::RetiBreak>
407    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
408          T: Clock,
409          F: FnOnce(CpuDebug)
410    {
411        cpu_dispatch_any!(self(cpu) => cpu.execute_instruction(control, tsc, debug, code))
412    }
413
414    fn execute_next<M, T, F>(&mut self, control: &mut M, tsc: &mut T, debug: Option<F>) -> Result<M::WrIoBreak, M::RetiBreak>
415    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
416          T: Clock,
417          F: FnOnce(CpuDebug)
418    {
419        cpu_dispatch_any!(self(cpu) => cpu.execute_next(control, tsc, debug))
420    }
421
422    fn execute_with_limit<M, T>(&mut self, control: &mut M, tsc: &mut T, vc_limit: T::Limit) -> Result<M::WrIoBreak, M::RetiBreak>
423    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
424          T: Clock
425    {
426        cpu_dispatch_any!(self(cpu) => cpu.execute_with_limit(control, tsc, vc_limit))
427    }
428}
429
430#[cfg(test)]
431mod tests {
432    use super::*;
433
434    #[test]
435    fn z80any() {
436        let cpu_any = Z80Any::with_tag(NMOS::tag()).unwrap();
437        assert_eq!(cpu_any.tag(), "NMOS");
438        assert_eq!(cpu_any, Z80Any::new_nmos());
439        assert_eq!(cpu_any.is_nmos(), true);
440        assert_eq!(cpu_any.is_cmos(), false);
441        assert_eq!(cpu_any.is_bm1(), false);
442        let cpu = cpu_any.clone().unwrap_nmos();
443        assert_eq!(cpu_any, Z80Any::NMOS(cpu));
444
445        let cpu_any = cpu_any.into_cmos();
446        assert_eq!(cpu_any.tag(), "CMOS");
447        assert_eq!(cpu_any, Z80Any::with_tag(CMOS::tag()).unwrap());
448        assert_eq!(cpu_any, Z80Any::new_cmos());
449        assert_eq!(cpu_any.is_nmos(), false);
450        assert_eq!(cpu_any.is_cmos(), true);
451        assert_eq!(cpu_any.is_bm1(), false);
452        let cpu = cpu_any.clone().unwrap_cmos();
453        assert_eq!(cpu_any, Z80Any::CMOS(cpu));
454
455        let cpu_any = cpu_any.into_bm1();
456        assert_eq!(cpu_any.tag(), "BM1");
457        assert_eq!(cpu_any, Z80Any::with_tag(BM1::tag()).unwrap());
458        assert_eq!(cpu_any, Z80Any::new_bm1());
459        assert_eq!(cpu_any.is_nmos(), false);
460        assert_eq!(cpu_any.is_cmos(), false);
461        assert_eq!(cpu_any.is_bm1(), true);
462        let cpu = cpu_any.clone().unwrap_bm1();
463        assert_eq!(cpu_any, Z80Any::BM1(cpu));
464
465        let cpu_any = cpu_any.into_nmos();
466        assert_eq!(cpu_any.tag(), "NMOS");
467        assert_eq!(cpu_any, Z80Any::new_nmos());
468    }
469}