gb_cpu_sim/
cpu.rs

1//! This module contains the CPU simulator.
2//!
3//! Importantly, the simulator is built with the assumption that instructions are atomic;
4//! reading from a "dynamic" location (typically, a hardware register) will **not** read the correct
5//! value (the cycle count is unknown to the [`AddressSpace`]).
6//!
7//! This is a design choice for simplicity and performance's sake, and not a bug.
8
9use crate::memory::AddressSpace;
10use std::{fmt, ops::BitOrAssign};
11
12/// The CPU's flags register.
13pub struct Flags {
14	/// The raw 8-bit value.
15	pub value: u8,
16}
17
18impl Flags {
19	/// Gets the Z flag's value.
20	pub fn get_z(&self) -> bool {
21		self.value & 0b10000000 != 0
22	}
23	/// Gets the N flag's value.
24	pub fn get_n(&self) -> bool {
25		self.value & 0b01000000 != 0
26	}
27	/// Gets the H flag's value.
28	pub fn get_h(&self) -> bool {
29		self.value & 0b00100000 != 0
30	}
31	/// Gets the C flag's value.
32	pub fn get_c(&self) -> bool {
33		self.value & 0b00010000 != 0
34	}
35	/// Sets the Z flag's value.
36	pub fn set_z(&mut self, value: bool) {
37		self.value = self.value & 0b01110000 | (value as u8) << 7;
38	}
39	/// Sets the N flag's value.
40	pub fn set_n(&mut self, value: bool) {
41		self.value = self.value & 0b10110000 | (value as u8) << 6;
42	}
43	/// Sets the H flag's value.
44	pub fn set_h(&mut self, value: bool) {
45		self.value = self.value & 0b11010000 | (value as u8) << 5;
46	}
47	/// Sets the C flag's value.
48	pub fn set_c(&mut self, value: bool) {
49		self.value = self.value & 0b11100000 | (value as u8) << 4;
50	}
51}
52
53impl fmt::Display for Flags {
54	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55		write!(
56			f,
57			"{}{}{}{}",
58			if self.get_z() { 'z' } else { '-' },
59			if self.get_n() { 'n' } else { '-' },
60			if self.get_h() { 'h' } else { '-' },
61			if self.get_c() { 'c' } else { '-' },
62		)
63	}
64}
65
66/// A tick's possible results.
67#[derive(Debug, PartialEq, Eq)]
68pub enum TickResult {
69	/// Nothing noteworthy happened.
70	Ok,
71	/// A `ld b, b` instruction was executed.
72	Break,
73	/// A `ld d, d` instruction was executed.
74	Debug,
75	/// A `halt` instruction was executed.
76	Halt,
77	/// A `stop` instruction was executed.
78	Stop,
79	/// An invalid opcode was executed.
80	InvalidOpcode,
81}
82
83/// The CPU's state, which is what gets ticked.
84pub struct State<S: AddressSpace> {
85	// Primary CPU Registers
86	pub a: u8,
87	pub f: Flags,
88	pub b: u8,
89	pub c: u8,
90	pub d: u8,
91	pub e: u8,
92	pub h: u8,
93	pub l: u8,
94	pub pc: u16,
95	pub sp: u16,
96
97	pub ime: bool,
98
99	/// Total number of M-Cycles that have passed during this CPU's life.
100	pub cycles_elapsed: usize,
101
102	/// The address space the CPU is communicating with.
103	pub address_space: S,
104}
105
106impl<S: AddressSpace> State<S> {
107	pub fn new(address_space: S) -> Self {
108		Self {
109			a: 0,
110			f: Flags { value: 0 },
111			b: 0,
112			c: 0,
113			d: 0,
114			e: 0,
115			h: 0,
116			l: 0,
117			pc: 0,
118			// SP defaults to the top of WRAM to minimize conflicts.
119			// Users should set SP to its proper address for all tests.
120			sp: 0xE000,
121			ime: true,
122			cycles_elapsed: 0,
123
124			address_space,
125		}
126	}
127
128	pub fn get_af(&self) -> u16 {
129		u16::from_be_bytes([self.a, self.f.value])
130	}
131	pub fn get_bc(&self) -> u16 {
132		u16::from_be_bytes([self.b, self.c])
133	}
134	pub fn get_de(&self) -> u16 {
135		u16::from_be_bytes([self.d, self.e])
136	}
137	pub fn get_hl(&self) -> u16 {
138		u16::from_be_bytes([self.h, self.l])
139	}
140	pub fn set_af(&mut self, value: u16) {
141		[self.a, self.f.value] = value.to_be_bytes();
142	}
143	pub fn set_bc(&mut self, value: u16) {
144		[self.b, self.c] = value.to_be_bytes();
145	}
146	pub fn set_de(&mut self, value: u16) {
147		[self.d, self.e] = value.to_be_bytes();
148	}
149	pub fn set_hl(&mut self, value: u16) {
150		[self.h, self.l] = value.to_be_bytes();
151	}
152
153	pub fn get_r8_by_id(&mut self, id: u8) -> u8 {
154		match id {
155			0 => self.b,
156			1 => self.c,
157			2 => self.d,
158			3 => self.e,
159			4 => self.h,
160			5 => self.l,
161			6 => {
162				self.cycles_elapsed += 1;
163				self.read(self.get_hl())
164			}
165			7 => self.a,
166			_ => unreachable!(),
167		}
168	}
169	pub fn set_r8_by_id(&mut self, id: u8, value: u8) {
170		match id {
171			0 => self.b = value,
172			1 => self.c = value,
173			2 => self.d = value,
174			3 => self.e = value,
175			4 => self.h = value,
176			5 => self.l = value,
177			6 => {
178				self.cycles_elapsed += 1;
179				self.write(self.get_hl(), value)
180			}
181			7 => self.a = value,
182			_ => unreachable!(),
183		}
184	}
185
186	/// Passthrough for [`self.address_space.read()`][AddressSpace::read].
187	pub fn read(&self, address: u16) -> u8 {
188		self.address_space.read(address)
189	}
190	/// Passthrough for [`self.address_space.write()`][AddressSpace::write].
191	pub fn write(&mut self, address: u16, value: u8) {
192		self.address_space.write(address, value);
193	}
194
195	fn read_pc(&mut self) -> u8 {
196		let value = self.address_space.read(self.pc);
197		self.pc = u16::wrapping_add(self.pc, 1);
198		self.cycles_elapsed += 1;
199		value
200	}
201
202	fn add_hl_r16(&mut self, operand: u16) {
203		let (value, carry) = self.get_hl().overflowing_add(operand);
204		self.set_hl(value);
205		self.f.set_c(carry);
206		self.f.set_n(false);
207		self.f.set_h(self.get_hl() & 0xFFF < operand & 0xFFF);
208		self.cycles_elapsed += 1;
209	}
210
211	fn jr_cc(&mut self, condition: bool) {
212		let offset = self.read_pc() as i8;
213		if condition {
214			self.pc = i16::wrapping_add(self.pc as i16, offset as i16) as u16;
215			self.cycles_elapsed += 1;
216		}
217	}
218
219	fn add(&mut self, operand: u8, carry_in: bool) {
220		let mut r = CarryRetainer::new();
221		r |= self.a.overflowing_add(operand);
222		r |= r.0.overflowing_add(carry_in.into());
223		// If carry is not set, it's easy: is the post-add strictly lower than the pre-add?
224		// If carry is set, it's instead: is the post-add lower than the pre-add?
225		// So that amounts to "is the post-add strictly lower than (the pre-add plus carry)?"
226		self.f.set_h(r.0 & 0xF < (self.a & 0xF) + carry_in as u8);
227		self.f.set_c(r.1);
228		self.f.set_z(r.0 == 0);
229		self.f.set_n(false);
230		self.a = r.0;
231	}
232
233	fn sub(&mut self, operand: u8, carry_in: bool) {
234		let mut r = CarryRetainer::new();
235		r |= self.a.overflowing_sub(operand);
236		r |= r.0.overflowing_sub(carry_in.into());
237		// If carry is not set, it's easy: is the post-add strictly greater than the pre-add?
238		// If carry is set, it's instead: is the post-add greater than the pre-add?
239		// So that amounts to "is (the post-add plus carry) strictly lower than the pre-add?"
240		self.f.set_h((r.0 & 0xF) + carry_in as u8 > self.a & 0xF);
241		self.f.set_c(r.1);
242		self.f.set_z(r.0 == 0);
243		self.f.set_n(true);
244		self.a = r.0;
245	}
246
247	fn and(&mut self, operand: u8) {
248		self.a &= operand;
249		self.f.set_z(self.a == 0);
250		self.f.set_n(false);
251		self.f.set_h(true); // No, this is not a typo.
252		self.f.set_c(false);
253	}
254
255	fn xor(&mut self, operand: u8) {
256		self.a ^= operand;
257		self.f.set_z(self.a == 0);
258		self.f.set_n(false);
259		self.f.set_h(false);
260		self.f.set_c(false);
261	}
262
263	fn or(&mut self, operand: u8) {
264		self.a |= operand;
265		self.f.set_z(self.a == 0);
266		self.f.set_n(false);
267		self.f.set_h(false);
268		self.f.set_c(false);
269	}
270
271	fn cp(&mut self, operand: u8) {
272		let (result, carry) = self.a.overflowing_sub(operand);
273		self.f.set_h(result & 0xF > self.a & 0xF);
274		self.f.set_c(carry);
275		self.f.set_z(result == 0);
276		self.f.set_n(true);
277	}
278
279	fn rlc(&mut self, reg_id: u8) {
280		let value = self.get_r8_by_id(reg_id);
281		let value = value.rotate_left(1);
282		self.set_r8_by_id(reg_id, value);
283		self.f.set_z(value == 0);
284		self.f.set_c(value & 0x01 != 0);
285		self.f.set_n(false);
286		self.f.set_h(false);
287	}
288
289	fn rl(&mut self, reg_id: u8) {
290		let value = self.get_r8_by_id(reg_id);
291		let carry = value & 0x80 != 0;
292		let value = value.wrapping_shl(1) | self.f.get_c() as u8;
293		self.set_r8_by_id(reg_id, value);
294		self.f.set_z(value == 0);
295		self.f.set_c(carry);
296		self.f.set_n(false);
297		self.f.set_h(false);
298	}
299
300	fn rrc(&mut self, reg_id: u8) {
301		let value = self.get_r8_by_id(reg_id);
302		let value = value.rotate_right(1);
303		self.set_r8_by_id(reg_id, value);
304		self.f.set_z(value == 0);
305		self.f.set_c(value & 0x80 != 0);
306		self.f.set_n(false);
307		self.f.set_h(false);
308	}
309
310	fn rr(&mut self, reg_id: u8) {
311		let value = self.get_r8_by_id(reg_id);
312		let carry = value & 0x01 != 0;
313		let value = value.wrapping_shr(1) | (self.f.get_c() as u8) << 7;
314		self.set_r8_by_id(reg_id, value);
315		self.f.set_z(value == 0);
316		self.f.set_c(carry);
317		self.f.set_n(false);
318		self.f.set_h(false);
319	}
320
321	fn sla(&mut self, reg_id: u8) {
322		let value = self.get_r8_by_id(reg_id);
323		self.f.set_c(value & 0x80 != 0);
324		let value = value.wrapping_shl(1);
325		self.set_r8_by_id(reg_id, value);
326		self.f.set_z(value == 0);
327		self.f.set_h(false);
328		self.f.set_n(false);
329	}
330
331	fn sra(&mut self, reg_id: u8) {
332		let value = self.get_r8_by_id(reg_id);
333		self.f.set_c(value & 0x01 != 0);
334		let value = value.wrapping_shr(1) | (value & 0x80);
335		self.set_r8_by_id(reg_id, value);
336		self.f.set_z(value == 0);
337		self.f.set_h(false);
338		self.f.set_n(false);
339	}
340
341	fn swap(&mut self, reg_id: u8) {
342		let value = self.get_r8_by_id(reg_id).rotate_left(4);
343		self.set_r8_by_id(reg_id, value);
344		self.f.value = 0;
345		self.f.set_z(value == 0);
346	}
347
348	fn srl(&mut self, reg_id: u8) {
349		let value = self.get_r8_by_id(reg_id);
350		self.f.set_c(value & 0x01 != 0);
351		let value = value.wrapping_shr(1);
352		self.set_r8_by_id(reg_id, value);
353		self.f.set_z(value == 0);
354		self.f.set_h(false);
355		self.f.set_n(false);
356	}
357
358	fn ret_cc(&mut self, condition: bool) {
359		if condition {
360			self.pc = self.pop();
361			self.cycles_elapsed += 2; // pop already takes care of 2 extra cycles.
362		} else {
363			self.cycles_elapsed += 1;
364		}
365	}
366
367	fn pop(&mut self) -> u16 {
368		let mut result = (self.read(self.sp) as u16) << 8;
369		self.sp = self.sp.wrapping_add(1);
370		result |= self.read(self.sp) as u16;
371		self.sp = self.sp.wrapping_add(1);
372		self.cycles_elapsed += 2;
373		result
374	}
375
376	fn jp_cc(&mut self, condition: bool) {
377		if condition {
378			self.pc = (self.read_pc() as u16) | (self.read_pc() as u16) << 8;
379			self.cycles_elapsed += 1;
380		} else {
381			self.read_pc();
382			self.read_pc();
383		}
384	}
385
386	fn call_cc(&mut self, condition: bool) {
387		if condition {
388			self.push(self.pc + 2);
389			self.pc = (self.read_pc() as u16) | (self.read_pc() as u16) << 8;
390			self.cycles_elapsed += 1;
391		} else {
392			self.read_pc();
393			self.read_pc();
394		}
395	}
396
397	fn push(&mut self, value: u16) {
398		self.sp = self.sp.wrapping_sub(1);
399		self.write(self.sp, (value & 0xFF) as u8);
400		self.sp = self.sp.wrapping_sub(1);
401		self.write(self.sp, (value >> 8) as u8);
402		self.cycles_elapsed += 3;
403	}
404
405	/// Steps the CPU forward by one instruction.
406	/// [`self.cycles_elapsed`][Self::cycles_elapsed] is updated accordingly.
407	pub fn tick(&mut self) -> TickResult {
408		match self.read_pc() {
409			/* nop */ 0x00 => {}
410			/* ld bc, u16 */
411			0x01 => {
412				self.c = self.read_pc();
413				self.b = self.read_pc();
414			}
415			/* ld [bc], a */
416			0x02 => {
417				self.write(self.get_bc(), self.a);
418				self.cycles_elapsed += 1;
419			}
420			/* inc bc */
421			0x03 => {
422				self.set_bc(self.get_bc().wrapping_add(1));
423				self.cycles_elapsed += 1;
424			}
425			/* inc r8 */
426			opcode @ (0x04 | 0x0C | 0x14 | 0x1C | 0x24 | 0x2C | 0x34 | 0x3C) => {
427				let reg_id = opcode >> 3;
428				let value = self.get_r8_by_id(reg_id).wrapping_add(1);
429				self.set_r8_by_id(reg_id, value);
430				self.f.set_z(value == 0);
431				self.f.set_n(false);
432				self.f.set_h(value & 0xF == 0);
433			}
434			/* dec r8 */
435			opcode @ (0x05 | 0x0D | 0x15 | 0x1D | 0x25 | 0x2D | 0x35 | 0x3D) => {
436				let reg_id = opcode >> 3;
437				let value = self.get_r8_by_id(reg_id).wrapping_sub(1);
438				self.set_r8_by_id(reg_id, value);
439				self.f.set_z(value == 0);
440				self.f.set_n(true);
441				self.f.set_h(value & 0xF == 0xF);
442			}
443			/* ld r8, u8 */
444			opcode @ (0x06 | 0x0E | 0x16 | 0x1E | 0x26 | 0x2E | 0x36 | 0x3E) => {
445				let value = self.read_pc();
446				self.set_r8_by_id(opcode >> 3, value);
447			}
448			/* rlca */
449			0x07 => {
450				self.rlc(7);
451				self.f.set_z(false);
452			}
453			/* ld [u16], sp */
454			0x08 => {
455				let pointer = u16::from_le_bytes([self.read_pc(), self.read_pc()]);
456				self.write(pointer, (self.sp & 0xFF) as u8);
457				self.write(pointer + 1, (self.sp >> 8) as u8);
458				self.cycles_elapsed += 4;
459			}
460			/* add hl, bc */
461			0x09 => {
462				self.add_hl_r16(self.get_bc());
463			}
464			/* ld a, [bc] */
465			0x0A => {
466				self.a = self.read(self.get_bc());
467				self.cycles_elapsed += 1;
468			}
469			/* dec bc */
470			0x0B => {
471				self.set_bc(self.get_bc().wrapping_sub(1));
472				self.cycles_elapsed += 1;
473			}
474			/* rrca */
475			0x0F => {
476				self.rrc(7);
477				self.f.set_z(false);
478			}
479			/* stop */
480			0x10 => {
481				self.read_pc();
482				return TickResult::Stop;
483			}
484			/* ld de, u16 */
485			0x11 => {
486				self.e = self.read_pc();
487				self.d = self.read_pc();
488			}
489			/* ld [de], a */
490			0x12 => {
491				self.write(self.get_de(), self.a);
492				self.cycles_elapsed += 1;
493			}
494			/* inc de */
495			0x13 => {
496				self.set_de(self.get_de().wrapping_add(1));
497				self.cycles_elapsed += 1;
498			}
499			/* rla */
500			0x17 => {
501				self.rl(7);
502				self.f.set_z(false);
503			}
504			/* jr u8 */ 0x18 => {
505				self.jr_cc(true);
506			}
507			/* add hl, de */
508			0x19 => {
509				self.add_hl_r16(self.get_de());
510			}
511			/* ld a, [de] */
512			0x1A => {
513				self.a = self.read(self.get_de());
514				self.cycles_elapsed += 1;
515			}
516			/* dec de */
517			0x1B => {
518				self.set_de(self.get_de().wrapping_sub(1));
519				self.cycles_elapsed += 1;
520			}
521			/* rra */
522			0x1F => {
523				self.rr(7);
524				self.f.set_z(false);
525			}
526			/* jr nz */ 0x20 => {
527				self.jr_cc(!self.f.get_z());
528			}
529			/* ld hl, u16 */
530			0x21 => {
531				self.l = self.read_pc();
532				self.h = self.read_pc();
533			}
534			/* ld [hli], a */
535			0x22 => {
536				self.write(self.get_hl(), self.a);
537				self.set_hl(self.get_hl().wrapping_add(1));
538				self.cycles_elapsed += 1;
539			}
540			/* inc hl */
541			0x23 => {
542				self.set_hl(self.get_hl().wrapping_add(1));
543				self.cycles_elapsed += 1;
544			}
545			/* daa */
546			0x27 => {
547				if !self.f.get_n() && self.a >= 0x9A {
548					self.f.set_c(true);
549				}
550				if !self.f.get_n() && self.a & 0xF >= 0xA {
551					self.f.set_h(true);
552				}
553				let adjustment =
554					if self.f.get_h() { 0x6 } else { 0 } | if self.f.get_c() { 0x60 } else { 0 };
555				if self.f.get_n() {
556					self.a = self.a.wrapping_sub(adjustment);
557				} else {
558					self.a = self.a.wrapping_add(adjustment);
559				}
560				self.f.set_z(self.a == 0);
561				self.f.set_h(false);
562			}
563			/* jr z */ 0x28 => {
564				self.jr_cc(self.f.get_z());
565			}
566			/* add hl, hl */
567			0x29 => {
568				self.add_hl_r16(self.get_hl());
569			}
570			/* ld a, [hli] */
571			0x2A => {
572				self.a = self.read(self.get_hl());
573				self.set_hl(self.get_hl().wrapping_add(1));
574				self.cycles_elapsed += 1;
575			}
576			/* dec hl */
577			0x2B => {
578				self.set_hl(self.get_hl().wrapping_sub(1));
579				self.cycles_elapsed += 1;
580			}
581			/* cpl */ 0x2F => {
582				self.a = !self.a;
583			}
584			/* jr nc */ 0x30 => {
585				self.jr_cc(!self.f.get_c());
586			}
587			/* ld sp, u16 */
588			0x31 => {
589				self.sp = u16::from_le_bytes([self.read_pc(), self.read_pc()]);
590			}
591			/* ld [hld], a */
592			0x32 => {
593				self.write(self.get_hl(), self.a);
594				self.set_hl(self.get_hl().wrapping_sub(1));
595				self.cycles_elapsed += 1;
596			}
597			/* inc sp */
598			0x33 => {
599				self.sp = self.sp.wrapping_add(1);
600				self.cycles_elapsed += 1;
601			}
602			/* scf */
603			0x37 => {
604				self.f.set_n(false);
605				self.f.set_h(false);
606				self.f.set_c(true);
607			}
608			/* jr c */ 0x38 => {
609				self.jr_cc(self.f.get_c());
610			}
611			/* add hl, sp */ 0x39 => {
612				self.add_hl_r16(self.sp);
613			}
614			/* ld a, [hld] */
615			0x3A => {
616				self.a = self.read(self.get_hl());
617				self.set_hl(self.get_hl().wrapping_sub(1));
618				self.cycles_elapsed += 1;
619			}
620			/* dec sp */
621			0x3B => {
622				self.sp = self.sp.wrapping_sub(1);
623				self.cycles_elapsed += 1;
624			}
625			/* ccf */
626			0x3F => {
627				self.f.set_n(false);
628				self.f.set_h(false);
629				self.f.set_c(!self.f.get_c());
630			}
631
632			/* ld b,b */
633			0x40 => {
634				return TickResult::Break;
635			}
636			/* ld d, d */
637			0x52 => {
638				return TickResult::Debug;
639			}
640			/* ld [hl], [hl] is actually halt */
641			0x76 => {
642				return TickResult::Halt;
643			}
644			/* ld r8,r8 family, special cases handled above */
645			opcode @ 0x40..=0x7F => {
646				let value = self.get_r8_by_id(opcode & 7);
647				self.set_r8_by_id((opcode >> 3) & 7, value);
648			}
649
650			/* add a, r8 */
651			opcode @ 0x80..=0x87 => {
652				let value = self.get_r8_by_id(opcode & 7);
653				self.add(value, false);
654			}
655			/* adc a, r8 */
656			opcode @ 0x88..=0x8F => {
657				let value = self.get_r8_by_id(opcode & 7);
658				self.add(value, self.f.get_c());
659			}
660			/* sub a, r8 */
661			opcode @ 0x90..=0x97 => {
662				let value = self.get_r8_by_id(opcode & 7);
663				self.sub(value, false);
664			}
665			/* sbc a, r8 */
666			opcode @ 0x98..=0x9F => {
667				let value = self.get_r8_by_id(opcode & 7);
668				self.sub(value, self.f.get_c());
669			}
670			/* and a, r8 */
671			opcode @ 0xA0..=0xA7 => {
672				let value = self.get_r8_by_id(opcode & 7);
673				self.and(value);
674			}
675			/* xor a, r8 */
676			opcode @ 0xA8..=0xAF => {
677				let value = self.get_r8_by_id(opcode & 7);
678				self.xor(value);
679			}
680			/* or a, r8 */
681			opcode @ 0xB0..=0xB7 => {
682				let value = self.get_r8_by_id(opcode & 7);
683				self.or(value);
684			}
685			/* cp a, r8 */
686			opcode @ 0xB8..=0xBF => {
687				let value = self.get_r8_by_id(opcode & 7);
688				self.cp(value);
689			}
690
691			/* ret nz */
692			0xC0 => {
693				self.ret_cc(!self.f.get_z());
694			}
695			/* pop bc */
696			0xC1 => {
697				let value = self.pop();
698				self.set_bc(value);
699			}
700			/* jp nz */
701			0xC2 => {
702				self.jp_cc(!self.f.get_z());
703			}
704			/* jp */
705			0xC3 => {
706				self.jp_cc(true);
707			}
708			/* call nz */
709			0xC4 => {
710				self.call_cc(!self.f.get_z());
711			}
712			/* push bc */
713			0xC5 => {
714				self.push(self.get_bc());
715			}
716			/* add a, u8 */
717			0xC6 => {
718				let value = self.read_pc();
719				self.add(value, false)
720			}
721			/* rst xx */
722			opcode @ (0xC7 | 0xCF | 0xD7 | 0xDF | 0xE7 | 0xEF | 0xF7 | 0xFF) => {
723				self.push(self.pc);
724				self.pc = (opcode & 7).into();
725				self.cycles_elapsed += 1;
726			}
727			/* ret z */
728			0xC8 => {
729				self.ret_cc(self.f.get_z());
730			}
731			/* ret */
732			0xC9 => {
733				self.ret_cc(true);
734			}
735			/* jp z */
736			0xCA => {
737				self.jp_cc(self.f.get_z());
738			}
739			/* prefix byte */
740			0xCB => {
741				match self.read_pc() {
742					/* rlc r8 */
743					opcode @ 0x00..=0x07 => self.rlc(opcode & 7),
744					/* rrc r8 */
745					opcode @ 0x08..=0x0F => self.rrc(opcode & 7),
746					/* rl r8 */
747					opcode @ 0x10..=0x17 => self.rl(opcode & 7),
748					/* rr r8 */
749					opcode @ 0x18..=0x1F => self.rr(opcode & 7),
750					/* sla r8 */
751					opcode @ 0x20..=0x27 => self.sla(opcode & 7),
752					/* sra r8 */
753					opcode @ 0x28..=0x2F => self.sra(opcode & 7),
754					/* swap r8 */
755					opcode @ 0x30..=0x37 => self.swap(opcode & 7),
756					/* srl r8 */
757					opcode @ 0x38..=0x3F => self.srl(opcode & 7),
758					/* bit r8 */
759					opcode @ 0x40..=0x7F => {
760						let value = self.get_r8_by_id(opcode & 7)
761							& 1u8.overflowing_shl((opcode >> 3).into()).0;
762						self.f.set_z(value == 0);
763					}
764					/* res n, r8 */
765					opcode @ 0x80..=0xBF => {
766						let mut value = self.get_r8_by_id(opcode & 7);
767						value &= !1u8.overflowing_shl((opcode >> 3).into()).0; // *evil grin*
768						self.set_r8_by_id(opcode & 7, value);
769					}
770					/* set n, r8 */
771					opcode @ 0xC0..=0xFF => {
772						let mut value = self.get_r8_by_id(opcode & 7);
773						value |= 1u8.overflowing_shl((opcode >> 3).into()).0; // *evil grin*
774						self.set_r8_by_id(opcode & 7, value);
775					}
776				}
777			}
778			/* call z */
779			0xCC => {
780				self.call_cc(self.f.get_z());
781			}
782			/* call */
783			0xCD => {
784				self.call_cc(true);
785			}
786			/* adc a, u8 */
787			0xCE => {
788				let value = self.read_pc();
789				self.add(value, self.f.get_c());
790			}
791			/* ret nc */
792			0xD0 => {
793				self.ret_cc(!self.f.get_c());
794			}
795			/* pop de */
796			0xD1 => {
797				let value = self.pop();
798				self.set_de(value);
799			}
800			/* jp nc */
801			0xD2 => {
802				self.jp_cc(!self.f.get_c());
803			}
804			/* invalid opcode */
805			/* call nc */
806			0xD4 => {
807				self.call_cc(!self.f.get_c());
808			}
809			/* push de */
810			0xD5 => {
811				self.push(self.get_de());
812			}
813			/* sub a, u8 */
814			0xD6 => {
815				let value = self.read_pc();
816				self.sub(value, false);
817			}
818			/* ret c */
819			0xD8 => {
820				self.ret_cc(self.f.get_c());
821			}
822			/* reti */
823			0xD9 => {
824				self.ret_cc(true);
825				self.ime = true;
826			}
827			/* jp c */
828			0xDA => {
829				self.jp_cc(self.f.get_c());
830			}
831			/* invalid opcode */
832			/* call c */
833			0xDC => {
834				self.call_cc(self.f.get_c());
835			}
836			/* invalid opcode */
837			/* sbc a, u8 */
838			0xDE => {
839				let value = self.read_pc();
840				self.sub(value, self.f.get_c());
841			}
842			/* ldh [u16], a */
843			0xE0 => {
844				let value = self.read_pc() as u16;
845				self.write(0xFF00 | value, self.a);
846				self.cycles_elapsed += 1;
847			}
848			/* pop hl */
849			0xE1 => {
850				let value = self.pop();
851				self.set_hl(value);
852			}
853			/* ldh [c], a */
854			0xE2 => {
855				self.write(0xFF00 | self.c as u16, self.a);
856				self.cycles_elapsed += 1;
857			}
858			/* invalid opcode */
859			/* invalid opcode */
860			/* push hl */
861			0xE5 => {
862				self.push(self.get_hl());
863			}
864			/* and a, u8 */
865			0xE6 => {
866				let value = self.read_pc();
867				self.and(value);
868			}
869			/* add sp, u8 */
870			0xE8 => {
871				let value = self.read_pc() as u16;
872				let old_sp = self.sp;
873				self.sp = self.sp.wrapping_add(value);
874				self.f.set_h((old_sp & 0xFFF) + (value & 0xFFF) > 0xFFF);
875				self.f.set_c(old_sp > self.sp);
876				self.f.set_z(false);
877				self.f.set_n(false);
878				self.cycles_elapsed += 2;
879			}
880			/* jp hl */
881			0xE9 => {
882				self.pc = self.get_hl();
883				self.cycles_elapsed += 1;
884			}
885			/* ld [u16], a */
886			0xEA => {
887				let address = u16::from_le_bytes([self.read_pc(), self.read_pc()]);
888				self.write(address, self.a);
889				self.cycles_elapsed += 1;
890			}
891			/* invalid opcode */
892			/* invalid opcode */
893			/* invalid opcode */
894			/* xor a, u8 */
895			0xEE => {
896				let value = self.read_pc();
897				self.xor(value);
898			}
899			/* ldh a, [u16] */
900			0xF0 => {
901				let address = 0xFF00 | self.read_pc() as u16;
902				self.a = self.read(address);
903				self.cycles_elapsed += 1;
904			}
905			/* pop af */
906			0xF1 => {
907				let value = self.pop();
908				self.set_af(value);
909			}
910			/* ldh a, [c] */
911			0xF2 => {
912				self.a = self.read(0xFF00 | self.c as u16);
913				self.cycles_elapsed += 1;
914			}
915			/* di */
916			0xF3 => {
917				self.ime = false;
918			}
919			/* invalid opcode */
920			/* push af */
921			0xF5 => {
922				self.push(self.get_af());
923			}
924			/* or a, u8 */
925			0xF6 => {
926				let value = self.read_pc();
927				self.or(value);
928			}
929			/* ld hl, sp + u8 */
930			0xF8 => {
931				let value = self.read_pc() as u16;
932				let old_sp = self.sp;
933				self.set_hl(self.sp.wrapping_add(value));
934				self.f.set_h((old_sp & 0xFFF) + (value & 0xFFF) > 0xFFF);
935				self.f.set_c(old_sp > self.get_hl());
936				self.f.set_z(false);
937				self.f.set_n(false);
938				self.cycles_elapsed += 1;
939			}
940			/* jp hl */
941			0xF9 => {
942				self.sp = self.get_hl();
943			}
944			/* ld a, [u16] */
945			0xFA => {
946				let address = u16::from_le_bytes([self.read_pc(), self.read_pc()]);
947				self.a = self.read(address);
948				self.cycles_elapsed += 1;
949			}
950			/* ei */
951			0xFB => {
952				self.ime = true;
953			}
954			/* invalid opcode */
955			/* invalid opcode */
956			/* cp a, u8 */
957			0xFE => {
958				let value = self.read_pc();
959				self.cp(value);
960			}
961			0xD3 | 0xDB | 0xDD | 0xE3..=0xE4 | 0xEB..=0xED | 0xF4 | 0xFC..=0xFD => {
962				panic!("Invalid opcode")
963			}
964		}
965
966		TickResult::Ok
967	}
968}
969
970#[derive(Clone, Copy, Default)]
971struct CarryRetainer(u8, bool);
972
973impl CarryRetainer {
974	fn new() -> Self {
975		Default::default()
976	}
977}
978
979impl BitOrAssign<(u8, bool)> for CarryRetainer {
980	fn bitor_assign(&mut self, rhs: (u8, bool)) {
981		self.0 = rhs.0;
982		self.1 |= rhs.1;
983	}
984}
985
986impl<S: AddressSpace> fmt::Display for State<S> {
987	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
988		write!(
989			f,
990			"\
991a:  0x{:02x}
992bc: 0x{:02x}{:02x}
993de: 0x{:02x}{:02x}
994hl: 0x{:02x}{:02x}
995f: {}
996pc: 0x{:04x}
997sp: 0x{:04x}
998Interrupts {}abled
999Elapsed cycles: {}",
1000			self.a,
1001			self.b,
1002			self.c,
1003			self.d,
1004			self.e,
1005			self.h,
1006			self.l,
1007			self.f,
1008			self.pc,
1009			self.sp,
1010			if self.ime { "en" } else { "dis" },
1011			self.cycles_elapsed
1012		)
1013	}
1014}
1015
1016#[cfg(test)]
1017mod tests {
1018	use std::{cell::RefCell, fmt::Debug};
1019
1020	use super::*;
1021
1022	static REG_NAMES: [&str; 8] = ["b", "c", "d", "e", "h", "l", "[hl]", "a"];
1023	static OP_NAMES: [&str; 8] = ["add", "adc", "sub", "sbc", "and", "xor", "or", "cp"];
1024
1025	#[derive(Debug, Clone, Copy)]
1026	struct DummyAddrSpace;
1027	impl AddressSpace for DummyAddrSpace {
1028		fn read(&self, _address: u16) -> u8 {
1029			0
1030		}
1031		fn write(&mut self, _address: u16, _value: u8) {
1032			/* Nothing. */
1033		}
1034	}
1035
1036	#[derive(Debug, Clone, Copy)]
1037	struct TinyAddrSpace<'a, const N: usize>(&'a RefCell<[u8; N]>);
1038	impl<const N: usize> AddressSpace for TinyAddrSpace<'_, N> {
1039		fn read(&self, address: u16) -> u8 {
1040			self.0.borrow()[address as usize % N]
1041		}
1042		fn write(&mut self, address: u16, value: u8) {
1043			self.0.borrow_mut()[address as usize % N] = value;
1044		}
1045	}
1046
1047	fn assert_flags<S: AddressSpace, M: Debug>(
1048		cpu: &State<S>,
1049		z: bool,
1050		n: bool,
1051		h: bool,
1052		c: bool,
1053		msg: M,
1054	) {
1055		let assert_flag = |flag, expected, ch| {
1056			assert!(
1057				flag == expected,
1058				"{} is {} for {:?}, it shouldn't",
1059				ch,
1060				if flag { "set" } else { "reset" },
1061				msg
1062			)
1063		};
1064		assert_flag(cpu.f.get_z(), z, 'Z');
1065		assert_flag(cpu.f.get_n(), n, 'N');
1066		assert_flag(cpu.f.get_h(), h, 'H');
1067		assert_flag(cpu.f.get_c(), c, 'C');
1068	}
1069
1070	#[test]
1071	fn add_hl_16() {
1072		let mut cpu = State::new(DummyAddrSpace);
1073		cpu.f.set_z(false);
1074
1075		for hl in 0..=u16::MAX {
1076			// Let's assume that the function is symmetrical, otherwise the test takes even more forever.
1077			for operand in hl..=u16::MAX {
1078				cpu.cycles_elapsed = 0;
1079				let params = (hl, operand);
1080				cpu.set_hl(hl);
1081
1082				cpu.add_hl_r16(operand);
1083
1084				let h = (hl & 0xFFF) + (operand & 0xFFF) > 0xFFF;
1085				let c = hl as u32 + operand as u32 > 0xFFFF;
1086				assert_flags(&cpu, false, false, h, c, &params);
1087				assert_eq!(cpu.get_hl(), hl.wrapping_add(operand), "{:?}", params);
1088				assert_eq!(cpu.cycles_elapsed, 1);
1089			}
1090		}
1091	}
1092
1093	#[test]
1094	fn add() {
1095		let mut cpu = State::new(DummyAddrSpace);
1096
1097		for a in 0..=u8::MAX {
1098			for operand in 0..=u8::MAX {
1099				for carry_in in [false, true] {
1100					cpu.cycles_elapsed = 0;
1101					let params = (a, operand, carry_in);
1102					cpu.a = a;
1103					cpu.f.set_n(true);
1104
1105					cpu.add(operand, carry_in);
1106
1107					let result = a.wrapping_add(operand).wrapping_add(carry_in.into());
1108					let z = result == 0;
1109					let h = (a & 0xF) + (operand & 0xF) + carry_in as u8 > 0xF;
1110					let c = a as u16 + operand as u16 + carry_in as u16 > 0xFF;
1111					assert_flags(&cpu, z, false, h, c, &params);
1112					assert_eq!(cpu.a, result, "{:?}", params);
1113					assert_eq!(cpu.cycles_elapsed, 0);
1114				}
1115			}
1116		}
1117	}
1118
1119	#[test]
1120	fn sub() {
1121		let mut cpu = State::new(DummyAddrSpace);
1122
1123		for a in 0..=u8::MAX {
1124			for operand in 0..=u8::MAX {
1125				for carry_in in [false, true] {
1126					cpu.cycles_elapsed = 0;
1127					let params = (a, operand, carry_in);
1128					cpu.a = a;
1129					cpu.f.set_n(false);
1130
1131					cpu.sub(operand, carry_in);
1132
1133					let result = a.wrapping_sub(operand).wrapping_sub(carry_in.into());
1134					let z = result == 0;
1135					let h = (a & 0xF) as i8 - (operand & 0xF) as i8 - (carry_in as i8) < 0;
1136					let c = (a as i32 - operand as i32 - carry_in as i32) < 0;
1137					assert_flags(&cpu, z, true, h, c, &params);
1138					assert_eq!(cpu.a, result, "{:?}", params);
1139					assert_eq!(cpu.cycles_elapsed, 0);
1140				}
1141			}
1142		}
1143	}
1144
1145	// Bit ops are trivial enough to skip testing them
1146
1147	#[test]
1148	fn cp() {
1149		let mut cpu = State::new(DummyAddrSpace);
1150
1151		for a in 0..=u8::MAX {
1152			for operand in 0..=u8::MAX {
1153				cpu.cycles_elapsed = 0;
1154				let params = (a, operand);
1155				cpu.a = a;
1156				cpu.f.set_n(false);
1157
1158				cpu.cp(operand);
1159
1160				let z = a.wrapping_sub(operand) == 0;
1161				let h = (a & 0xF) as i8 - ((operand & 0xF) as i8) < 0;
1162				let c = (a as i32 - operand as i32) < 0;
1163				assert_flags(&cpu, z, true, h, c, &params);
1164				assert_eq!(cpu.a, a, "{:?}", params);
1165				assert_eq!(cpu.cycles_elapsed, 0);
1166			}
1167		}
1168	}
1169
1170	#[test]
1171	fn rlc() {
1172		let mut cpu = State::new(DummyAddrSpace);
1173
1174		for b in 0..=u8::MAX {
1175			cpu.cycles_elapsed = 0;
1176			let params = b;
1177			cpu.b = b;
1178
1179			cpu.rlc(0);
1180
1181			let result = b.rotate_left(1);
1182			let z = result == 0;
1183			let c = b & 0x80 != 0;
1184			assert_flags(&cpu, z, false, false, c, &params);
1185			assert_eq!(cpu.b, result, "{:?}", params);
1186			assert_eq!(cpu.cycles_elapsed, 0);
1187		}
1188	}
1189
1190	#[test]
1191	fn rl() {
1192		let mut cpu = State::new(DummyAddrSpace);
1193
1194		for c in 0..=u8::MAX {
1195			for carry in [false, true] {
1196				cpu.cycles_elapsed = 0;
1197				let params = (c, carry);
1198				cpu.c = c;
1199				cpu.f.set_c(carry);
1200
1201				cpu.rl(1);
1202
1203				let result = c.wrapping_shl(1) | carry as u8;
1204				let z = result == 0;
1205				let c = c & 0x80 != 0;
1206				assert_flags(&cpu, z, false, false, c, &params);
1207				assert_eq!(cpu.c, result, "{:?}", params);
1208				assert_eq!(cpu.cycles_elapsed, 0);
1209			}
1210		}
1211	}
1212
1213	#[test]
1214	fn rrc() {
1215		let mut cpu = State::new(DummyAddrSpace);
1216
1217		for d in 0..=u8::MAX {
1218			cpu.cycles_elapsed = 0;
1219			let params = d;
1220			cpu.d = d;
1221
1222			cpu.rrc(2);
1223
1224			let result = d.rotate_right(1);
1225			let z = result == 0;
1226			let c = d & 0x01 != 0;
1227			assert_flags(&cpu, z, false, false, c, &params);
1228			assert_eq!(cpu.d, result, "{:?}", params);
1229			assert_eq!(cpu.cycles_elapsed, 0);
1230		}
1231	}
1232
1233	#[test]
1234	fn rr() {
1235		let mut cpu = State::new(DummyAddrSpace);
1236
1237		for e in 0..=u8::MAX {
1238			for carry in [false, true] {
1239				cpu.cycles_elapsed = 0;
1240				let params = (e, carry);
1241				cpu.e = e;
1242				cpu.f.set_c(carry);
1243
1244				cpu.rr(3);
1245
1246				let result = e.wrapping_shr(1) | (carry as u8) << 7;
1247				let z = result == 0;
1248				let c = e & 0x01 != 0;
1249				assert_flags(&cpu, z, false, false, c, &params);
1250				assert_eq!(cpu.e, result, "{:?}", params);
1251				assert_eq!(cpu.cycles_elapsed, 0);
1252			}
1253		}
1254	}
1255
1256	#[test]
1257	fn sla() {
1258		let mut cpu = State::new(DummyAddrSpace);
1259
1260		for h in 0..=u8::MAX {
1261			cpu.cycles_elapsed = 0;
1262			let params = h;
1263			cpu.h = h;
1264
1265			cpu.sla(4);
1266
1267			let result = h.wrapping_shl(1);
1268			let z = result == 0;
1269			let c = h & 0x80 != 0;
1270			assert_flags(&cpu, z, false, false, c, &params);
1271			assert_eq!(cpu.h, result, "{:?}", params);
1272			assert_eq!(cpu.cycles_elapsed, 0);
1273		}
1274	}
1275
1276	#[test]
1277	fn sra() {
1278		let mut cpu = State::new(DummyAddrSpace);
1279
1280		for l in 0..=u8::MAX {
1281			cpu.cycles_elapsed = 0;
1282			let params = l;
1283			cpu.l = l;
1284
1285			cpu.sra(5);
1286
1287			let result = l.wrapping_shr(1) | l & 0x80;
1288			let z = result == 0;
1289			let c = l & 0x01 != 0;
1290			assert_flags(&cpu, z, false, false, c, &params);
1291			assert_eq!(cpu.l, result, "{:?}", params);
1292			assert_eq!(cpu.cycles_elapsed, 0);
1293		}
1294	}
1295
1296	#[test]
1297	fn swap() {
1298		let mem = RefCell::new([0]);
1299		let mut cpu = State::new(TinyAddrSpace(&mem));
1300
1301		for hl_ in 0..=u8::MAX {
1302			cpu.cycles_elapsed = 0;
1303			let params = hl_;
1304			mem.borrow_mut()[0] = hl_;
1305
1306			cpu.swap(6);
1307
1308			let result = hl_.rotate_right(4);
1309			let z = result == 0;
1310			assert_flags(&cpu, z, false, false, false, &params);
1311			assert_eq!(mem.borrow()[0], result, "{:?}", params);
1312			assert_eq!(cpu.cycles_elapsed, 2); // Accesses to and from [hl]
1313		}
1314	}
1315
1316	#[test]
1317	fn srl() {
1318		let mut cpu = State::new(DummyAddrSpace);
1319
1320		for a in 0..=u8::MAX {
1321			cpu.cycles_elapsed = 0;
1322			let params = a;
1323			cpu.a = a;
1324
1325			cpu.srl(7);
1326
1327			let result = a.wrapping_shr(1);
1328			let z = result == 0;
1329			let c = a & 0x01 != 0;
1330			assert_flags(&cpu, z, false, false, c, &params);
1331			assert_eq!(cpu.a, result, "{:?}", params);
1332			assert_eq!(cpu.cycles_elapsed, 0);
1333		}
1334	}
1335
1336	#[test]
1337	fn ld_r8_r8() {
1338		let mem = RefCell::new([0; 2]);
1339		let mut cpu = State::new(TinyAddrSpace(&mem));
1340
1341		for dest in 0..=7 {
1342			for src in 0..=7 {
1343				let mut regs = [b'G', b'A', b'M', b'E', b' ', b'B', b'O', b'Y']; // 8 unique values :)
1344				for i in 0..=7 {
1345					cpu.set_r8_by_id(i, regs[i as usize]);
1346				}
1347				assert_eq!(cpu.get_hl() % 2, 0); // Otherwise [hl] doesn't point to the first cell
1348
1349				cpu.pc = 1;
1350				mem.borrow_mut()[1] = 0x40 | dest << 3 | src; // Write the instruction
1351				cpu.cycles_elapsed = 0;
1352
1353				let ret = cpu.tick();
1354
1355				regs[dest as usize] = regs[src as usize];
1356				for i in 0..=7 {
1357					assert_eq!(
1358						if i == 6 {
1359							mem.borrow_mut()[0]
1360						} else {
1361							cpu.get_r8_by_id(i)
1362						},
1363						regs[i as usize],
1364						"from {} to {}",
1365						src,
1366						dest
1367					);
1368				}
1369
1370				match (dest, src) {
1371					(0, 0) => assert_eq!(ret, TickResult::Break),
1372					(2, 2) => assert_eq!(ret, TickResult::Debug),
1373					(6, 6) => assert_eq!(ret, TickResult::Halt),
1374					_ => assert_eq!(ret, TickResult::Ok, "from {} to {}", src, dest),
1375				}
1376
1377				if ret != TickResult::Halt {
1378					assert_eq!(
1379						cpu.cycles_elapsed,
1380						1 + (dest == 6) as usize + (src == 6) as usize,
1381						"from {} to {}",
1382						src,
1383						dest
1384					);
1385				}
1386			}
1387		}
1388	}
1389
1390	#[test]
1391	fn ld_r8_n8() {
1392		let mem = RefCell::new([0; 3]);
1393		let mut cpu = State::new(TinyAddrSpace(&mem));
1394
1395		mem.borrow_mut()[1] = 42;
1396		for dest in 0..=7 {
1397			let mut regs = [b'G', b'A', b'M', b'E', b' ', b'B', b'O', b'Y']; // 8 unique values :)
1398			for i in 0..=7 {
1399				cpu.set_r8_by_id(i, regs[i as usize]);
1400			}
1401			assert_eq!(cpu.get_hl() % 3, 2); // Otherwise [hl] doesn't point to the last cell
1402
1403			cpu.pc = 0;
1404			mem.borrow_mut()[0] = 0x06 | dest << 3; // Write the instruction
1405			cpu.cycles_elapsed = 0;
1406
1407			let ret = cpu.tick();
1408
1409			regs[dest as usize] = 42;
1410			for i in 0..=7 {
1411				assert_eq!(
1412					if i == 6 {
1413						mem.borrow_mut()[2]
1414					} else {
1415						cpu.get_r8_by_id(i)
1416					},
1417					regs[i as usize],
1418					"to {}",
1419					dest
1420				);
1421			}
1422
1423			assert_eq!(ret, TickResult::Ok, "to {}", dest);
1424
1425			assert_eq!(cpu.cycles_elapsed, 2 + (dest == 6) as usize, "to {}", dest);
1426		}
1427	}
1428
1429	#[test]
1430	fn inc_dec_r8() {
1431		let mem = RefCell::new([0; 3]);
1432		let mut cpu = State::new(TinyAddrSpace(&mem));
1433
1434		let mut regs = [b'G', b'A', b'M', b'E', b' ', b'B', b'O', b'Y']; // 8 unique values :)
1435		for i in 0..=7 {
1436			cpu.set_r8_by_id(i, regs[i as usize]);
1437		}
1438		assert_eq!(cpu.get_hl() % 3, 2); // Otherwise [hl] doesn't point to the last cell
1439
1440		for dest in 0..=7 {
1441			for dec in [false, true] {
1442				cpu.pc = 0;
1443				mem.borrow_mut()[0] = 0x04 | dest << 3 | dec as u8; // Write the instruction
1444				cpu.cycles_elapsed = 0;
1445				let c = dest > 3;
1446				cpu.f.set_c(c);
1447
1448				let ret = cpu.tick();
1449
1450				regs[dest as usize] =
1451					regs[dest as usize].wrapping_add(if dec { u8::MAX } else { 1 });
1452				for i in 0..=7 {
1453					assert_eq!(
1454						if i == 6 {
1455							mem.borrow_mut()[2]
1456						} else {
1457							cpu.get_r8_by_id(i)
1458						},
1459						regs[i as usize],
1460						"{} {}",
1461						if dec { "dec" } else { "inc" },
1462						dest
1463					);
1464				}
1465
1466				assert_eq!(ret, TickResult::Ok, "to {}", dest);
1467
1468				let z = regs[dest as usize] == 0;
1469				let h = regs[dest as usize] & 0xF == if dec { 0xF } else { 0 };
1470				assert_flags(&cpu, z, dec, h, c, (dec, dest));
1471				assert_eq!(
1472					cpu.cycles_elapsed,
1473					1 + (dest == 6) as usize * 2,
1474					"{} {}",
1475					if dec { "dec" } else { "inc" },
1476					dest
1477				);
1478			}
1479		}
1480	}
1481
1482	#[test]
1483	fn alu_r8() {
1484		let mem = RefCell::new([0; 3]);
1485		let mut cpu = State::new(TinyAddrSpace(&mem));
1486
1487		let ops: [&dyn Fn(u8, u8, bool) -> (u8, bool, bool, bool, bool); 8] = [
1488			&|a, operand, _carry| {
1489				// add
1490				let res = a as u16 + operand as u16;
1491				(
1492					res as u8,
1493					res == 0,
1494					false,
1495					(a & 0xF) + (operand & 0xF) > 0xF,
1496					res > 0xFF,
1497				)
1498			},
1499			&|a, operand, carry| {
1500				// adc
1501				let res = a as u16 + operand as u16 + carry as u16;
1502				(
1503					res as u8,
1504					res == 0,
1505					false,
1506					(a & 0xF) + (operand & 0xF) + carry as u8 > 0xF,
1507					res > 0xFF,
1508				)
1509			},
1510			&|a, operand, _carry| {
1511				// sub
1512				let res = a as i16 - operand as i16;
1513				(
1514					res as u8,
1515					res == 0,
1516					true,
1517					(a & 0xF) as i8 - ((operand & 0xF) as i8) < 0,
1518					res < 0,
1519				)
1520			},
1521			&|a, operand, carry| {
1522				// sbc
1523				let res = a as i16 - operand as i16 - carry as i16;
1524				(
1525					res as u8,
1526					res == 0,
1527					true,
1528					(a & 0xF) as i8 - (operand & 0xF) as i8 - (carry as i8) < 0,
1529					res < 0,
1530				)
1531			},
1532			&|a, operand, _carry| {
1533				// and
1534				let res = a & operand;
1535				(res as u8, res == 0, false, true, false)
1536			},
1537			&|a, operand, _carry| {
1538				// xor
1539				let res = a ^ operand;
1540				(res as u8, res == 0, false, false, false)
1541			},
1542			&|a, operand, _carry| {
1543				// or
1544				let res = a | operand;
1545				(res as u8, res == 0, false, false, false)
1546			},
1547			&|a, operand, _carry| {
1548				// cp
1549				let res = a as i16 - operand as i16;
1550				(
1551					a,
1552					res == 0,
1553					true,
1554					(a & 0xF) as i8 - ((operand & 0xF) as i8) < 0,
1555					res < 0,
1556				)
1557			},
1558		];
1559
1560		let regs = [b'G', b'A', b'M', b'E', b' ', b'B', b'O', b'Y']; // 8 unique values :)
1561		mem.borrow_mut()[1] = 42;
1562
1563		for op in 0..=7 {
1564			for carry_in in [false, true] {
1565				for operand in 0..=8 {
1566					let params = format!(
1567						"[c={}] {} a, {}",
1568						carry_in,
1569						OP_NAMES[op as usize],
1570						if operand == 8 {
1571							"42"
1572						} else {
1573							REG_NAMES[operand as usize]
1574						}
1575					);
1576
1577					for i in 0..=7 {
1578						cpu.set_r8_by_id(i, regs[i as usize]);
1579					}
1580					assert_eq!(cpu.get_hl() % 3, 2); // Otherwise [hl] doesn't point to the last cell
1581
1582					cpu.pc = 0;
1583					mem.borrow_mut()[0] = if operand == 8 {
1584						0xC6 | op << 3
1585					} else {
1586						0x80 | op << 3 | operand
1587					}; // Write the instruction
1588					cpu.cycles_elapsed = 0;
1589					cpu.f.set_c(carry_in);
1590
1591					let ret = cpu.tick();
1592
1593					let (res, z, n, h, c) = ops[op as usize](
1594						regs[7],
1595						if operand == 8 {
1596							42
1597						} else {
1598							regs[operand as usize]
1599						},
1600						carry_in,
1601					);
1602					for i in 0..=6 {
1603						assert_eq!(
1604							if i == 6 {
1605								mem.borrow_mut()[2]
1606							} else {
1607								cpu.get_r8_by_id(i)
1608							},
1609							regs[i as usize],
1610							"{:?}",
1611							params
1612						);
1613					}
1614					assert_eq!(cpu.a, res, "{:?}", params);
1615
1616					assert_eq!(ret, TickResult::Ok, "to {}", operand);
1617
1618					assert_flags(&cpu, z, n, h, c, &params);
1619					assert_eq!(
1620						cpu.cycles_elapsed,
1621						1 + (operand == 6) as usize + (operand == 8) as usize,
1622						"{:?}",
1623						params
1624					);
1625				}
1626
1627				// TODO: test with immediate operand as well
1628			}
1629		}
1630	}
1631}