-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpu.py
More file actions
3033 lines (2703 loc) · 111 KB
/
Copy pathcpu.py
File metadata and controls
3033 lines (2703 loc) · 111 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""The CPU.
The CPU in the original GameBoy is a modified Zilog Z80.
http://www.devrs.com/gb/files/opcodes.html :
The GameBoy has instructions & registers similiar to the 8080, 8085, & Z80
microprocessors. The internal 8-bit registers are A, B, C, D, E, F, H, & L.
These registers may be used in pairs for 16-bit operations as AF, BC, DE, &
HL. The two remaining 16-bit registers are the program counter (PC) and the
stack pointer (SP).
The F register holds the cpu flags. The operation of these flags is identical
to their Z80 relative. The lower four bits of this register always read zero
even if written with a one.
Flag Register
7 6 5 4 3 2 1 0
Z N H C 0 0 0 0
The GameBoy CPU is based on a subset of the Z80 microprocessor.
A summary of these commands is given below.
Mnemonic Symbolic Operation Comments CPU Clocks Flags - Z,N,H,C
8-Bit Loads
-----------
LD r,s r s s=r,n,(HL) r=4, n=8, (HL)=8
LD d,r d r d=r,(HL) r=4, (HL)=8
LD d,n d n r=8, (HL)=12
LD A,(ss) A (ss) ss=BC,DE,HL,nn [BC,DE,HL]=8, nn=16
LD (dd),A (dd) A dd=BC,DE,HL,nn
LD A,(C) A ($FF00+C) - 8
LD (C),A ($FF00+C) A 8
LDD A,(HL) A (HL), HL HL - 1 8
LDD (HL),A (HL) A, HL HL - 1 8
LDI A,(HL) A (HL), HL HL + 1 8
LDI (HL),A (HL) A, HL HL + 1 8
LDH (n),A ($FF00+n) A 12
LDH A,(n) A ($FF00+n) 12
16-Bit Loads
------------
LD dd,nn dd nn dd=BC,DE,HL,SP 12 - - - -
LD (nn),SP (nn) SP - 20
LD SP,HL SP HL 8
LD HL,(SP+e) HL (SP+e) 12 0 0 * *
PUSH ss (SP-1) ssh, (SP-2) ssl, SPSP-2 ss=BC,DE,HL,AF 16 - - - -
POP dd ddl (SP), ddh (SP+1), SPSP+2 dd=BC,DE,HL,AF 12
8-Bit ALU
---------
ADD A,s A A + s CY is the carry flag. s=r,n,(HL) r=4, n=8, (HL)=8 * 0 * *
ADC A,s A A + s + CY
SUB s A A - s * 1 * *
SBC A,s A A - s - CY
AND s A A s * 0 1 0
OR s A A s * 0 0 0
XOR s A A s
CP s A - s * 1 * *
INC s s s + 1 s=r,(HL) r=4, (HL)=12 * 0 * -
DEC s s s - 1 * 1 * -
16-Bit Arithmetic
-----------------
ADD HL,ss HL HL + ss ss=BC,DE,HL,SP 8 - 0 * *
ADD SP,e SP SP + e 16 0 0 * *
INC ss ss ss + 1 8 - - - -
DEC ss ss ss - 1 8
Miscellaneous
-------------
SWAP s Swap nibbles. s=r,(HL) r=8, (HL)=16 * 0 0 0
DAA Converts A into packed BCD. - 4 * - 0 *
CPL A /A 4 - 1 1 -
CCF CY /CY CY is the carry flag. 4 - 0 0 *
SCF CY 1 4 - 0 0 1
NOP No operation. - 4 - - - -
HALT Halt CPU until an interrupt occurs. 4
STOP Halt CPU. 4
DI Disable Interrupts. 4
EI Enable Interrupts. 4
Rotates & Shifts
----------------
RLCA 4 0 0 0 *
RLA
RRCA
RRA
RLC s s=A,r,(HL) r=8,(HL)=16 * 0 0 *
RL s
RRC s
RR s
SLA s s=r,(HL) r=8, (HL)=16
SRA s
SRL s
Bit Opcodes
-----------
BIT b,s Z /sb Z is zero flag. s=r,(HL) r=8, (HL)=12 * 0 1 -
SET b,s sb 1 r=8, (HL)=16 - - - -
RES b,s sb 0
Jumps
-----
JP nn PC nn - 16
JP cc,nn If cc is true, PC nn, else continue. If cc is true, 16 else 12.
JP (HL) PC HL 4
JR e PC PC + e 12
JR cc,e if cc is true, PC PC + e, else continue. If cc is true, 12 else 8.
Calls
-----
CALL nn (SP-1) PCh, (SP-2) PCl, PC nn, SPSP-2 - 24
CALL cc,nn If condition cc is false continue, else same as CALL nn. If cc is true, 24 else 12.
Restarts
--------
RST f (SP-1) PCh, (SP-2) PCl, PCh 0, PCl f, SPSP-2 - 16
Returns
-------
RET pcl (SP), pch (SP+1), SPSP+2 - 16
RET cc If cc is true, RET else continue. If cc is true, 20 else 8.
RETI Return then enable interrupts. 16
"""
# import pdb
FLAG = {
'zero': 0x80, # Z flag
'sub': 0x40, # N flag
'half-carry': 0x20, # H flag
'carry': 0x10 # C flag
}
FLAG_ZERO = 0x80
FLAG_HALF_CARRY = 0x20
FLAG_CARRY = 0x10
CB_REGISTER_NAMES = ('b', 'c', 'd', 'e', 'h', 'l', None, 'a')
PPU_MODE_CYCLES = (204, 456, 80, 172)
my_counter = 0
def _build_cp_flag_table():
"""Return flags for CP A,value indexed by ``(A << 8) | value``."""
table = bytearray(0x10000)
for a in range(0x100):
base = a << 8
for value in range(0x100):
result = a - value
flags = FLAG['sub']
if result == 0:
flags |= FLAG_ZERO
if (a & 0x0F) < (value & 0x0F):
flags |= FLAG_HALF_CARRY
if result < 0:
flags |= FLAG_CARRY
table[base | value] = flags
return table
CP_FLAG_TABLE = _build_cp_flag_table()
class ExecutionHalted(Exception):
"""Raised when execution should stop."""
pass
class GbZ80Cpu(object):
"""The Z80 CPU class."""
def __init__(self, log_dump, gb_doctor_test_mode, trace_enabled=False):
"""Initialize an instance."""
self.gb_doctor_test_mode = gb_doctor_test_mode
self.trace_enabled = trace_enabled
self.enable_interrupts_next_cycle = False
self.halted = False
self.clock = {'m': 0} # Time clock
self.log_dump = log_dump
self.sys_interface = None # Set after interface instantiated.
self.direct_rom = None
self.direct_rom_length = 0
self.hram_poll_loop_ldh_offsets = {}
self.hram_compare_b_loop_ldh_offsets = {}
self.cp_hl_jr_nz_loop_pcs = set()
self.opcode_counts = None
self.cb_opcode_counts = None
self.halt_m_cycles = 0
# Register set
self.registers = {
# 16-bit registers stored as two 8-bit registers
'a': 0x01, 'f': 0xB0,
'b': 0x00, 'c': 0x13,
'd': 0x00, 'e': 0xD8,
'h': 0x01, 'l': 0x4D,
# Interrupts enabled/disabled
'ime': 1,
# 16-bit registers (program counter, stack pointer)
'pc': 0x0100, 'sp': 0xFFFE,
# Clock for last instr
'm': 0 # cpu cycles/4
}
self.rsv = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0, 'f': 0,
'h': 0, 'l': 0}
self.opcode_map = {
# opcode number: func to call, args
0: (self._nop, ()), # NOP
1: (self._ld_r1r2_nn, ('b', 'c')), # LDBCnn
2: (self._ld_r1r2m_a, ('b', 'c')), # LDBCmA
3: (self._inc_r_r, ('b', 'c')), # INCBC
4: (self._inc_r, ('b',)), # INCr_b
5: (self._dec_r, ('b',)), # DECr_b
6: (self._ld_rn, ('b',)), # LDrn_b
7: (self._rlc_a, ()), # RLCA
8: (self._ld_nn_sp, ()), # LDnnSP
9: (self._add_hl_n, ('b', 'c')), # ADDHLBC
10: (self._ld_a_r1r2m, ('b', 'c')), # LDABCm
11: (self._dec_bc, ()), # DECBC
12: (self._inc_r, ('c',)), # INCr_c
13: (self._dec_r, ('c',)), # DECr_c
14: (self._ld_rn, ('c',)), # LDrn_c
15: (self._rrca, ()), # RRCA
# 16: (self._djnz_n, ()), # DJNZn or stop?
16: (self._stop, ()), # DJNZn or stop?
17: (self._ld_r1r2_nn, ('d', 'e')), # LDDEnn
18: (self._ld_de_a, ()), # LDDEmA
19: (self._inc_r_r, ('d', 'e')), # INCDE
20: (self._inc_r, ('d',)), # INCr_d
21: (self._dec_r, ('d',)), # DECr_d
22: (self._ld_rn, ('d',)), # LDrn_d
23: (self._rla, ()), # RLA
24: (self._jr_n, ()), # JRn
25: (self._add_hl_n, ('d', 'e')), # ADDHLDE
26: (self._ld_a_r1r2m, ('d', 'e')), # LDADEm
27: (self._dec_r_r, ('d', 'e')), # DECDE
28: (self._inc_r, ('e',)), # INCr_e
29: (self._dec_r, ('e',)), # DECr_e
30: (self._ld_rn, ('e',)), # LDrn_e
31: (self._rra, ()), # RRA
32: (self._jr_nz_n, ()), # JRNZn
33: (self._ld_hl_nn, ()), # LDHLnn
34: (self._ld_hlmi_a, ()), # LDHLIA
35: (self._inc_hl, ()), # INCHL
36: (self._inc_r, ('h',)), # INCr_h
37: (self._dec_r, ('h',)), # DECr_h
38: (self._ld_rn, ('h',)), # LDrn_h
39: (self._daa, ()), # DAA
40: (self._jr_z_n, ()), # JRZn
41: (self._add_hl_n, ('h', 'l')), # ADDHLHL
42: (self._ld_a_hl_i, ()), # LDAHLI
43: (self._dec_r_r, ('h', 'l')), # DECHL
44: (self._inc_r, ('l',)), # INCr_l
45: (self._dec_r, ('l',)), # DECr_l
46: (self._ld_rn, ('l',)), # LDrn_l
47: (self.cpl, ()), # CPL
48: (self._jr_cc_n, (0x10, 0x00)), # JRNCn
49: (self._ld_sp_nn, ()), # LD SP nn
50: (self._ld_hlmd_a, ()), # LDHLDA
51: (self._inc_sp, ()), # INC SP
52: (self._inc_hlm, ()), # INCHLm
53: (self._dec_hlm, ()), # DECHLm
54: (self._ld_hlm_n, ()), # LDHLmn
55: (self._scf, ()), # SCF
56: (self._jr_cc_n, (0x10, 0x10)), # JRCn
57: (self._add_hl_sp, ()), # ADDHLSP
58: (self._ld_a_hl_d, ()), # LDAHLD
59: (self._dec_sp, ()), # DECSP
60: (self._inc_r, ('a',)), # INCr_a
61: (self._dec_a, ()), # DECr_a
62: (self._ld_rn, ('a',)), # LDrn_a
63: (self._ccf, ()), # CCF
64: (self._ld_rr, ('b', 'b')), # LDrr_bb (nop?)
65: (self._ld_rr, ('b', 'c')), # LDrr_bc
66: (self._ld_rr, ('b', 'd')), # LDrr_bd
67: (self._ld_rr, ('b', 'e')), # LDrr_be
68: (self._ld_rr, ('b', 'h')), # LDrr_bh
69: (self._ld_rr, ('b', 'l')), # LDrr_bl
70: (self._ld_r_hlm, ('b',)), # LDrHLm_b
71: (self._ld_rr, ('b', 'a')), # LDrr_ba
72: (self._ld_rr, ('c', 'b')), # LDrr_cb
73: (self._ld_rr, ('c', 'c')), # LDrr_cc (nop?)
74: (self._ld_rr, ('c', 'd')), # LDrr_cd
75: (self._ld_rr, ('c', 'e')), # LDrr_ce
76: (self._ld_rr, ('c', 'h')), # LDrr_ch
77: (self._ld_rr, ('c', 'l')), # LDrr_cl
78: (self._ld_r_hlm, ('c',)), # LDrHLm_c
79: (self._ld_rr, ('c', 'a')), # LDrr_ca
80: (self._ld_rr, ('d', 'b')), # LDrr_db
81: (self._ld_rr, ('d', 'c')), # LDrr_dc
82: (self._ld_rr, ('d', 'd')), # LDrr_dd (nop?)
83: (self._ld_rr, ('d', 'e')), # LDrr_de
84: (self._ld_rr, ('d', 'h')), # LDrr_dh
85: (self._ld_rr, ('d', 'l')), # LDrr_dl
86: (self._ld_r_hlm, ('d',)), # LDrHLm_d
87: (self._ld_rr, ('d', 'a')), # LDrr_da
88: (self._ld_rr, ('e', 'b')), # LDrr_eb
89: (self._ld_rr, ('e', 'c')), # LDrr_ec
90: (self._ld_rr, ('e', 'd')), # LDrr_ed
91: (self._ld_rr, ('e', 'e')), # LDrr_ee (nop?)
92: (self._ld_rr, ('e', 'h')), # LDrr_eh
93: (self._ld_rr, ('e', 'l')), # LDrr_el
94: (self._ld_r_hlm, ('e',)), # LDrHLm_e
95: (self._ld_rr, ('e', 'a')), # LDrr_ea
96: (self._ld_rr, ('h', 'b')), # LDrr_hb
97: (self._ld_rr, ('h', 'c')), # LDrr_hc
98: (self._ld_rr, ('h', 'd')), # LDrr_hd
99: (self._ld_rr, ('h', 'e')), # LDrr_he
100: (self._ld_rr, ('h', 'h')), # LDrr_hh (nop?)
101: (self._ld_rr, ('h', 'l')), # LDrr_hl
102: (self._ld_r_hlm, ('h',)), # LDrHLm_h
103: (self._ld_rr, ('h', 'a')), # LDrr_ha
104: (self._ld_rr, ('l', 'b')), # LDrr_lb
105: (self._ld_rr, ('l', 'c')), # LDrr_lc
106: (self._ld_rr, ('l', 'd')), # LDrr_ld
107: (self._ld_rr, ('l', 'e')), # LDrr_le
108: (self._ld_rr, ('l', 'h')), # LDrr_lh
109: (self._ld_rr, ('l', 'l')), # LDrr_ll (nop?)
110: (self._ld_r_hlm, ('l',)), # LDrHLm_l
111: (self._ld_rr, ('l', 'a')), # LDrr_la
112: (self._ld_hlm_r, ('b',)), # LDHLmr_b
113: (self._ld_hlm_r, ('c',)), # LDHLmr_c
114: (self._ld_hlm_r, ('d',)), # LDHLmr_d
115: (self._ld_hlm_r, ('e',)), # LDHLmr_e
116: (self._ld_hlm_r, ('h',)), # LDHLmr_h
117: (self._ld_hlm_r, ('l',)), # LDHLmr_l
118: (self._halt, ()), # HALT
119: (self._ld_hlm_r, ('a',)), # LDHLmr_a
120: (self._ld_a_b, ()), # LDrr_ab
121: (self._ld_rr, ('a', 'c')), # LDrr_ac
122: (self._ld_rr, ('a', 'd')), # LDrr_ad
123: (self._ld_rr, ('a', 'e')), # LDrr_ae
124: (self._ld_rr, ('a', 'h')), # LDrr_ah
125: (self._ld_a_l, ()), # LDrr_al
126: (self._ld_a_hlm, ()), # LDrHLm_a
127: (self._ld_rr, ('a', 'a')), # LDrr_aa (nop?)
128: (self._add_a_n, ('b',)), # ADDr_b
129: (self._add_a_n, ('c',)), # ADDr_c
130: (self._add_a_n, ('d',)), # ADDr_d
131: (self._add_a_n, ('e',)), # ADDr_e
132: (self._add_a_n, ('h',)), # ADDr_h
133: (self._add_a_n, ('l',)), # ADDr_l
134: (self._add_a_hl, ()), # ADD A,(HL)
135: (self._add_a_n, ('a',)), # ADDr_a
136: (self._adc_a_n, ('b',)), # ADC A, B
137: (self._adc_a_n, ('c',)), # ADC A, C
138: (self._adc_a_n, ('d',)), # ADC A, D
139: (self._adc_a_n, ('e',)), # ADC A, E
140: (self._adc_a_n, ('h',)), # ADC A, H
141: (self._adc_a_n, ('l',)), # ADC A, L
142: (self._adc_hl, ()), # ADCHL
143: (self._adc_a_n, ('a',)), # ADCr_a
144: (self._sub_n, ('b',)), # SUBr_b
145: (self._sub_n, ('c',)), # SUBr_c
146: (self._sub_n, ('d',)), # SUBr_d
147: (self._sub_n, ('e',)), # SUBr_e
148: (self._sub_n, ('h',)), # SUBr_h
149: (self._sub_n, ('l',)), # SUBr_l
150: (self._sub_hl, ()), # SUBHL
151: (self._sub_n, ('a',)), # SUBr_a
152: (self._sub_a_n, ('b',)), # SBCr_b
153: (self._sub_a_n, ('c',)), # SBCr_c
154: (self._sub_a_n, ('d',)), # SBCr_d
155: (self._sub_a_n, ('e',)), # SBCr_e
156: (self._sub_a_n, ('h',)), # SBCr_h
157: (self._sub_a_n, ('l',)), # SBCr_l
158: (self._sbc_a_hl, ()), # SBC A,(HL)
159: (self._sub_a_n, ('a',)), # SBCr_a
160: (self._and_b, ()), # ANDr_b
161: (self._and_n, ('c',)), # ANDr_c
162: (self._and_n, ('d',)), # ANDr_d
163: (self._and_n, ('e',)), # ANDr_e
164: (self._and_n, ('h',)), # ANDr_h
165: (self._and_n, ('l',)), # ANDr_l
166: (self._and_n, ('hl',)), # ANDHL
167: (self._and_a, ()), # ANDr_a
168: (self._xor_a_n, ('b',)), # XORr_b
169: (self._xor_a_n, ('c',)), # XORr_c
170: (self._xor_a_n, ('d',)), # XORr_d
171: (self._xor_a_n, ('e',)), # XORr_e
172: (self._xor_a_n, ('h',)), # XORr_h
173: (self._xor_a_n, ('l',)), # XORr_l
174: (self._xor_hl, ()), # XORHL
175: (self._xor_a_n, ('a',)), # XORr_a
176: (self._or_n, ('b',)), # ORr_b
177: (self._or_c, ()), # ORr_c
178: (self._or_n, ('d',)), # ORr_d
179: (self._or_n, ('e',)), # ORr_e
180: (self._or_n, ('h',)), # ORr_h
181: (self._or_n, ('l',)), # ORr_l
182: (self._or_hl, ()), # ORHL
183: (self._or_n, ('a',)), # ORr_a
184: (self._cp_b, ()), # CPr_b
185: (self._cp_n, ('c',)), # CPr_c
186: (self._cp_n, ('d',)), # CPr_d
187: (self._cp_n, ('e',)), # CPr_e
188: (self._cp_n, ('h',)), # CPr_h
189: (self._cp_n, ('l',)), # CPr_l
190: (self._cp_hl, ()), # CP (HL)
191: (self._cp_n, ('a',)), # CPr_a
192: (self._ret_f, (FLAG['zero'], 0x00)), # RETNZ
193: (self._pop_nn, ('b', 'c')), # POPBC
194: (self._jp_cc_nn, (FLAG['zero'], 0x00)), # JPNZnn
195: (self._jp_nn, ()), # JPnn
196: (self._call_cc_nn, (FLAG['zero'], 0x00)), # CALL NZ,nn
197: (self._push_nn, ('b', 'c')), # PUSHBC
198: (self._add_n, ()), # ADDn
199: (self._rst_n, (0x00,)), # RST00
200: (self._ret_f, (FLAG['zero'], FLAG['zero'])), # RETZ
201: (self._ret, ()), # RET
202: (self._jp_cc_nn, (FLAG['zero'], FLAG['zero'])), # JPZnn
203: (self._call_cb_op, ()), # MAPcb
204: (self._call_cc_nn, (FLAG['zero'], FLAG['zero'])), # CALL Z,nn
205: (self._call_nn, ()), # CALLnn
206: (self._adc_n, ()), # ADCn
207: (self._rst_n, (0x08,)), # RST08
208: (self._ret_f, (FLAG['carry'], 0x00)), # RETNC
209: (self._pop_nn, ('d', 'e')), # POPDE
210: (self._jp_cc_nn, (FLAG['carry'], 0x00)), # JPNCnn
211: (self._nop, ()), # XX
212: (self._call_cc_nn, (FLAG['carry'], 0x00)), # CALL NC,nn
213: (self._push_nn, ('d', 'e')), # PUSHDE
214: (self._sub_n_imm, ()), # SUBn
215: (self._rst_n, (FLAG['carry'],)), # RST10
216: (self._ret_f, (FLAG['carry'], FLAG['carry'])), # RETC
217: (self._reti, ()), # RETI
218: (self._jp_cc_nn, (FLAG['carry'], FLAG['carry'])), # JPCnn
219: (self._nop, ()), # XX
220: (self._call_cc_nn, (FLAG['carry'], FLAG['carry'])), # CALL C,nn
221: (self._nop, ()), # XX
222: (self._sbc_n, ()), # SBC A,n
223: (self._rst_n, (0x18,)), # RST18
224: (self._ldh_n_a, ()), # LDIOnA
225: (self._pop_nn, ('h', 'l')), # POPHL
226: (self._ld_c_a, ()), # LDIOCA
227: (self._nop, ()), # XX
228: (self._nop, ()), # XX
229: (self._push_nn, ('h', 'l')), # PUSHHL
230: (self._and_pc, ()), # ANDn
231: (self._rst_n, (FLAG['half-carry'],)), # RST20
232: (self._add_sp_n, ()), # ADDSPn
233: (self._jp_hl, ()), # JPHL
234: (self._ld_nn_a, ()), # LD nn A
235: (self._nop, ()), # XX
236: (self._nop, ()), # XX
237: (self._nop, ()), # XX
238: (self._xor_n_imm, ()), # ORn
239: (self._rst_n, (0x28,)), # RST28
240: (self._ldh_a_n, ()), # LD AIO n
241: (self._pop_nn, ('a', 'f')), # POPAF
242: (self._ld_a_c, ()), # LDAIOC
243: (self._di, ()), # DI
244: (self._nop, ()), # XX
245: (self._push_nn, ('a', 'f')), # PUSHAF
246: (self._or_n_imm, ()), # ORn
247: (self._rst_n, (0x30,)), # RST30
248: (self._ld_hl_sp_n, ()), # LD HL SP+n
249: (self._ld_sp_hl, ()), # LS SP HL
250: (self._ld_a_nn, ()), # LD A nn
251: (self._ei, ()), # EI
252: (self._nop, ()), # XX
253: (self._nop, ()), # XX
254: (self._cp_n, ('pc',)), # CPn
255: (self._rst_n, (0x38,)), # RST38
}
self.cb_map = {
0: (self._rlc_n, ['b']), # RLCr_b
1: (self._rlc_n, ['c']), # RLCr_c
2: (self._rlc_n, ['d']), # RLCr_d
3: (self._rlc_n, ['e']), # RLCr_e
4: (self._rlc_n, ['h']), # RLCr_h
5: (self._rlc_n, ['l']), # RLCr_l
6: (self._rlc_hlm, ()), # RLC (HL)
7: (self._rlc_n, ['a']), # RLCr_a
8: (self._rrc_n, ['b']), # RRC B
9: (self._rrc_n, ['c']), # RRC C
10: (self._rrc_n, ['d']), # RRC D
11: (self._rrc_n, ['e']), # RRC E
12: (self._rrc_n, ['h']), # RRC H
13: (self._rrc_n, ['l']), # RRC L
14: (self._rrc_hlm, ()), # RRC (HL)
15: (self._rrc_n, ['a']), # RRC A
16: (self._rl_n, ['b']), # RL B
17: (self._rl_n, ['c']), # RL C
18: (self._rl_n, ['d']), # RL D
19: (self._rl_n, ['e']), # RL E
20: (self._rl_n, ['h']), # RL H
21: (self._rl_n, ['l']), # RL L
22: (self._rl_hlm, ()), # RL (HL)
23: (self._rl_n, ['a']), # RL A
24: (self._rr_n, ['b']), # RR B
25: (self._rr_n, ['c']), # RR C
26: (self._rr_n, ['d']), # RR D
27: (self._rr_n, ['e']), # RR E
28: (self._rr_n, ['h']), # RR H
29: (self._rr_n, ['l']), # RR L
30: (self._rr_hlm, ()), # RR (HL)
31: (self._rr_n, ['a']), # RR A
32: (self._sla_n, ['b']), # SLA B
33: (self._sla_n, ['c']), # SLA C
34: (self._sla_n, ['d']), # SLA D
35: (self._sla_n, ['e']), # SLA E
36: (self._sla_n, ['h']), # SLA H
37: (self._sla_n, ['l']), # SLA L
38: (self._sla_hlm, ()), # SLA (HL)
39: (self._sla_n, ['a']), # SLA A
40: (self._sra_n, ['b']), # SRA B
41: (self._sra_n, ['c']), # SRA C
42: (self._sra_n, ['d']), # SRA D
43: (self._sra_n, ['e']), # SRA E
44: (self._sra_n, ['h']), # SRA H
45: (self._sra_n, ['l']), # SRA L
46: (self._sra_hlm, ()), # SRA (HL)
47: (self._sra_n, ['a']), # SRA A
48: (self._swap_n, ['b']), # SWAPr_b
49: (self._swap_n, ['c']), # SWAPr_c
50: (self._swap_n, ['d']), # SWAPr_d
51: (self._swap_n, ['e']), # SWAPr_e
52: (self._swap_n, ['h']), # SWAPr_h
53: (self._swap_n, ['l']), # SWAPr_l
54: (self._swap_hlm, ()), # SWAP (HL)
55: (self._swap_n, ['a']), # SWAPr_a
56: (self._srl_n, ['b']), # SRL B
57: (self._srl_n, ['c']), # SRL C
58: (self._srl_n, ['d']), # SRL D
59: (self._srl_n, ['e']), # SRL E
60: (self._srl_n, ['h']), # SRL H
61: (self._srl_n, ['l']), # SRL L
62: (self._srl_hlm, ()), # SRL (HL)
63: (self._srl_n, ['a']), # SRL A
# BIT 0
64: (self._bit_test_r, [0, 'b']),
65: (self._bit_test_r, [0, 'c']),
66: (self._bit_test_r, [0, 'd']),
67: (self._bit_test_r, [0, 'e']),
68: (self._bit_test_r, [0, 'h']),
69: (self._bit_test_r, [0, 'l']),
70: (self._bit_test_hlm, [0]),
71: (self._bit_test_r, [0, 'a']),
# BIT 1
72: (self._bit_test_r, [1, 'b']),
73: (self._bit_test_r, [1, 'c']),
74: (self._bit_test_r, [1, 'd']),
75: (self._bit_test_r, [1, 'e']),
76: (self._bit_test_r, [1, 'h']),
77: (self._bit_test_r, [1, 'l']),
78: (self._bit_test_hlm, [1]),
79: (self._bit_test_r, [1, 'a']),
# BIT 2
80: (self._bit_test_r, [2, 'b']),
81: (self._bit_test_r, [2, 'c']),
82: (self._bit_test_r, [2, 'd']),
83: (self._bit_test_r, [2, 'e']),
84: (self._bit_test_r, [2, 'h']),
85: (self._bit_test_r, [2, 'l']),
86: (self._bit_test_hlm, [2]),
87: (self._bit_test_r, [2, 'a']),
# BIT 3
88: (self._bit_test_r, [3, 'b']),
89: (self._bit_test_r, [3, 'c']),
90: (self._bit_test_r, [3, 'd']),
91: (self._bit_test_r, [3, 'e']),
92: (self._bit_test_r, [3, 'h']),
93: (self._bit_test_r, [3, 'l']),
94: (self._bit_test_hlm, [3]),
95: (self._bit_test_r, [3, 'a']),
# BIT 4
96: (self._bit_test_r, [4, 'b']),
97: (self._bit_test_r, [4, 'c']),
98: (self._bit_test_r, [4, 'd']),
99: (self._bit_test_r, [4, 'e']),
100: (self._bit_test_r, [4, 'h']),
101: (self._bit_test_r, [4, 'l']),
102: (self._bit_test_hlm, [4]),
103: (self._bit_test_r, [4, 'a']),
# BIT 5
104: (self._bit_test_r, [5, 'b']),
105: (self._bit_test_r, [5, 'c']),
106: (self._bit_test_r, [5, 'd']),
107: (self._bit_test_r, [5, 'e']),
108: (self._bit_test_r, [5, 'h']),
109: (self._bit_test_r, [5, 'l']),
110: (self._bit_test_hlm, [5]),
111: (self._bit_test_r, [5, 'a']),
# BIT 6
112: (self._bit_test_r, [6, 'b']),
113: (self._bit_test_r, [6, 'c']),
114: (self._bit_test_r, [6, 'd']),
115: (self._bit_test_r, [6, 'e']),
116: (self._bit_test_r, [6, 'h']),
117: (self._bit_test_r, [6, 'l']),
118: (self._bit_test_hlm, [6]),
119: (self._bit_test_r, [6, 'a']),
# BIT 7
120: (self._bit_test_r, [7, 'b']),
121: (self._bit_test_r, [7, 'c']),
122: (self._bit_test_r, [7, 'd']),
123: (self._bit_test_r, [7, 'e']),
124: (self._bit_test_r, [7, 'h']),
125: (self._bit_test_r, [7, 'l']),
126: (self._bit_test_hlm, [7]),
127: (self._bit_test_r, [7, 'a']),
# RES 0
128: (self._res_bit_r, [0, 'b']),
129: (self._res_bit_r, [0, 'c']),
130: (self._res_bit_r, [0, 'd']),
131: (self._res_bit_r, [0, 'e']),
132: (self._res_bit_r, [0, 'h']),
133: (self._res_bit_r, [0, 'l']),
134: (self._res_bit_hlm, [0]),
135: (self._res_bit_r, [0, 'a']),
# RES 1
136: (self._res_bit_r, [1, 'b']),
137: (self._res_bit_r, [1, 'c']),
138: (self._res_bit_r, [1, 'd']),
139: (self._res_bit_r, [1, 'e']),
140: (self._res_bit_r, [1, 'h']),
141: (self._res_bit_r, [1, 'l']),
142: (self._res_bit_hlm, [1]),
143: (self._res_bit_r, [1, 'a']),
# RES 2
144: (self._res_bit_r, [2, 'b']),
145: (self._res_bit_r, [2, 'c']),
146: (self._res_bit_r, [2, 'd']),
147: (self._res_bit_r, [2, 'e']),
148: (self._res_bit_r, [2, 'h']),
149: (self._res_bit_r, [2, 'l']),
150: (self._res_bit_hlm, [2]),
151: (self._res_bit_r, [2, 'a']),
# RES 3
152: (self._res_bit_r, [3, 'b']),
153: (self._res_bit_r, [3, 'c']),
154: (self._res_bit_r, [3, 'd']),
155: (self._res_bit_r, [3, 'e']),
156: (self._res_bit_r, [3, 'h']),
157: (self._res_bit_r, [3, 'l']),
158: (self._res_bit_hlm, [3]),
159: (self._res_bit_r, [3, 'a']),
# RES 4
160: (self._res_bit_r, [4, 'b']),
161: (self._res_bit_r, [4, 'c']),
162: (self._res_bit_r, [4, 'd']),
163: (self._res_bit_r, [4, 'e']),
164: (self._res_bit_r, [4, 'h']),
165: (self._res_bit_r, [4, 'l']),
166: (self._res_bit_hlm, [4]),
167: (self._res_bit_r, [4, 'a']),
# RES 5
168: (self._res_bit_r, [5, 'b']),
169: (self._res_bit_r, [5, 'c']),
170: (self._res_bit_r, [5, 'd']),
171: (self._res_bit_r, [5, 'e']),
172: (self._res_bit_r, [5, 'h']),
173: (self._res_bit_r, [5, 'l']),
174: (self._res_bit_hlm, [5]),
175: (self._res_bit_r, [5, 'a']),
# RES 6
176: (self._res_bit_r, [6, 'b']),
177: (self._res_bit_r, [6, 'c']),
178: (self._res_bit_r, [6, 'd']),
179: (self._res_bit_r, [6, 'e']),
180: (self._res_bit_r, [6, 'h']),
181: (self._res_bit_r, [6, 'l']),
182: (self._res_bit_hlm, [6]),
183: (self._res_bit_r, [6, 'a']),
# RES 7
184: (self._res_bit_r, [7, 'b']),
185: (self._res_bit_r, [7, 'c']),
186: (self._res_bit_r, [7, 'd']),
187: (self._res_bit_r, [7, 'e']),
188: (self._res_bit_r, [7, 'h']),
189: (self._res_bit_r, [7, 'l']),
190: (self._res_bit_hlm, [7]),
191: (self._res_bit_r, [7, 'a']),
# SET 0
192: (self._set_bit_r, [0, 'b']),
193: (self._set_bit_r, [0, 'c']),
194: (self._set_bit_r, [0, 'd']),
195: (self._set_bit_r, [0, 'e']),
196: (self._set_bit_r, [0, 'h']),
197: (self._set_bit_r, [0, 'l']),
198: (self._set_bit_hlm, [0]),
199: (self._set_bit_r, [0, 'a']),
# SET 1
200: (self._set_bit_r, [1, 'b']),
201: (self._set_bit_r, [1, 'c']),
202: (self._set_bit_r, [1, 'd']),
203: (self._set_bit_r, [1, 'e']),
204: (self._set_bit_r, [1, 'h']),
205: (self._set_bit_r, [1, 'l']),
206: (self._set_bit_hlm, [1]),
207: (self._set_bit_r, [1, 'a']),
# SET 2
208: (self._set_bit_r, [2, 'b']),
209: (self._set_bit_r, [2, 'c']),
210: (self._set_bit_r, [2, 'd']),
211: (self._set_bit_r, [2, 'e']),
212: (self._set_bit_r, [2, 'h']),
213: (self._set_bit_r, [2, 'l']),
214: (self._set_bit_hlm, [2]),
215: (self._set_bit_r, [2, 'a']),
# SET 3
216: (self._set_bit_r, [3, 'b']),
217: (self._set_bit_r, [3, 'c']),
218: (self._set_bit_r, [3, 'd']),
219: (self._set_bit_r, [3, 'e']),
220: (self._set_bit_r, [3, 'h']),
221: (self._set_bit_r, [3, 'l']),
222: (self._set_bit_hlm, [3]),
223: (self._set_bit_r, [3, 'a']),
# SET 4
224: (self._set_bit_r, [4, 'b']),
225: (self._set_bit_r, [4, 'c']),
226: (self._set_bit_r, [4, 'd']),
227: (self._set_bit_r, [4, 'e']),
228: (self._set_bit_r, [4, 'h']),
229: (self._set_bit_r, [4, 'l']),
230: (self._set_bit_hlm, [4]),
231: (self._set_bit_r, [4, 'a']),
# SET 5
232: (self._set_bit_r, [5, 'b']),
233: (self._set_bit_r, [5, 'c']),
234: (self._set_bit_r, [5, 'd']),
235: (self._set_bit_r, [5, 'e']),
236: (self._set_bit_r, [5, 'h']),
237: (self._set_bit_r, [5, 'l']),
238: (self._set_bit_hlm, [5]),
239: (self._set_bit_r, [5, 'a']),
# SET 6
240: (self._set_bit_r, [6, 'b']),
241: (self._set_bit_r, [6, 'c']),
242: (self._set_bit_r, [6, 'd']),
243: (self._set_bit_r, [6, 'e']),
244: (self._set_bit_r, [6, 'h']),
245: (self._set_bit_r, [6, 'l']),
246: (self._set_bit_hlm, [6]),
247: (self._set_bit_r, [6, 'a']),
# SET 7
248: (self._set_bit_r, [7, 'b']),
249: (self._set_bit_r, [7, 'c']),
250: (self._set_bit_r, [7, 'd']),
251: (self._set_bit_r, [7, 'e']),
252: (self._set_bit_r, [7, 'h']),
253: (self._set_bit_r, [7, 'l']),
254: (self._set_bit_hlm, [7]),
255: (self._set_bit_r, [7, 'a']),
}
self.opcode_table = [self.opcode_map[i] for i in range(256)]
self.cb_table = [self.cb_map[i] for i in range(256)]
def execute_next_operation(self):
global my_counter
registers = self.registers
sys_interface = self.sys_interface
gpu = sys_interface.gpu
clock = self.clock
trace_enabled = self.trace_enabled
gb_doctor_test_mode = self.gb_doctor_test_mode
if trace_enabled:
my_counter += 1
# Handle HALT state
if self.halted:
pending = (
sys_interface.read_byte(0xFFFF)
& sys_interface.read_byte(0xFF0F)
& 0x1F
)
if not pending:
m_cycles = min(
gpu.m_cycles_until_mode_transition(),
sys_interface.m_cycles_until_timer_interrupt(),
)
registers['m'] = m_cycles
clock['m'] += m_cycles
self.halt_m_cycles += m_cycles
self._step_system_timer(sys_interface, m_cycles)
gpu.step(m_cycles * 4)
return 0
self.halted = False
if gb_doctor_test_mode:
self.log_for_gameboy_dr(registers['pc'])
# Interrupts are accepted at the next instruction boundary. The
# boundary state is logged above, then execution continues at the
# interrupt vector instead of the interrupted PC.
if registers['ime']:
memory = sys_interface.raw_memory
if memory[0xFFFF] & memory[0xFF0F] & 0x1F:
if self.handle_interrupts():
m_cycles = registers['m']
clock['m'] += m_cycles
self._step_system_timer(sys_interface, m_cycles)
gpu.step(m_cycles * 4)
pc = registers['pc']
direct_rom = self.direct_rom
if direct_rom is not None and pc < 0x8000:
op = direct_rom[pc] if pc < self.direct_rom_length else 0xFF
else:
op = sys_interface.read_byte(pc)
if self.opcode_counts is not None:
self.opcode_counts[op] += 1
executed_instructions = 1
registers['pc'] = (pc + 1) & 0xFFFF
if not trace_enabled and op == 0xF0:
executed_instructions = self._fast_ldh_a_n(
pc, direct_rom, sys_interface, gpu, gb_doctor_test_mode
)
elif not trace_enabled and op == 0xA7:
a = registers['a']
registers['f'] = FLAG_HALF_CARRY | (FLAG_ZERO if a == 0 else 0)
registers['m'] = 1
elif not trace_enabled and op == 0x28:
pc = registers['pc']
if direct_rom is not None and pc < 0x8000:
i = direct_rom[pc] if pc < self.direct_rom_length else 0xFF
else:
i = sys_interface.read_byte(pc)
pc += 1
if not (registers['f'] & FLAG_ZERO):
registers['pc'] = pc & 0xFFFF
registers['m'] = 2
else:
if i >= 0x80:
i -= 0x100
registers['pc'] = (pc + i) & 0xFFFF
registers['m'] = 3
elif not trace_enabled and op == 0xB8:
registers['f'] = CP_FLAG_TABLE[
(registers['a'] << 8) | registers['b']
]
registers['m'] = 1
elif not trace_enabled and op == 0xBE:
# Keep this very hot path inline: games commonly poll LY with
# CP (HL); JR NZ,-3, and an extra helper call is measurable here.
memory = sys_interface.raw_memory
address = (registers['h'] << 8) | registers['l']
if address == 0xFF44 and not sys_interface.memory.gb_doctor_test_mode:
value = memory[0xFF44]
else:
value = sys_interface.read_byte(address)
flags = CP_FLAG_TABLE[(registers['a'] << 8) | value]
registers['f'] = flags
can_fold_cp_hl_loop = (
pc in self.cp_hl_jr_nz_loop_pcs
and self.opcode_counts is None
and not gb_doctor_test_mode
and not self.enable_interrupts_next_cycle
and not (memory[0xFFFF] & memory[0xFF0F] & 0x1F)
)
if not can_fold_cp_hl_loop:
registers['m'] = 2
else:
ppu_m_until = 0x10000
if memory[0xFF40] & 0x80:
remaining = PPU_MODE_CYCLES[gpu.linemode] - gpu._mode_clock
if (
gpu.linemode == 1
and not gpu._line153_ly_reset
and memory[0xFF44] == 153
):
line153_remaining = 4 - gpu._mode_clock
if line153_remaining < remaining:
remaining = line153_remaining
ppu_m_until = max(1, remaining // 4)
timer_m_until = 0x10000
if sys_interface.timer_enabled:
period = 1 << sys_interface.timer_period_shift
until_next_edge = period - (
sys_interface.divider_counter & (period - 1)
)
edges_until_overflow = 0x100 - memory[0xFF05]
timer_m_until = (
until_next_edge
+ (edges_until_overflow - 1) * period
)
loop_boundary = min(ppu_m_until, timer_m_until)
if loop_boundary <= 5:
registers['m'] = 2
elif flags & FLAG_ZERO:
registers['pc'] = (registers['pc'] + 2) & 0xFFFF
registers['m'] = 4
executed_instructions = 2
elif address == 0xFF44:
loops = (loop_boundary - 1) // 5
if loops < 1:
loops = 1
registers['pc'] = pc
registers['m'] = loops * 5
executed_instructions = loops * 2
else:
registers['pc'] = pc
registers['m'] = 5
executed_instructions = 2
elif not trace_enabled and op == 0x20:
pc = registers['pc']
if direct_rom is not None and pc < 0x8000:
i = direct_rom[pc] if pc < self.direct_rom_length else 0xFF
else:
i = sys_interface.read_byte(pc)
pc += 1
if registers['f'] & FLAG_ZERO:
registers['pc'] = pc & 0xFFFF
registers['m'] = 2
else:
if i >= 0x80:
i -= 0x100
registers['pc'] = (pc + i) & 0xFFFF
registers['m'] = 3
elif not trace_enabled and op == 0x23:
l = (registers['l'] + 1) & 0xFF
registers['l'] = l
if l == 0:
registers['h'] = (registers['h'] + 1) & 0xFF
registers['m'] = 2
elif not trace_enabled and op == 0x05:
val = registers['b']
result = (val - 1) & 0xFF
flags = (registers['f'] & FLAG_CARRY) | FLAG['sub']
if result == 0:
flags |= FLAG_ZERO
if (val & 0xF) == 0:
flags |= FLAG_HALF_CARRY
registers['b'] = result
registers['f'] = flags
registers['m'] = 1
elif not trace_enabled and op == 0x21:
pc = registers['pc']
if direct_rom is not None and pc < 0x8000:
registers['l'] = direct_rom[pc] if pc < self.direct_rom_length else 0xFF
next_pc = pc + 1
registers['h'] = (
direct_rom[next_pc] if next_pc < self.direct_rom_length else 0xFF
)
else:
registers['l'] = sys_interface.read_byte(pc)
registers['h'] = sys_interface.read_byte((pc + 1) & 0xFFFF)
registers['pc'] = (pc + 2) & 0xFFFF
registers['m'] = 3
elif not trace_enabled and op == 0x12:
address = (registers['d'] << 8) | registers['e']
self._fast_write8(address, registers['a'], sys_interface)
registers['m'] = 2
elif not trace_enabled and op == 0x22:
address = (registers['h'] << 8) | registers['l']
self._fast_write8(address, registers['a'], sys_interface)
l = (registers['l'] + 1) & 0xFF
registers['l'] = l
if l == 0:
registers['h'] = (registers['h'] + 1) & 0xFF
registers['m'] = 2
elif not trace_enabled and op == 0x2A:
address = (registers['h'] << 8) | registers['l']
registers['a'] = self._fast_read8(address, direct_rom, sys_interface)
l = (registers['l'] + 1) & 0xFF
registers['l'] = l
if l == 0:
registers['h'] = (registers['h'] + 1) & 0xFF
registers['m'] = 2
elif not trace_enabled and op == 0xCB:
pc = registers['pc']
if direct_rom is not None and pc < 0x8000:
cb_op = direct_rom[pc] if pc < self.direct_rom_length else 0xFF
else:
cb_op = sys_interface.read_byte(pc)
if self.cb_opcode_counts is not None:
self.cb_opcode_counts[cb_op] += 1
registers['pc'] = (pc + 1) & 0xFFFF
if cb_op == 0x46:
address = (registers['h'] << 8) | registers['l']
if (
0x8000 <= address <= 0x9FFF
or 0xC000 <= address <= 0xFEFF
or 0xFF80 <= address <= 0xFFFE
):
value = sys_interface.raw_memory[address]
else:
value = self.read8(address)
flags = (registers['f'] & FLAG_CARRY) | FLAG_HALF_CARRY
if not (value & 0x01):
flags |= FLAG_ZERO
registers['f'] = flags
registers['m'] = 4
else:
register_index = cb_op & 0x07
if 0x40 <= cb_op < 0x80 and register_index != 6: