1#[cfg(feature = "serde")]
9use serde::{Serialize, Deserialize};
10
11use super::{Z80, any::Z80Any, CpuFlags};
12
13pub trait Flavour: Clone + Copy + Default + PartialEq + Eq {
21 const CONSTANT_OUT_DATA: u8;
23 const ACCEPTING_INT_RESETS_IFF2_EARLY: bool;
26 fn tag() -> &'static str;
28 fn memptr_mix(msb: u8, lsb: u8) -> (u8, u8);
33 fn begin_instruction(&mut self);
37 fn flags_modified(&mut self);
39 fn get_q(&self, acc:u8, flags: CpuFlags) -> u8;
41 fn cpu_into_any(cpu: Z80<Self>) -> Z80Any;
43 fn unwrap_cpu_any(cpu_any: Z80Any) -> Z80<Self>;
48 fn reset(&mut self) {
51 *self = Default::default();
52 }
53}
54
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
57#[cfg_attr(feature = "serde", serde(default, rename_all(serialize = "camelCase")))]
58#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
59pub struct NMOS {
60 #[cfg_attr(feature = "serde", serde(alias = "flagsModified"))]
61 flags_modified: bool,
62 #[cfg_attr(feature = "serde", serde(alias = "lastFlagsModified"))]
63 last_flags_modified: bool
64}
65
66#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68#[cfg_attr(feature = "serde", serde(into = "NMOS", from = "NMOS"))]
69#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
70pub struct CMOS;
71
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78#[cfg_attr(feature = "serde", serde(default, rename_all(serialize = "camelCase")))]
79#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
80pub struct BM1 {
81 #[cfg_attr(feature = "serde", serde(alias = "flagsModified"))]
82 flags_modified: bool,
83 #[cfg_attr(feature = "serde", serde(alias = "lastFlagsModified"))]
84 last_flags_modified: bool
85}
86
87impl Flavour for NMOS {
88 const CONSTANT_OUT_DATA: u8 = 0;
89 const ACCEPTING_INT_RESETS_IFF2_EARLY: bool = true;
90
91 fn tag() -> &'static str {
92 "NMOS"
93 }
94 #[inline(always)]
95 fn memptr_mix(msb: u8, lsb: u8) -> (u8, u8) {
96 (msb, lsb.wrapping_add(1))
97 }
98 #[inline(always)]
99 fn begin_instruction(&mut self) {
100 self.last_flags_modified = self.flags_modified;
101 self.flags_modified = false;
102 }
103 #[inline(always)]
104 fn flags_modified(&mut self) {
105 self.flags_modified = true;
106 }
107 #[inline(always)]
108 fn get_q(&self, acc: u8, flags: CpuFlags) -> u8 {
109 if self.last_flags_modified {
110 acc
111 }
112 else {
113 acc | flags.bits()
114 }
115 }
116
117 fn cpu_into_any(cpu: Z80<Self>) -> Z80Any {
118 Z80Any::NMOS(cpu)
119 }
120
121 fn unwrap_cpu_any(cpu_any: Z80Any) -> Z80<Self> {
122 cpu_any.unwrap_nmos()
123 }
124}
125
126impl Flavour for CMOS {
127 const CONSTANT_OUT_DATA: u8 = u8::max_value();
128 const ACCEPTING_INT_RESETS_IFF2_EARLY: bool = false;
129
130 fn tag() -> &'static str {
131 "CMOS"
132 }
133 #[inline(always)]
134 fn memptr_mix(msb: u8, lsb: u8) -> (u8, u8) {
135 (msb, lsb.wrapping_add(1))
136 }
137 #[inline(always)]
138 fn begin_instruction(&mut self) {}
139 #[inline(always)]
140 fn flags_modified(&mut self) {}
141 #[inline(always)]
142 fn get_q(&self, acc: u8, _flags: CpuFlags) -> u8 { acc }
143
144 fn cpu_into_any(cpu: Z80<Self>) -> Z80Any {
145 Z80Any::CMOS(cpu)
146 }
147
148 fn unwrap_cpu_any(cpu_any: Z80Any) -> Z80<Self> {
149 cpu_any.unwrap_cmos()
150 }
151}
152
153impl Flavour for BM1 {
154 const CONSTANT_OUT_DATA: u8 = 0;
155 const ACCEPTING_INT_RESETS_IFF2_EARLY: bool = false;
156
157 fn tag() -> &'static str {
158 "BM1"
159 }
160 #[inline(always)]
161 fn memptr_mix(_msb: u8, lsb: u8) -> (u8, u8) {
162 (0, lsb.wrapping_add(1))
163 }
164 #[inline(always)]
165 fn begin_instruction(&mut self) {
166 self.last_flags_modified = self.flags_modified;
167 self.flags_modified = false;
168 }
169 #[inline(always)]
170 fn flags_modified(&mut self) {
171 self.flags_modified = true;
172 }
173 #[inline(always)]
174 fn get_q(&self, acc: u8, flags: CpuFlags) -> u8 {
175 if self.last_flags_modified {
176 acc
177 }
178 else {
179 acc | flags.bits()
180 }
181 }
182
183 fn cpu_into_any(cpu: Z80<Self>) -> Z80Any {
184 Z80Any::BM1(cpu)
185 }
186
187 fn unwrap_cpu_any(cpu_any: Z80Any) -> Z80<Self> {
188 cpu_any.unwrap_bm1()
189 }
190}
191
192impl From<NMOS> for CMOS {
194 fn from(_: NMOS) -> Self {
195 CMOS
196 }
197}
198
199impl From<CMOS> for NMOS {
200 fn from(_: CMOS) -> Self {
201 NMOS::default()
202 }
203}
204
205impl From<BM1> for CMOS {
207 fn from(_: BM1) -> Self {
208 CMOS
209 }
210}
211
212impl From<CMOS> for BM1 {
213 fn from(_: CMOS) -> Self {
214 BM1::default()
215 }
216}
217
218impl From<NMOS> for BM1 {
219 fn from(NMOS{flags_modified, last_flags_modified}: NMOS) -> Self {
220 BM1 {flags_modified, last_flags_modified}
221 }
222}
223
224impl From<BM1> for NMOS {
225 fn from(BM1{flags_modified, last_flags_modified}: BM1) -> Self {
226 NMOS {flags_modified, last_flags_modified}
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn flavour_works() {
236 assert_eq!(NMOS::memptr_mix(1, 1), (1, 2));
237 assert_eq!(NMOS::memptr_mix(1, 255), (1, 0));
238 assert_eq!(CMOS::memptr_mix(1, 1), (1, 2));
239 assert_eq!(CMOS::memptr_mix(1, 255), (1, 0));
240 assert_eq!(BM1::memptr_mix(1, 1), (0, 2));
241 assert_eq!(BM1::memptr_mix(1, 255), (0, 0));
242
243 let flags = CpuFlags::all();
244
245 let mut flav = NMOS::default();
246 assert!(!flav.last_flags_modified);
247 assert!(!flav.flags_modified);
248 assert_eq!(flav.get_q(0, flags), 0xFF);
249 flav.begin_instruction();
250 assert!(!flav.last_flags_modified);
251 assert!(!flav.flags_modified);
252 assert_eq!(flav.get_q(0, flags), 0xFF);
253 flav.flags_modified();
254 assert!(!flav.last_flags_modified);
255 assert!(flav.flags_modified);
256 assert_eq!(flav.get_q(0, flags), 0xFF);
257 flav.begin_instruction();
258 assert!(flav.last_flags_modified);
259 assert!(!flav.flags_modified);
260 assert_eq!(flav.get_q(0, flags), 0);
261
262 let mut flav = BM1::default();
263 assert!(!flav.last_flags_modified);
264 assert!(!flav.flags_modified);
265 assert_eq!(flav.get_q(0, flags), 0xFF);
266 flav.begin_instruction();
267 assert!(!flav.last_flags_modified);
268 assert!(!flav.flags_modified);
269 assert_eq!(flav.get_q(0, flags), 0xFF);
270 flav.flags_modified();
271 assert!(!flav.last_flags_modified);
272 assert!(flav.flags_modified);
273 assert_eq!(flav.get_q(0, flags), 0xFF);
274 flav.begin_instruction();
275 assert!(flav.last_flags_modified);
276 assert!(!flav.flags_modified);
277 assert_eq!(flav.get_q(0, flags), 0);
278
279 let mut flav = CMOS::default();
280 assert_eq!(flav.get_q(0, flags), 0);
281 flav.begin_instruction();
282 assert_eq!(flav.get_q(1, flags), 1);
283 flav.flags_modified();
284 assert_eq!(flav.get_q(2, flags), 2);
285 flav.begin_instruction();
286 assert_eq!(flav.get_q(3, flags), 3);
287 }
288
289 #[test]
290 fn flavour_conversion() {
291 let cmos: Z80<CMOS> = Z80::<BM1>::default().into_flavour();
292 let nmos = Z80::<NMOS>::from_flavour(cmos);
293 let bm1 = nmos.into_flavour::<BM1>();
294 assert_eq!(bm1, Z80::<BM1>::default());
295 let cmos1: Z80<CMOS> = Z80::<CMOS>::default();
296 let cmos2: Z80<CMOS> = Z80::<CMOS>::default();
297 assert_eq!(Z80Any::from(cmos1), Z80Any::CMOS(cmos2));
298 let nmos1: Z80<NMOS> = Z80::<NMOS>::default();
299 let nmos2: Z80<NMOS> = Z80::<NMOS>::default();
300 assert_eq!(Z80Any::from(nmos1), Z80Any::NMOS(nmos2));
301 let bm1_1: Z80<BM1> = Z80::<BM1>::default();
302 let bm1_2: Z80<BM1> = Z80::<BM1>::default();
303 assert_eq!(Z80Any::from(bm1_1), Z80Any::BM1(bm1_2));
304 }
305
306 #[cfg(feature = "serde")]
307 #[test]
308 fn flavour_serde() {
309 assert_eq!(NMOS::tag(), "NMOS");
310 assert_eq!(CMOS::tag(), "CMOS");
311 assert_eq!(BM1::tag(), "BM1");
312 assert_eq!(serde_json::to_string(&NMOS::default()).unwrap(), r#"{"flagsModified":false,"lastFlagsModified":false}"#);
313 assert_eq!(serde_json::to_string(&CMOS::default()).unwrap(), r#"{"flagsModified":false,"lastFlagsModified":false}"#);
314 assert_eq!(serde_json::to_string(&BM1::default()).unwrap(), r#"{"flagsModified":false,"lastFlagsModified":false}"#);
315 let flav: NMOS = serde_json::from_str(r#"{"flags_modified":false,"last_flags_modified":false}"#).unwrap();
316 assert!(flav == NMOS::default());
317 let flav: NMOS = serde_json::from_str(r#"{}"#).unwrap();
318 assert!(flav == NMOS::default());
319 let flav: NMOS = serde_json::from_str(r#"{"flagsModified":true,"lastFlagsModified":true}"#).unwrap();
320 assert!(flav == NMOS { flags_modified: true, last_flags_modified: true});
321 let flav: CMOS = serde_json::from_str(r#"{"flags_modified":false,"last_flags_modified":false}"#).unwrap();
322 assert!(flav == CMOS::default());
323 let flav: CMOS = serde_json::from_str(r#"{}"#).unwrap();
324 assert!(flav == CMOS::default());
325 let flav: CMOS = serde_json::from_str(r#"{"flagsModified":true,"lastFlagsModified":true}"#).unwrap();
326 assert!(flav == CMOS);
327 let flav: BM1 = serde_json::from_str(r#"{"flags_modified":false,"last_flags_modified":false}"#).unwrap();
328 assert!(flav == BM1::default());
329 let flav: BM1 = serde_json::from_str(r#"{}"#).unwrap();
330 assert!(flav == BM1::default());
331 let flav: BM1 = serde_json::from_str(r#"{"flagsModified":true,"lastFlagsModified":true}"#).unwrap();
332 assert!(flav == BM1 { flags_modified: true, last_flags_modified: true});
333 }
334}