1use crate::memory::AddressSpace;
10use std::{fmt, ops::BitOrAssign};
11
12pub struct Flags {
14 pub value: u8,
16}
17
18impl Flags {
19 pub fn get_z(&self) -> bool {
21 self.value & 0b10000000 != 0
22 }
23 pub fn get_n(&self) -> bool {
25 self.value & 0b01000000 != 0
26 }
27 pub fn get_h(&self) -> bool {
29 self.value & 0b00100000 != 0
30 }
31 pub fn get_c(&self) -> bool {
33 self.value & 0b00010000 != 0
34 }
35 pub fn set_z(&mut self, value: bool) {
37 self.value = self.value & 0b01110000 | (value as u8) << 7;
38 }
39 pub fn set_n(&mut self, value: bool) {
41 self.value = self.value & 0b10110000 | (value as u8) << 6;
42 }
43 pub fn set_h(&mut self, value: bool) {
45 self.value = self.value & 0b11010000 | (value as u8) << 5;
46 }
47 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#[derive(Debug, PartialEq, Eq)]
68pub enum TickResult {
69 Ok,
71 Break,
73 Debug,
75 Halt,
77 Stop,
79 InvalidOpcode,
81}
82
83pub struct State<S: AddressSpace> {
85 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 pub cycles_elapsed: usize,
101
102 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: 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 pub fn read(&self, address: u16) -> u8 {
188 self.address_space.read(address)
189 }
190 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 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 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); 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; } 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 pub fn tick(&mut self) -> TickResult {
408 match self.read_pc() {
409 0x00 => {}
410 0x01 => {
412 self.c = self.read_pc();
413 self.b = self.read_pc();
414 }
415 0x02 => {
417 self.write(self.get_bc(), self.a);
418 self.cycles_elapsed += 1;
419 }
420 0x03 => {
422 self.set_bc(self.get_bc().wrapping_add(1));
423 self.cycles_elapsed += 1;
424 }
425 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 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 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 0x07 => {
450 self.rlc(7);
451 self.f.set_z(false);
452 }
453 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 0x09 => {
462 self.add_hl_r16(self.get_bc());
463 }
464 0x0A => {
466 self.a = self.read(self.get_bc());
467 self.cycles_elapsed += 1;
468 }
469 0x0B => {
471 self.set_bc(self.get_bc().wrapping_sub(1));
472 self.cycles_elapsed += 1;
473 }
474 0x0F => {
476 self.rrc(7);
477 self.f.set_z(false);
478 }
479 0x10 => {
481 self.read_pc();
482 return TickResult::Stop;
483 }
484 0x11 => {
486 self.e = self.read_pc();
487 self.d = self.read_pc();
488 }
489 0x12 => {
491 self.write(self.get_de(), self.a);
492 self.cycles_elapsed += 1;
493 }
494 0x13 => {
496 self.set_de(self.get_de().wrapping_add(1));
497 self.cycles_elapsed += 1;
498 }
499 0x17 => {
501 self.rl(7);
502 self.f.set_z(false);
503 }
504 0x18 => {
505 self.jr_cc(true);
506 }
507 0x19 => {
509 self.add_hl_r16(self.get_de());
510 }
511 0x1A => {
513 self.a = self.read(self.get_de());
514 self.cycles_elapsed += 1;
515 }
516 0x1B => {
518 self.set_de(self.get_de().wrapping_sub(1));
519 self.cycles_elapsed += 1;
520 }
521 0x1F => {
523 self.rr(7);
524 self.f.set_z(false);
525 }
526 0x20 => {
527 self.jr_cc(!self.f.get_z());
528 }
529 0x21 => {
531 self.l = self.read_pc();
532 self.h = self.read_pc();
533 }
534 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 0x23 => {
542 self.set_hl(self.get_hl().wrapping_add(1));
543 self.cycles_elapsed += 1;
544 }
545 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 0x28 => {
564 self.jr_cc(self.f.get_z());
565 }
566 0x29 => {
568 self.add_hl_r16(self.get_hl());
569 }
570 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 0x2B => {
578 self.set_hl(self.get_hl().wrapping_sub(1));
579 self.cycles_elapsed += 1;
580 }
581 0x2F => {
582 self.a = !self.a;
583 }
584 0x30 => {
585 self.jr_cc(!self.f.get_c());
586 }
587 0x31 => {
589 self.sp = u16::from_le_bytes([self.read_pc(), self.read_pc()]);
590 }
591 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 0x33 => {
599 self.sp = self.sp.wrapping_add(1);
600 self.cycles_elapsed += 1;
601 }
602 0x37 => {
604 self.f.set_n(false);
605 self.f.set_h(false);
606 self.f.set_c(true);
607 }
608 0x38 => {
609 self.jr_cc(self.f.get_c());
610 }
611 0x39 => {
612 self.add_hl_r16(self.sp);
613 }
614 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 0x3B => {
622 self.sp = self.sp.wrapping_sub(1);
623 self.cycles_elapsed += 1;
624 }
625 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 0x40 => {
634 return TickResult::Break;
635 }
636 0x52 => {
638 return TickResult::Debug;
639 }
640 0x76 => {
642 return TickResult::Halt;
643 }
644 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 opcode @ 0x80..=0x87 => {
652 let value = self.get_r8_by_id(opcode & 7);
653 self.add(value, false);
654 }
655 opcode @ 0x88..=0x8F => {
657 let value = self.get_r8_by_id(opcode & 7);
658 self.add(value, self.f.get_c());
659 }
660 opcode @ 0x90..=0x97 => {
662 let value = self.get_r8_by_id(opcode & 7);
663 self.sub(value, false);
664 }
665 opcode @ 0x98..=0x9F => {
667 let value = self.get_r8_by_id(opcode & 7);
668 self.sub(value, self.f.get_c());
669 }
670 opcode @ 0xA0..=0xA7 => {
672 let value = self.get_r8_by_id(opcode & 7);
673 self.and(value);
674 }
675 opcode @ 0xA8..=0xAF => {
677 let value = self.get_r8_by_id(opcode & 7);
678 self.xor(value);
679 }
680 opcode @ 0xB0..=0xB7 => {
682 let value = self.get_r8_by_id(opcode & 7);
683 self.or(value);
684 }
685 opcode @ 0xB8..=0xBF => {
687 let value = self.get_r8_by_id(opcode & 7);
688 self.cp(value);
689 }
690
691 0xC0 => {
693 self.ret_cc(!self.f.get_z());
694 }
695 0xC1 => {
697 let value = self.pop();
698 self.set_bc(value);
699 }
700 0xC2 => {
702 self.jp_cc(!self.f.get_z());
703 }
704 0xC3 => {
706 self.jp_cc(true);
707 }
708 0xC4 => {
710 self.call_cc(!self.f.get_z());
711 }
712 0xC5 => {
714 self.push(self.get_bc());
715 }
716 0xC6 => {
718 let value = self.read_pc();
719 self.add(value, false)
720 }
721 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 0xC8 => {
729 self.ret_cc(self.f.get_z());
730 }
731 0xC9 => {
733 self.ret_cc(true);
734 }
735 0xCA => {
737 self.jp_cc(self.f.get_z());
738 }
739 0xCB => {
741 match self.read_pc() {
742 opcode @ 0x00..=0x07 => self.rlc(opcode & 7),
744 opcode @ 0x08..=0x0F => self.rrc(opcode & 7),
746 opcode @ 0x10..=0x17 => self.rl(opcode & 7),
748 opcode @ 0x18..=0x1F => self.rr(opcode & 7),
750 opcode @ 0x20..=0x27 => self.sla(opcode & 7),
752 opcode @ 0x28..=0x2F => self.sra(opcode & 7),
754 opcode @ 0x30..=0x37 => self.swap(opcode & 7),
756 opcode @ 0x38..=0x3F => self.srl(opcode & 7),
758 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 opcode @ 0x80..=0xBF => {
766 let mut value = self.get_r8_by_id(opcode & 7);
767 value &= !1u8.overflowing_shl((opcode >> 3).into()).0; self.set_r8_by_id(opcode & 7, value);
769 }
770 opcode @ 0xC0..=0xFF => {
772 let mut value = self.get_r8_by_id(opcode & 7);
773 value |= 1u8.overflowing_shl((opcode >> 3).into()).0; self.set_r8_by_id(opcode & 7, value);
775 }
776 }
777 }
778 0xCC => {
780 self.call_cc(self.f.get_z());
781 }
782 0xCD => {
784 self.call_cc(true);
785 }
786 0xCE => {
788 let value = self.read_pc();
789 self.add(value, self.f.get_c());
790 }
791 0xD0 => {
793 self.ret_cc(!self.f.get_c());
794 }
795 0xD1 => {
797 let value = self.pop();
798 self.set_de(value);
799 }
800 0xD2 => {
802 self.jp_cc(!self.f.get_c());
803 }
804 0xD4 => {
807 self.call_cc(!self.f.get_c());
808 }
809 0xD5 => {
811 self.push(self.get_de());
812 }
813 0xD6 => {
815 let value = self.read_pc();
816 self.sub(value, false);
817 }
818 0xD8 => {
820 self.ret_cc(self.f.get_c());
821 }
822 0xD9 => {
824 self.ret_cc(true);
825 self.ime = true;
826 }
827 0xDA => {
829 self.jp_cc(self.f.get_c());
830 }
831 0xDC => {
834 self.call_cc(self.f.get_c());
835 }
836 0xDE => {
839 let value = self.read_pc();
840 self.sub(value, self.f.get_c());
841 }
842 0xE0 => {
844 let value = self.read_pc() as u16;
845 self.write(0xFF00 | value, self.a);
846 self.cycles_elapsed += 1;
847 }
848 0xE1 => {
850 let value = self.pop();
851 self.set_hl(value);
852 }
853 0xE2 => {
855 self.write(0xFF00 | self.c as u16, self.a);
856 self.cycles_elapsed += 1;
857 }
858 0xE5 => {
862 self.push(self.get_hl());
863 }
864 0xE6 => {
866 let value = self.read_pc();
867 self.and(value);
868 }
869 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 0xE9 => {
882 self.pc = self.get_hl();
883 self.cycles_elapsed += 1;
884 }
885 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 0xEE => {
896 let value = self.read_pc();
897 self.xor(value);
898 }
899 0xF0 => {
901 let address = 0xFF00 | self.read_pc() as u16;
902 self.a = self.read(address);
903 self.cycles_elapsed += 1;
904 }
905 0xF1 => {
907 let value = self.pop();
908 self.set_af(value);
909 }
910 0xF2 => {
912 self.a = self.read(0xFF00 | self.c as u16);
913 self.cycles_elapsed += 1;
914 }
915 0xF3 => {
917 self.ime = false;
918 }
919 0xF5 => {
922 self.push(self.get_af());
923 }
924 0xF6 => {
926 let value = self.read_pc();
927 self.or(value);
928 }
929 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 0xF9 => {
942 self.sp = self.get_hl();
943 }
944 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 0xFB => {
952 self.ime = true;
953 }
954 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 }
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 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, ¶ms);
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, ¶ms);
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, ¶ms);
1138 assert_eq!(cpu.a, result, "{:?}", params);
1139 assert_eq!(cpu.cycles_elapsed, 0);
1140 }
1141 }
1142 }
1143 }
1144
1145 #[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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
1311 assert_eq!(mem.borrow()[0], result, "{:?}", params);
1312 assert_eq!(cpu.cycles_elapsed, 2); }
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, ¶ms);
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']; 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); cpu.pc = 1;
1350 mem.borrow_mut()[1] = 0x40 | dest << 3 | src; 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']; 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); cpu.pc = 0;
1404 mem.borrow_mut()[0] = 0x06 | dest << 3; 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']; 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); 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; 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 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 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 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 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 let res = a & operand;
1535 (res as u8, res == 0, false, true, false)
1536 },
1537 &|a, operand, _carry| {
1538 let res = a ^ operand;
1540 (res as u8, res == 0, false, false, false)
1541 },
1542 &|a, operand, _carry| {
1543 let res = a | operand;
1545 (res as u8, res == 0, false, false, false)
1546 },
1547 &|a, operand, _carry| {
1548 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']; 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); cpu.pc = 0;
1583 mem.borrow_mut()[0] = if operand == 8 {
1584 0xC6 | op << 3
1585 } else {
1586 0x80 | op << 3 | operand
1587 }; 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, ¶ms);
1619 assert_eq!(
1620 cpu.cycles_elapsed,
1621 1 + (operand == 6) as usize + (operand == 8) as usize,
1622 "{:?}",
1623 params
1624 );
1625 }
1626
1627 }
1629 }
1630 }
1631}