yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
cpu.cc
Go to the documentation of this file.
1#include "cpu.h"
2
3#include <algorithm>
4#include <cstdint>
5#include <iomanip>
6#include <iostream>
7#include <sstream>
8#include <vector>
9
10#include "absl/strings/str_format.h"
13#include "core/features.h"
14#include "util/log.h"
15
16namespace yaze {
17namespace emu {
18
25
27 if (disassembly_viewer_ == nullptr) {
28 const_cast<Cpu*>(this)->disassembly_viewer_ =
30 }
31 return *disassembly_viewer_;
32}
33
34void Cpu::Reset(bool hard) {
35 if (hard) {
36 A = 0;
37 X = 0;
38 Y = 0;
39 PC = 0;
40 PB = 0;
41 D = 0;
42 DB = 0;
43 E = 1;
44 status = 0x34;
45 irq_wanted_ = false;
46 }
47
48 reset_wanted_ = true;
49 stopped_ = false;
50 waiting_ = false;
51 nmi_wanted_ = false;
52 int_wanted_ = false;
53 int_delay_ = false;
54}
55
57 // Check for execute breakpoint BEFORE running instruction
59 uint32_t current_pc = (PB << 16) | PC;
60 if (on_breakpoint_hit_(current_pc)) {
61 // Breakpoint hit - pause execution
62 return; // Don't run this opcode yet
63 }
64 }
65
66 if (reset_wanted_) {
67 reset_wanted_ = false;
68 // reset: brk/interrupt without writes
69 auto sp = SP();
70
71 ReadByte((PB << 16) | PC);
72 callbacks_.idle(false);
73 ReadByte(0x100 | (sp-- & 0xff));
74 ReadByte(0x100 | (sp-- & 0xff));
75 ReadByte(0x100 | (sp-- & 0xff));
76 sp = (sp & 0xff) | 0x100;
77
78 SetSP(sp);
79
80 E = 1;
81 SetInterruptFlag(true);
82 SetDecimalFlag(false);
83 SetFlags(status); // updates x and m flags, clears
84 // upper half of x and y if needed
85 PB = 0;
86
87 // Debug: Log reset vector read
88 uint8_t low_byte = ReadByte(0xfffc);
89 uint8_t high_byte = ReadByte(0xfffd);
90 PC = low_byte | (high_byte << 8);
91 LOG_DEBUG("CPU", "Reset vector: $FFFC=$%02X $FFFD=$%02X -> PC=$%04X",
92 low_byte, high_byte, PC);
93 return;
94 }
95 if (stopped_) {
96 static int stopped_log_count = 0;
97 if (stopped_log_count++ < 5) {
98 LOG_DEBUG("CPU",
99 "CPU is STOPPED at $%02X:%04X (STP instruction executed)", PB,
100 PC);
101 }
102 callbacks_.idle(true);
103 return;
104 }
105 if (waiting_) {
106 static int waiting_log_count = 0;
107 if (waiting_log_count++ < 5) {
108 LOG_DEBUG("CPU",
109 "CPU is WAITING at $%02X:%04X - irq_wanted=%d nmi_wanted=%d "
110 "int_flag=%d",
112 }
113 if (irq_wanted_ || nmi_wanted_) {
114 LOG_DEBUG("CPU", "CPU waking from WAIT - irq=%d nmi=%d", irq_wanted_,
116 waiting_ = false;
117 callbacks_.idle(false);
118 CheckInt();
119 callbacks_.idle(false);
120 return;
121 } else {
122 callbacks_.idle(true);
123 return;
124 }
125 }
126 // not stopped or waiting, execute a opcode or go to interrupt
127 if (int_wanted_) {
128 ReadByte((PB << 16) | PC);
129 DoInterrupt();
130 } else {
131 uint8_t opcode = ReadOpcode();
132
133 // AUDIO DEBUG: Enhanced logging for audio initialization tracking
134 static int instruction_count = 0;
135 instruction_count++;
136 uint16_t cur_pc = PC - 1;
137
138 // Track entry into Bank $00 (where all audio code lives)
139 static bool entered_bank00 = false;
140 static bool logged_first_nmi = false;
141
142 if (PB == 0x00 && !entered_bank00) {
143 LOG_INFO("CPU_AUDIO",
144 "=== ENTERED BANK $00 at PC=$%04X (instruction #%d) ===", cur_pc,
145 instruction_count);
146 entered_bank00 = true;
147 }
148
149 // Monitor NMI interrupts (audio init usually happens in NMI)
150 if (nmi_wanted_ && !logged_first_nmi) {
151 LOG_INFO("CPU_AUDIO", "=== FIRST NMI TRIGGERED at PC=$%02X:%04X ===", PB,
152 cur_pc);
153 logged_first_nmi = true;
154 }
155
156 // Track key audio routines in Bank $00
157 if (PB == 0x00) {
158 static bool logged_routines[0x10000] = {false};
159
160 // NMI handler entry ($0080-$00FF region)
161 if (cur_pc >= 0x0080 && cur_pc <= 0x00FF) {
162 if (cur_pc == 0x0080 || cur_pc == 0x0090 || cur_pc == 0x00A0) {
163 if (!logged_routines[cur_pc]) {
164 LOG_INFO("CPU_AUDIO",
165 "NMI code: PC=$00:%04X A=$%02X X=$%04X Y=$%04X", cur_pc,
166 A & 0xFF, X, Y);
167 logged_routines[cur_pc] = true;
168 }
169 }
170 }
171
172 // LoadSongBank routine ($8888-$88FF) - This is where handshake happens!
173 // LOGIC: Track CPU's journey through audio initialization to identify
174 // where it gets stuck. We log key waypoints to understand if CPU reaches
175 // handshake write instructions.
176 if (cur_pc >= 0x8888 && cur_pc <= 0x88FF) {
177 // Log entry
178 if (cur_pc == 0x8888) {
179 LOG_INFO("CPU_AUDIO",
180 ">>> LoadSongBank ENTRY at $8888! A=$%02X X=$%04X", A & 0xFF,
181 X);
182 }
183
184 // DISCOVERY: Log every unique PC in this range to see the execution
185 // path This helps identify if CPU is looping, stuck, or simply not
186 // reaching write instructions
187 static int exec_count_8888 = 0;
188 if (exec_count_8888++ < 100 && !logged_routines[cur_pc]) {
189 LOG_INFO("CPU_AUDIO",
190 " LoadSongBank: PC=$%04X A=$%02X X=$%04X Y=$%04X SP=$%04X "
191 "[exec #%d]",
192 cur_pc, A & 0xFF, X, Y, SP(), exec_count_8888);
193 logged_routines[cur_pc] = true;
194 }
195
196 // Log handshake initiation ($88A0-$88B0 area writes $CC to F4)
197 if (cur_pc >= 0x88A0 && cur_pc <= 0x88B0) {
198 static int setup_count = 0;
199 if (setup_count++ < 20) {
200 LOG_INFO("CPU_AUDIO", "Handshake setup area: PC=$%04X A=$%02X",
201 cur_pc, A & 0xFF);
202 }
203 }
204
205 // Log handshake wait loop
206 // LOGIC: If we see these addresses, CPU is waiting for APU response
207 static int handshake_log_count = 0;
208 if (cur_pc == 0x88B3 || cur_pc == 0x88B6) {
209 if (handshake_log_count++ < 20 || handshake_log_count % 500 == 0) {
210 uint8_t f4_val = callbacks_.read_byte(0x2140);
211 LOG_INFO(
212 "CPU_AUDIO",
213 "Handshake wait: PC=$%04X A=$%02X F4=$%02X X=$%04X [loop #%d]",
214 cur_pc, A & 0xFF, f4_val, X, handshake_log_count);
215 }
216 }
217 }
218 }
219
220 // Log first 50 instructions for boot tracking
221 bool should_log = instruction_count < 50;
222 if (should_log) {
223 LOG_DEBUG("CPU", "Boot #%d: $%02X:%04X opcode=$%02X", instruction_count,
224 PB, PC - 1, opcode);
225 }
226
227 // Debug: Log if stuck at same PC for extended period (after first 200
228 // instructions)
229 static uint16_t last_stuck_pc = 0xFFFF;
230 static int stuck_count = 0;
231 if (instruction_count >= 200) {
232 if (PC - 1 == last_stuck_pc) {
233 stuck_count++;
234 if (stuck_count == 100 || stuck_count == 1000 || stuck_count == 10000) {
235 LOG_DEBUG("CPU", "Stuck at $%02X:%04X opcode=$%02X for %d iterations",
236 PB, PC - 1, opcode, stuck_count);
237 }
238 } else {
239 if (stuck_count > 50) {
240 LOG_DEBUG("CPU",
241 "Moved from $%02X:%04X (was stuck %d times) to $%02X:%04X",
242 PB, last_stuck_pc, stuck_count, PB, PC - 1);
243 }
244 stuck_count = 0;
245 last_stuck_pc = PC - 1;
246 }
247 }
248
249 ExecuteInstruction(opcode);
250 }
251}
252
254 callbacks_.idle(false);
255 PushByte(PB);
256 PushWord(PC);
258 SetInterruptFlag(true);
259 SetDecimalFlag(false);
260 PB = 0;
261 int_wanted_ = false;
262 if (nmi_wanted_) {
263 nmi_wanted_ = false;
264 PC = ReadWord(0xffea, 0xffeb);
265 } else { // irq
266 PC = ReadWord(0xffee, 0xffef);
267 }
268}
269
270void Cpu::ExecuteInstruction(uint8_t opcode) {
271 uint16_t cache_pc = PC;
272 uint32_t operand = 0;
273 bool immediate = false;
274 bool accumulator_mode = GetAccumulatorSize();
275
276 switch (opcode) {
277 case 0x00: { // brk imm(s)
278 uint32_t vector = (E) ? 0xfffe : 0xffe6;
279 ReadOpcode();
280 if (!E)
281 PushByte(PB);
282 PushWord(PC, false);
284 SetInterruptFlag(true);
285 SetDecimalFlag(false);
286 PB = 0;
287 PC = ReadWord(vector, vector + 1, true);
288 break;
289 }
290 case 0x01: { // ora idx
291 uint32_t low = 0;
292 uint32_t high = AdrIdx(&low);
293 ORA(low, high);
294 break;
295 }
296 case 0x02: { // cop imm(s)
297 uint32_t vector = (E) ? 0xfff4 : 0xffe4;
298 ReadOpcode();
299 if (!E)
300 PushByte(PB);
301 PushWord(PC, false);
303 SetInterruptFlag(true);
304 SetDecimalFlag(false);
305 PB = 0;
306 PC = ReadWord(vector, vector + 1, true);
307 break;
308 }
309 case 0x03: { // ora sr
310 uint32_t low = 0;
311 uint32_t high = AdrSr(&low);
312 ORA(low, high);
313 break;
314 }
315 case 0x04: { // tsb dp
316 uint32_t low = 0;
317 uint32_t high = AdrDp(&low);
318 Tsb(low, high);
319 break;
320 }
321 case 0x05: { // ora dp
322 uint32_t low = 0;
323 uint32_t high = AdrDp(&low);
324 ORA(low, high);
325 break;
326 }
327 case 0x06: { // asl dp
328 uint32_t low = 0;
329 uint32_t high = AdrDp(&low);
330 Asl(low, high);
331 break;
332 }
333 case 0x07: { // ora idl
334 uint32_t low = 0;
335 uint32_t high = AdrIdl(&low);
336 ORA(low, high);
337 break;
338 }
339 case 0x08: { // php imp
340 callbacks_.idle(false);
341 CheckInt();
343 break;
344 }
345 case 0x09: { // ora imm(m)
346 uint32_t low = 0;
347 uint32_t high = Immediate(&low, false);
348 ORA(low, high);
349 break;
350 }
351 case 0x0a: { // asla imp
352 AdrImp();
353 if (GetAccumulatorSize()) {
354 SetCarryFlag(A & 0x80);
355 A = (A & 0xff00) | ((A << 1) & 0xff);
356 } else {
357 SetCarryFlag(A & 0x8000);
358 A <<= 1;
359 }
361 break;
362 }
363 case 0x0b: { // phd imp
364 callbacks_.idle(false);
365 PushWord(D, true);
366 break;
367 }
368 case 0x0c: { // tsb abs
369 uint32_t low = 0;
370 uint32_t high = Absolute(&low);
371 Tsb(low, high);
372 break;
373 }
374 case 0x0d: { // ora abs
375 uint32_t low = 0;
376 uint32_t high = Absolute(&low);
377 ORA(low, high);
378 break;
379 }
380 case 0x0e: { // asl abs
381 uint32_t low = 0;
382 uint32_t high = Absolute(&low);
383 Asl(low, high);
384 break;
385 }
386 case 0x0f: { // ora abl
387 uint32_t low = 0;
388 uint32_t high = AdrAbl(&low);
389 ORA(low, high);
390 break;
391 }
392 case 0x10: { // bpl rel
394 break;
395 }
396 case 0x11: { // ora idy(r)
397 uint32_t low = 0;
398 uint32_t high = AdrIdy(&low, false);
399 ORA(low, high);
400 break;
401 }
402 case 0x12: { // ora idp
403 uint32_t low = 0;
404 uint32_t high = AdrIdp(&low);
405 ORA(low, high);
406 break;
407 }
408 case 0x13: { // ora isy
409 uint32_t low = 0;
410 uint32_t high = AdrIsy(&low);
411 ORA(low, high);
412 break;
413 }
414 case 0x14: { // trb dp
415 uint32_t low = 0;
416 uint32_t high = AdrDp(&low);
417 Trb(low, high);
418 break;
419 }
420 case 0x15: { // ora dpx
421 uint32_t low = 0;
422 uint32_t high = AdrDpx(&low);
423 ORA(low, high);
424 break;
425 }
426 case 0x16: { // asl dpx
427 uint32_t low = 0;
428 uint32_t high = AdrDpx(&low);
429 Asl(low, high);
430 break;
431 }
432 case 0x17: { // ora ily
433 uint32_t low = 0;
434 uint32_t high = AdrIly(&low);
435 ORA(low, high);
436 break;
437 }
438 case 0x18: { // clc imp
439 AdrImp();
440 SetCarryFlag(false);
441 break;
442 }
443 case 0x19: { // ora aby(r)
444 uint32_t low = 0;
445 uint32_t high = AdrAby(&low, false);
446 ORA(low, high);
447 break;
448 }
449 case 0x1a: { // inca imp
450 AdrImp();
451 if (GetAccumulatorSize()) {
452 A = (A & 0xff00) | ((A + 1) & 0xff);
453 } else {
454 A++;
455 }
457 break;
458 }
459 case 0x1b: { // tcs imp
460 AdrImp();
461 SetSP(A);
462 break;
463 }
464 case 0x1c: { // trb abs
465 uint32_t low = 0;
466 uint32_t high = Absolute(&low);
467 Trb(low, high);
468 break;
469 }
470 case 0x1d: { // ora abx(r)
471 uint32_t low = 0;
472 uint32_t high = AdrAbx(&low, false);
473 ORA(low, high);
474 break;
475 }
476 case 0x1e: { // asl abx
477 uint32_t low = 0;
478 uint32_t high = AdrAbx(&low, true);
479 Asl(low, high);
480 break;
481 }
482 case 0x1f: { // ora alx
483 uint32_t low = 0;
484 uint32_t high = AdrAlx(&low);
485 ORA(low, high);
486 break;
487 }
488 case 0x20: { // jsr abs
489 uint16_t value = ReadOpcodeWord(false);
490 callbacks_.idle(false);
491 PushWord(PC - 1, true);
492 PC = value;
493 break;
494 }
495 case 0x21: { // and idx
496 uint32_t low = 0;
497 uint32_t high = AdrIdx(&low);
498 And(low, high);
499 break;
500 }
501 case 0x22: { // jsl abl
502 uint16_t value = ReadOpcodeWord(false);
503 PushByte(PB);
504 callbacks_.idle(false);
505 uint8_t newK = ReadOpcode();
506 PushWord(PC - 1, true);
507 PC = value;
508 PB = newK;
509 break;
510 }
511 case 0x23: { // and sr
512 uint32_t low = 0;
513 uint32_t high = AdrSr(&low);
514 And(low, high);
515 break;
516 }
517 case 0x24: { // bit dp
518 uint32_t low = 0;
519 uint32_t high = AdrDp(&low);
520 Bit(low, high);
521 break;
522 }
523 case 0x25: { // and dp
524 uint32_t low = 0;
525 uint32_t high = AdrDp(&low);
526 And(low, high);
527 break;
528 }
529 case 0x26: { // rol dp
530 uint32_t low = 0;
531 uint32_t high = AdrDp(&low);
532 Rol(low, high);
533 break;
534 }
535 case 0x27: { // and idl
536 uint32_t low = 0;
537 uint32_t high = AdrIdl(&low);
538 And(low, high);
539 break;
540 }
541 case 0x28: { // plp imp
542 callbacks_.idle(false);
543 callbacks_.idle(false);
544 CheckInt();
545 SetFlags(PopByte());
546 break;
547 }
548 case 0x29: { // and imm(m)
549 uint32_t low = 0;
550 uint32_t high = Immediate(&low, false);
551 And(low, high);
552 break;
553 }
554 case 0x2a: { // rola imp
555 AdrImp();
556 int result = (A << 1) | GetCarryFlag();
557 if (GetAccumulatorSize()) {
558 SetCarryFlag(result & 0x100);
559 A = (A & 0xff00) | (result & 0xff);
560 } else {
561 SetCarryFlag(result & 0x10000);
562 A = result;
563 }
565 break;
566 }
567 case 0x2b: { // pld imp
568 callbacks_.idle(false);
569 callbacks_.idle(false);
570 D = PopWord(true);
571 SetZN(D, false);
572 break;
573 }
574 case 0x2c: { // bit abs
575 uint32_t low = 0;
576 uint32_t high = Absolute(&low);
577 Bit(low, high);
578 break;
579 }
580 case 0x2d: { // and abs
581 uint32_t low = 0;
582 uint32_t high = Absolute(&low);
583 And(low, high);
584 break;
585 }
586 case 0x2e: { // rol abs
587 uint32_t low = 0;
588 uint32_t high = Absolute(&low);
589 Rol(low, high);
590 break;
591 }
592 case 0x2f: { // and abl
593 uint32_t low = 0;
594 uint32_t high = AdrAbl(&low);
595 And(low, high);
596 break;
597 }
598 case 0x30: { // bmi rel
600 break;
601 }
602 case 0x31: { // and idy(r)
603 uint32_t low = 0;
604 uint32_t high = AdrIdy(&low, false);
605 And(low, high);
606 break;
607 }
608 case 0x32: { // and idp
609 uint32_t low = 0;
610 uint32_t high = AdrIdp(&low);
611 And(low, high);
612 break;
613 }
614 case 0x33: { // and isy
615 uint32_t low = 0;
616 uint32_t high = AdrIsy(&low);
617 And(low, high);
618 break;
619 }
620 case 0x34: { // bit dpx
621 uint32_t low = 0;
622 uint32_t high = AdrDpx(&low);
623 Bit(low, high);
624 break;
625 }
626 case 0x35: { // and dpx
627 uint32_t low = 0;
628 uint32_t high = AdrDpx(&low);
629 And(low, high);
630 break;
631 }
632 case 0x36: { // rol dpx
633 uint32_t low = 0;
634 uint32_t high = AdrDpx(&low);
635 Rol(low, high);
636 break;
637 }
638 case 0x37: { // and ily
639 uint32_t low = 0;
640 uint32_t high = AdrIly(&low);
641 And(low, high);
642 break;
643 }
644 case 0x38: { // sec imp
645 AdrImp();
646 SetCarryFlag(true);
647 break;
648 }
649 case 0x39: { // and aby(r)
650 uint32_t low = 0;
651 uint32_t high = AdrAby(&low, false);
652 And(low, high);
653 break;
654 }
655 case 0x3a: { // deca imp
656 AdrImp();
657 if (GetAccumulatorSize()) {
658 A = (A & 0xff00) | ((A - 1) & 0xff);
659 } else {
660 A--;
661 }
663 break;
664 }
665 case 0x3b: { // tsc imp
666 AdrImp();
667 A = SP();
668 SetZN(A, false);
669 break;
670 }
671 case 0x3c: { // bit abx(r)
672 uint32_t low = 0;
673 uint32_t high = AdrAbx(&low, false);
674 Bit(low, high);
675 break;
676 }
677 case 0x3d: { // and abx(r)
678 uint32_t low = 0;
679 uint32_t high = AdrAbx(&low, false);
680 And(low, high);
681 break;
682 }
683 case 0x3e: { // rol abx
684 uint32_t low = 0;
685 uint32_t high = AdrAbx(&low, true);
686 Rol(low, high);
687 break;
688 }
689 case 0x3f: { // and alx
690 uint32_t low = 0;
691 uint32_t high = AdrAlx(&low);
692 And(low, high);
693 break;
694 }
695 case 0x40: { // rti imp
696 callbacks_.idle(false);
697 callbacks_.idle(false);
698 SetFlags(PopByte());
699 PC = PopWord(false);
700 CheckInt();
701 PB = PopByte();
702 break;
703 }
704 case 0x41: { // eor idx
705 uint32_t low = 0;
706 uint32_t high = AdrIdx(&low);
707 Eor(low, high);
708 break;
709 }
710 case 0x42: { // wdm imm(s)
711 CheckInt();
712 ReadOpcode();
713 break;
714 }
715 case 0x43: { // eor sr
716 uint32_t low = 0;
717 uint32_t high = AdrSr(&low);
718 Eor(low, high);
719 break;
720 }
721 case 0x44: { // mvp bm
722 uint8_t dest = ReadOpcode();
723 uint8_t src = ReadOpcode();
724 DB = dest;
725 WriteByte((dest << 16) | Y, ReadByte((src << 16) | X));
726 A--;
727 X--;
728 Y--;
729 if (A != 0xffff) {
730 PC -= 3;
731 }
732 if (GetIndexSize()) {
733 X &= 0xff;
734 Y &= 0xff;
735 }
736 callbacks_.idle(false);
737 CheckInt();
738 callbacks_.idle(false);
739 break;
740 }
741 case 0x45: { // eor dp
742 uint32_t low = 0;
743 uint32_t high = AdrDp(&low);
744 Eor(low, high);
745 break;
746 }
747 case 0x46: { // lsr dp
748 uint32_t low = 0;
749 uint32_t high = AdrDp(&low);
750 Lsr(low, high);
751 break;
752 }
753 case 0x47: { // eor idl
754 uint32_t low = 0;
755 uint32_t high = AdrIdl(&low);
756 Eor(low, high);
757 break;
758 }
759 case 0x48: { // pha imp
760 callbacks_.idle(false);
761 if (GetAccumulatorSize()) {
762 CheckInt();
763 PushByte(A);
764 } else {
765 PushWord(A, true);
766 }
767 break;
768 }
769 case 0x49: { // eor imm(m)
770 uint32_t low = 0;
771 uint32_t high = Immediate(&low, false);
772 Eor(low, high);
773 break;
774 }
775 case 0x4a: { // lsra imp
776 AdrImp();
777 SetCarryFlag(A & 1);
778 if (GetAccumulatorSize()) {
779 A = (A & 0xff00) | ((A >> 1) & 0x7f);
780 } else {
781 A >>= 1;
782 }
784 break;
785 }
786 case 0x4b: { // phk imp
787 callbacks_.idle(false);
788 CheckInt();
789 PushByte(PB);
790 break;
791 }
792 case 0x4c: { // jmp abs
793 PC = ReadOpcodeWord(true);
794 break;
795 }
796 case 0x4d: { // eor abs
797 uint32_t low = 0;
798 uint32_t high = Absolute(&low);
799 Eor(low, high);
800 break;
801 }
802 case 0x4e: { // lsr abs
803 uint32_t low = 0;
804 uint32_t high = Absolute(&low);
805 Lsr(low, high);
806 break;
807 }
808 case 0x4f: { // eor abl
809 uint32_t low = 0;
810 uint32_t high = AdrAbl(&low);
811 Eor(low, high);
812 break;
813 }
814 case 0x50: { // bvc rel
816 break;
817 }
818 case 0x51: { // eor idy(r)
819 uint32_t low = 0;
820 uint32_t high = AdrIdy(&low, false);
821 Eor(low, high);
822 break;
823 }
824 case 0x52: { // eor idp
825 uint32_t low = 0;
826 uint32_t high = AdrIdp(&low);
827 Eor(low, high);
828 break;
829 }
830 case 0x53: { // eor isy
831 uint32_t low = 0;
832 uint32_t high = AdrIsy(&low);
833 Eor(low, high);
834 break;
835 }
836 case 0x54: { // mvn bm
837 uint8_t dest = ReadOpcode();
838 uint8_t src = ReadOpcode();
839 DB = dest;
840 WriteByte((dest << 16) | Y, ReadByte((src << 16) | X));
841 A--;
842 X++;
843 Y++;
844 if (A != 0xffff) {
845 PC -= 3;
846 }
847 if (GetIndexSize()) {
848 X &= 0xff;
849 Y &= 0xff;
850 }
851 callbacks_.idle(false);
852 CheckInt();
853 callbacks_.idle(false);
854 break;
855 }
856 case 0x55: { // eor dpx
857 uint32_t low = 0;
858 uint32_t high = AdrDpx(&low);
859 Eor(low, high);
860 break;
861 }
862 case 0x56: { // lsr dpx
863 uint32_t low = 0;
864 uint32_t high = AdrDpx(&low);
865 Lsr(low, high);
866 break;
867 }
868 case 0x57: { // eor ily
869 uint32_t low = 0;
870 uint32_t high = AdrIly(&low);
871 Eor(low, high);
872 break;
873 }
874 case 0x58: { // cli imp
875 AdrImp();
876 SetInterruptFlag(false);
877 break;
878 }
879 case 0x59: { // eor aby(r)
880 uint32_t low = 0;
881 uint32_t high = AdrAby(&low, false);
882 Eor(low, high);
883 break;
884 }
885 case 0x5a: { // phy imp
886 callbacks_.idle(false);
887 if (GetIndexSize()) {
888 CheckInt();
889 PushByte(Y);
890 } else {
891 PushWord(Y, true);
892 }
893 break;
894 }
895 case 0x5b: { // tcd imp
896 AdrImp();
897 D = A;
898 SetZN(D, false);
899 break;
900 }
901 case 0x5c: { // jml abl
902 uint16_t value = ReadOpcodeWord(false);
903 CheckInt();
904 PB = ReadOpcode();
905 PC = value;
906 break;
907 }
908 case 0x5d: { // eor abx(r)
909 uint32_t low = 0;
910 uint32_t high = AdrAbx(&low, false);
911 Eor(low, high);
912 break;
913 }
914 case 0x5e: { // lsr abx
915 uint32_t low = 0;
916 uint32_t high = AdrAbx(&low, true);
917 Lsr(low, high);
918 break;
919 }
920 case 0x5f: { // eor alx
921 uint32_t low = 0;
922 uint32_t high = AdrAlx(&low);
923 Eor(low, high);
924 break;
925 }
926 case 0x60: { // rts imp
927 callbacks_.idle(false);
928 callbacks_.idle(false);
929 PC = PopWord(false) + 1;
930 CheckInt();
931 callbacks_.idle(false);
932 break;
933 }
934 case 0x61: { // adc idx
935 uint32_t low = 0;
936 uint32_t high = AdrIdx(&low);
937 Adc(low, high);
938 break;
939 }
940 case 0x62: { // per rll
941 uint16_t value = ReadOpcodeWord(false);
942 callbacks_.idle(false);
943 PushWord(PC + (int16_t)value, true);
944 break;
945 }
946 case 0x63: { // adc sr
947 uint32_t low = 0;
948 uint32_t high = AdrSr(&low);
949 Adc(low, high);
950 break;
951 }
952 case 0x64: { // stz dp
953 uint32_t low = 0;
954 uint32_t high = AdrDp(&low);
955 Stz(low, high);
956 break;
957 }
958 case 0x65: { // adc dp
959 uint32_t low = 0;
960 uint32_t high = AdrDp(&low);
961 Adc(low, high);
962 break;
963 }
964 case 0x66: { // ror dp
965 uint32_t low = 0;
966 uint32_t high = AdrDp(&low);
967 Ror(low, high);
968 break;
969 }
970 case 0x67: { // adc idl
971 uint32_t low = 0;
972 uint32_t high = AdrIdl(&low);
973 Adc(low, high);
974 break;
975 }
976 case 0x68: { // pla imp
977 callbacks_.idle(false);
978 callbacks_.idle(false);
979 if (GetAccumulatorSize()) {
980 CheckInt();
981 A = (A & 0xff00) | PopByte();
982 } else {
983 A = PopWord(true);
984 }
986 break;
987 }
988 case 0x69: { // adc imm(m)
989 uint32_t low = 0;
990 uint32_t high = Immediate(&low, false);
991 Adc(low, high);
992 break;
993 }
994 case 0x6a: { // rora imp
995 AdrImp();
996 bool carry = A & 1;
997 auto C = GetCarryFlag();
998 if (GetAccumulatorSize()) {
999 A = (A & 0xff00) | ((A >> 1) & 0x7f) | (C << 7);
1000 } else {
1001 A = (A >> 1) | (C << 15);
1002 }
1003 SetCarryFlag(carry);
1005 break;
1006 }
1007 case 0x6b: { // rtl imp
1008 callbacks_.idle(false);
1009 callbacks_.idle(false);
1010 PC = PopWord(false) + 1;
1011 CheckInt();
1012 PB = PopByte();
1013 break;
1014 }
1015 case 0x6c: { // jmp ind
1016 uint16_t adr = ReadOpcodeWord(false);
1017 PC = ReadWord(adr, (adr + 1) & 0xffff, true);
1018 break;
1019 }
1020 case 0x6d: { // adc abs
1021 uint32_t low = 0;
1022 uint32_t high = Absolute(&low);
1023 Adc(low, high);
1024 break;
1025 }
1026 case 0x6e: { // ror abs
1027 uint32_t low = 0;
1028 uint32_t high = Absolute(&low);
1029 Ror(low, high);
1030 break;
1031 }
1032 case 0x6f: { // adc abl
1033 uint32_t low = 0;
1034 uint32_t high = AdrAbl(&low);
1035 Adc(low, high);
1036 break;
1037 }
1038 case 0x70: { // bvs rel
1040 break;
1041 }
1042 case 0x71: { // adc idy(r)
1043 uint32_t low = 0;
1044 uint32_t high = AdrIdy(&low, false);
1045 Adc(low, high);
1046 break;
1047 }
1048 case 0x72: { // adc idp
1049 uint32_t low = 0;
1050 uint32_t high = AdrIdp(&low);
1051 Adc(low, high);
1052 break;
1053 }
1054 case 0x73: { // adc isy
1055 uint32_t low = 0;
1056 uint32_t high = AdrIsy(&low);
1057 Adc(low, high);
1058 break;
1059 }
1060 case 0x74: { // stz dpx
1061 uint32_t low = 0;
1062 uint32_t high = AdrDpx(&low);
1063 Stz(low, high);
1064 break;
1065 }
1066 case 0x75: { // adc dpx
1067 uint32_t low = 0;
1068 uint32_t high = AdrDpx(&low);
1069 Adc(low, high);
1070 break;
1071 }
1072 case 0x76: { // ror dpx
1073 uint32_t low = 0;
1074 uint32_t high = AdrDpx(&low);
1075 Ror(low, high);
1076 break;
1077 }
1078 case 0x77: { // adc ily
1079 uint32_t low = 0;
1080 uint32_t high = AdrIly(&low);
1081 Adc(low, high);
1082 break;
1083 }
1084 case 0x78: { // sei imp
1085 AdrImp();
1086 SetInterruptFlag(true);
1087 break;
1088 }
1089 case 0x79: { // adc aby(r)
1090 uint32_t low = 0;
1091 uint32_t high = AdrAby(&low, false);
1092 Adc(low, high);
1093 break;
1094 }
1095 case 0x7a: { // ply imp
1096 callbacks_.idle(false);
1097 callbacks_.idle(false);
1098 if (GetIndexSize()) {
1099 CheckInt();
1100 Y = PopByte();
1101 } else {
1102 Y = PopWord(true);
1103 }
1104 SetZN(Y, GetIndexSize());
1105 break;
1106 }
1107 case 0x7b: { // tdc imp
1108 AdrImp();
1109 A = D;
1110 SetZN(A, false);
1111 break;
1112 }
1113 case 0x7c: { // jmp iax
1114 uint16_t adr = ReadOpcodeWord(false);
1115 callbacks_.idle(false);
1116 PC = ReadWord((PB << 16) | ((adr + X) & 0xffff),
1117 ((PB << 16) | ((adr + X + 1) & 0xffff)), true);
1118 break;
1119 }
1120 case 0x7d: { // adc abx(r)
1121 uint32_t low = 0;
1122 uint32_t high = AdrAbx(&low, false);
1123 Adc(low, high);
1124 break;
1125 }
1126 case 0x7e: { // ror abx
1127 uint32_t low = 0;
1128 uint32_t high = AdrAbx(&low, true);
1129 Ror(low, high);
1130 break;
1131 }
1132 case 0x7f: { // adc alx
1133 uint32_t low = 0;
1134 uint32_t high = AdrAlx(&low);
1135 Adc(low, high);
1136 break;
1137 }
1138 case 0x80: { // bra rel
1139 DoBranch(true);
1140 break;
1141 }
1142 case 0x81: { // sta idx
1143 uint32_t low = 0;
1144 uint32_t high = AdrIdx(&low);
1145 Sta(low, high);
1146 break;
1147 }
1148 case 0x82: { // brl rll
1149 PC += (int16_t)ReadOpcodeWord(false);
1150 CheckInt();
1151 callbacks_.idle(false);
1152 break;
1153 }
1154 case 0x83: { // sta sr
1155 uint32_t low = 0;
1156 uint32_t high = AdrSr(&low);
1157 Sta(low, high);
1158 break;
1159 }
1160 case 0x84: { // sty dp
1161 uint32_t low = 0;
1162 uint32_t high = AdrDp(&low);
1163 Sty(low, high);
1164 break;
1165 }
1166 case 0x85: { // sta dp
1167 uint32_t low = 0;
1168 uint32_t high = AdrDp(&low);
1169 Sta(low, high);
1170 break;
1171 }
1172 case 0x86: { // stx dp
1173 uint32_t low = 0;
1174 uint32_t high = AdrDp(&low);
1175 Stx(low, high);
1176 break;
1177 }
1178 case 0x87: { // sta idl
1179 uint32_t low = 0;
1180 uint32_t high = AdrIdl(&low);
1181 Sta(low, high);
1182 break;
1183 }
1184 case 0x88: { // dey imp
1185 AdrImp();
1186 if (GetIndexSize()) {
1187 Y = (Y - 1) & 0xff;
1188 } else {
1189 Y--;
1190 }
1191 SetZN(Y, GetIndexSize());
1192 break;
1193 }
1194 case 0x89: { // biti imm(m)
1195 if (GetAccumulatorSize()) {
1196 CheckInt();
1197 uint8_t result = (A & 0xff) & ReadOpcode();
1198 SetZeroFlag(result == 0);
1199 } else {
1200 uint16_t result = A & ReadOpcodeWord(true);
1201 SetZeroFlag(result == 0);
1202 }
1203 break;
1204 }
1205 case 0x8a: { // txa imp
1206 AdrImp();
1207 if (GetAccumulatorSize()) {
1208 A = (A & 0xff00) | (X & 0xff);
1209 } else {
1210 A = X;
1211 }
1213 break;
1214 }
1215 case 0x8b: { // phb imp
1216 callbacks_.idle(false);
1217 CheckInt();
1218 PushByte(DB);
1219 break;
1220 }
1221 case 0x8c: { // sty abs
1222 uint32_t low = 0;
1223 uint32_t high = Absolute(&low);
1224 Sty(low, high);
1225 break;
1226 }
1227 case 0x8d: { // sta abs
1228 uint32_t low = 0;
1229 uint32_t high = Absolute(&low);
1230 Sta(low, high);
1231 break;
1232 }
1233 case 0x8e: { // stx abs
1234 uint32_t low = 0;
1235 uint32_t high = Absolute(&low);
1236 Stx(low, high);
1237 break;
1238 }
1239 case 0x8f: { // sta abl
1240 uint32_t low = 0;
1241 uint32_t high = AdrAbl(&low);
1242 Sta(low, high);
1243 break;
1244 }
1245 case 0x90: { // bcc rel
1247 break;
1248 }
1249 case 0x91: { // sta idy
1250 uint32_t low = 0;
1251 uint32_t high = AdrIdy(&low, true);
1252 Sta(low, high);
1253 break;
1254 }
1255 case 0x92: { // sta idp
1256 uint32_t low = 0;
1257 uint32_t high = AdrIdp(&low);
1258 Sta(low, high);
1259 break;
1260 }
1261 case 0x93: { // sta isy
1262 uint32_t low = 0;
1263 uint32_t high = AdrIsy(&low);
1264 Sta(low, high);
1265 break;
1266 }
1267 case 0x94: { // sty dpx
1268 uint32_t low = 0;
1269 uint32_t high = AdrDpx(&low);
1270 Sty(low, high);
1271 break;
1272 }
1273 case 0x95: { // sta dpx
1274 uint32_t low = 0;
1275 uint32_t high = AdrDpx(&low);
1276 Sta(low, high);
1277 break;
1278 }
1279 case 0x96: { // stx dpy
1280 uint32_t low = 0;
1281 uint32_t high = AdrDpy(&low);
1282 Stx(low, high);
1283 break;
1284 }
1285 case 0x97: { // sta ily
1286 uint32_t low = 0;
1287 uint32_t high = AdrIly(&low);
1288 Sta(low, high);
1289 break;
1290 }
1291 case 0x98: { // tya imp
1292 AdrImp();
1293 if (GetAccumulatorSize()) {
1294 A = (A & 0xff00) | (Y & 0xff);
1295 } else {
1296 A = Y;
1297 }
1299 break;
1300 }
1301 case 0x99: { // sta aby
1302 uint32_t low = 0;
1303 uint32_t high = AdrAby(&low, true);
1304 Sta(low, high);
1305 break;
1306 }
1307 case 0x9a: { // txs imp
1308 AdrImp();
1309 SetSP(X);
1310 break;
1311 }
1312 case 0x9b: { // txy imp
1313 AdrImp();
1314 if (GetIndexSize()) {
1315 Y = X & 0xff;
1316 } else {
1317 Y = X;
1318 }
1319 SetZN(Y, GetIndexSize());
1320 break;
1321 }
1322 case 0x9c: { // stz abs
1323 uint32_t low = 0;
1324 uint32_t high = Absolute(&low);
1325 Stz(low, high);
1326 break;
1327 }
1328 case 0x9d: { // sta abx
1329 uint32_t low = 0;
1330 uint32_t high = AdrAbx(&low, true);
1331 Sta(low, high);
1332 break;
1333 }
1334 case 0x9e: { // stz abx
1335 uint32_t low = 0;
1336 uint32_t high = AdrAbx(&low, true);
1337 Stz(low, high);
1338 break;
1339 }
1340 case 0x9f: { // sta alx
1341 uint32_t low = 0;
1342 uint32_t high = AdrAlx(&low);
1343 Sta(low, high);
1344 break;
1345 }
1346 case 0xa0: { // ldy imm(x)
1347 uint32_t low = 0;
1348 uint32_t high = Immediate(&low, true);
1349 Ldy(low, high);
1350 break;
1351 }
1352 case 0xa1: { // lda idx
1353 uint32_t low = 0;
1354 uint32_t high = AdrIdx(&low);
1355 Lda(low, high);
1356 break;
1357 }
1358 case 0xa2: { // ldx imm(x)
1359 uint32_t low = 0;
1360 uint32_t high = Immediate(&low, true);
1361 Ldx(low, high);
1362 break;
1363 }
1364 case 0xa3: { // lda sr
1365 uint32_t low = 0;
1366 uint32_t high = AdrSr(&low);
1367 Lda(low, high);
1368 break;
1369 }
1370 case 0xa4: { // ldy dp
1371 uint32_t low = 0;
1372 uint32_t high = AdrDp(&low);
1373 Ldy(low, high);
1374 break;
1375 }
1376 case 0xa5: { // lda dp
1377 uint32_t low = 0;
1378 uint32_t high = AdrDp(&low);
1379 Lda(low, high);
1380 break;
1381 }
1382 case 0xa6: { // ldx dp
1383 uint32_t low = 0;
1384 uint32_t high = AdrDp(&low);
1385 Ldx(low, high);
1386 break;
1387 }
1388 case 0xa7: { // lda idl
1389 uint32_t low = 0;
1390 uint32_t high = AdrIdl(&low);
1391 Lda(low, high);
1392 break;
1393 }
1394 case 0xa8: { // tay imp
1395 AdrImp();
1396 if (GetIndexSize()) {
1397 Y = A & 0xff;
1398 } else {
1399 Y = A;
1400 }
1401 SetZN(Y, GetIndexSize());
1402 break;
1403 }
1404 case 0xa9: { // lda imm(m)
1405 uint32_t low = 0;
1406 uint32_t high = Immediate(&low, false);
1407 Lda(low, high);
1408 break;
1409 }
1410 case 0xaa: { // tax imp
1411 AdrImp();
1412 if (GetIndexSize()) {
1413 X = A & 0xff;
1414 } else {
1415 X = A;
1416 }
1417 SetZN(X, GetIndexSize());
1418 break;
1419 }
1420 case 0xab: { // plb imp
1421 callbacks_.idle(false);
1422 callbacks_.idle(false);
1423 CheckInt();
1424 DB = PopByte();
1425 SetZN(DB, true);
1426 break;
1427 }
1428 case 0xac: { // ldy abs
1429 uint32_t low = 0;
1430 uint32_t high = Absolute(&low);
1431 Ldy(low, high);
1432 break;
1433 }
1434 case 0xad: { // lda abs
1435 uint32_t low = 0;
1436 uint32_t high = Absolute(&low);
1437 Lda(low, high);
1438 break;
1439 }
1440 case 0xae: { // ldx abs
1441 uint32_t low = 0;
1442 uint32_t high = Absolute(&low);
1443 Ldx(low, high);
1444 break;
1445 }
1446 case 0xaf: { // lda abl
1447 uint32_t low = 0;
1448 uint32_t high = AdrAbl(&low);
1449 Lda(low, high);
1450 break;
1451 }
1452 case 0xb0: { // bcs rel
1454 break;
1455 }
1456 case 0xb1: { // lda idy(r)
1457 uint32_t low = 0;
1458 uint32_t high = AdrIdy(&low, false);
1459 Lda(low, high);
1460 break;
1461 }
1462 case 0xb2: { // lda idp
1463 uint32_t low = 0;
1464 uint32_t high = AdrIdp(&low);
1465 Lda(low, high);
1466 break;
1467 }
1468 case 0xb3: { // lda isy
1469 uint32_t low = 0;
1470 uint32_t high = AdrIsy(&low);
1471 Lda(low, high);
1472 break;
1473 }
1474 case 0xb4: { // ldy dpx
1475 uint32_t low = 0;
1476 uint32_t high = AdrDpx(&low);
1477 Ldy(low, high);
1478 break;
1479 }
1480 case 0xb5: { // lda dpx
1481 uint32_t low = 0;
1482 uint32_t high = AdrDpx(&low);
1483 Lda(low, high);
1484 break;
1485 }
1486 case 0xb6: { // ldx dpy
1487 uint32_t low = 0;
1488 uint32_t high = AdrDpy(&low);
1489 Ldx(low, high);
1490 break;
1491 }
1492 case 0xb7: { // lda ily ([dp],Y)
1493 // CRITICAL: Log LDA [$00],Y at $88CF and $88D4 to trace upload data reads
1494 uint16_t cur_pc = PC - 1;
1495 if (PB == 0x00 && (cur_pc == 0x88CF || cur_pc == 0x88D4)) {
1496 // Read the 24-bit pointer from zero page
1497 uint8_t dp0 = ReadByte(D + 0x00);
1498 uint8_t dp1 = ReadByte(D + 0x01);
1499 uint8_t dp2 = ReadByte(D + 0x02);
1500 uint32_t ptr = dp0 | (dp1 << 8) | (dp2 << 16);
1501 LOG_DEBUG(
1502 "CPU",
1503 "LDA [$00],Y at PC=$%04X: DP=$%04X, [$00]=$%02X:$%04X, Y=$%04X",
1504 cur_pc, D, dp2, (uint16_t)(dp0 | (dp1 << 8)), Y);
1505 LOG_DEBUG("CPU", " -> Reading 16-bit value from address $%06X",
1506 ptr + Y);
1507 }
1508 uint32_t low = 0;
1509 uint32_t high = AdrIly(&low);
1510 Lda(low, high);
1511 // Log the value read
1512 if (PB == 0x00 && (cur_pc == 0x88CF || cur_pc == 0x88D4)) {
1513 LOG_DEBUG("CPU", " -> Read value A=$%04X", A);
1514 }
1515 break;
1516 }
1517 case 0xb8: { // clv imp
1518 AdrImp();
1519 SetOverflowFlag(false);
1520 break;
1521 }
1522 case 0xb9: { // lda aby(r)
1523 uint32_t low = 0;
1524 uint32_t high = AdrAby(&low, false);
1525 Lda(low, high);
1526 break;
1527 }
1528 case 0xba: { // tsx imp
1529 AdrImp();
1530 if (GetIndexSize()) {
1531 SetSP(X & 0xff);
1532 } else {
1533 SetSP(X);
1534 }
1535 SetZN(X, GetIndexSize());
1536 break;
1537 }
1538 case 0xbb: { // tyx imp
1539 AdrImp();
1540 if (GetIndexSize()) {
1541 X = Y & 0xff;
1542 } else {
1543 X = Y;
1544 }
1545 SetZN(X, GetIndexSize());
1546 break;
1547 }
1548 case 0xbc: { // ldy abx(r)
1549 uint32_t low = 0;
1550 uint32_t high = AdrAbx(&low, false);
1551 Ldy(low, high);
1552 break;
1553 }
1554 case 0xbd: { // lda abx(r)
1555 uint32_t low = 0;
1556 uint32_t high = AdrAbx(&low, false);
1557 Lda(low, high);
1558 break;
1559 }
1560 case 0xbe: { // ldx aby(r)
1561 uint32_t low = 0;
1562 uint32_t high = AdrAby(&low, false);
1563 Ldx(low, high);
1564 break;
1565 }
1566 case 0xbf: { // lda alx
1567 uint32_t low = 0;
1568 uint32_t high = AdrAlx(&low);
1569 Lda(low, high);
1570 break;
1571 }
1572 case 0xc0: { // cpy imm(x)
1573 uint32_t low = 0;
1574 uint32_t high = Immediate(&low, true);
1575 Cpy(low, high);
1576 break;
1577 }
1578 case 0xc1: { // cmp idx
1579 uint32_t low = 0;
1580 uint32_t high = AdrIdx(&low);
1581 Cmp(low, high);
1582 break;
1583 }
1584 case 0xc2: { // rep imm(s)
1585 uint8_t val = ReadOpcode();
1586 CheckInt();
1587 SetFlags(status & ~val);
1588 callbacks_.idle(false);
1589 break;
1590 }
1591 case 0xc3: { // cmp sr
1592 uint32_t low = 0;
1593 uint32_t high = AdrSr(&low);
1594 Cmp(low, high);
1595 break;
1596 }
1597 case 0xc4: { // cpy dp
1598 uint32_t low = 0;
1599 uint32_t high = AdrDp(&low);
1600 Cpy(low, high);
1601 break;
1602 }
1603 case 0xc5: { // cmp dp
1604 uint32_t low = 0;
1605 uint32_t high = AdrDp(&low);
1606 Cmp(low, high);
1607 break;
1608 }
1609 case 0xc6: { // dec dp
1610 uint32_t low = 0;
1611 uint32_t high = AdrDp(&low);
1612 Dec(low, high);
1613 break;
1614 }
1615 case 0xc7: { // cmp idl
1616 uint32_t low = 0;
1617 uint32_t high = AdrIdl(&low);
1618 Cmp(low, high);
1619 break;
1620 }
1621 case 0xc8: { // iny imp
1622 AdrImp();
1623 if (GetIndexSize()) {
1624 Y = (Y + 1) & 0xff;
1625 } else {
1626 Y++;
1627 }
1628 SetZN(Y, GetIndexSize());
1629 break;
1630 }
1631 case 0xc9: { // cmp imm(m)
1632 uint32_t low = 0;
1633 uint32_t high = Immediate(&low, false);
1634 Cmp(low, high);
1635 break;
1636 }
1637 case 0xca: { // dex imp
1638 AdrImp();
1639 if (GetIndexSize()) {
1640 X = (X - 1) & 0xff;
1641 } else {
1642 X--;
1643 }
1644 SetZN(X, GetIndexSize());
1645 break;
1646 }
1647 case 0xcb: { // wai imp
1648 waiting_ = true;
1649 callbacks_.idle(false);
1650 callbacks_.idle(false);
1651 break;
1652 }
1653 case 0xcc: { // cpy abs
1654 uint32_t low = 0;
1655 uint32_t high = Absolute(&low);
1656 Cpy(low, high);
1657 break;
1658 }
1659 case 0xcd: { // cmp abs
1660 uint32_t low = 0;
1661 uint32_t high = Absolute(&low);
1662 Cmp(low, high);
1663 break;
1664 }
1665 case 0xce: { // dec abs
1666 uint32_t low = 0;
1667 uint32_t high = Absolute(&low);
1668 Dec(low, high);
1669 break;
1670 }
1671 case 0xcf: { // cmp abl
1672 uint32_t low = 0;
1673 uint32_t high = AdrAbl(&low);
1674 Cmp(low, high);
1675 break;
1676 }
1677 case 0xd0: { // bne rel
1679 break;
1680 }
1681 case 0xd1: { // cmp idy(r)
1682 uint32_t low = 0;
1683 uint32_t high = AdrIdy(&low, false);
1684 Cmp(low, high);
1685 break;
1686 }
1687 case 0xd2: { // cmp idp
1688 uint32_t low = 0;
1689 uint32_t high = AdrIdp(&low);
1690 Cmp(low, high);
1691 break;
1692 }
1693 case 0xd3: { // cmp isy
1694 uint32_t low = 0;
1695 uint32_t high = AdrIsy(&low);
1696 Cmp(low, high);
1697 break;
1698 }
1699 case 0xd4: { // pei dp
1700 uint32_t low = 0;
1701 uint32_t high = AdrDp(&low);
1702 PushWord(ReadWord(low, high, false), true);
1703 break;
1704 }
1705 case 0xd5: { // cmp dpx
1706 uint32_t low = 0;
1707 uint32_t high = AdrDpx(&low);
1708 Cmp(low, high);
1709 break;
1710 }
1711 case 0xd6: { // dec dpx
1712 uint32_t low = 0;
1713 uint32_t high = AdrDpx(&low);
1714 Dec(low, high);
1715 break;
1716 }
1717 case 0xd7: { // cmp ily
1718 uint32_t low = 0;
1719 uint32_t high = AdrIly(&low);
1720 Cmp(low, high);
1721 break;
1722 }
1723 case 0xd8: { // cld imp
1724 AdrImp();
1725 SetDecimalFlag(false);
1726 break;
1727 }
1728 case 0xd9: { // cmp aby(r)
1729 uint32_t low = 0;
1730 uint32_t high = AdrAby(&low, false);
1731 Cmp(low, high);
1732 break;
1733 }
1734 case 0xda: { // phx imp
1735 callbacks_.idle(false);
1736 if (GetIndexSize()) {
1737 CheckInt();
1738 PushByte(X);
1739 } else {
1740 PushWord(X, true);
1741 }
1742 break;
1743 }
1744 case 0xdb: { // stp imp
1745 stopped_ = true;
1746 callbacks_.idle(false);
1747 callbacks_.idle(false);
1748 break;
1749 }
1750 case 0xdc: { // jml ial
1751 uint16_t adr = ReadOpcodeWord(false);
1752 PC = ReadWord(adr, ((adr + 1) & 0xffff), false);
1753 CheckInt();
1754 PB = ReadByte((adr + 2) & 0xffff);
1755 break;
1756 }
1757 case 0xdd: { // cmp abx(r)
1758 uint32_t low = 0;
1759 uint32_t high = AdrAbx(&low, false);
1760 Cmp(low, high);
1761 break;
1762 }
1763 case 0xde: { // dec abx
1764 uint32_t low = 0;
1765 uint32_t high = AdrAbx(&low, true);
1766 Dec(low, high);
1767 break;
1768 }
1769 case 0xdf: { // cmp alx
1770 uint32_t low = 0;
1771 uint32_t high = AdrAlx(&low);
1772 Cmp(low, high);
1773 break;
1774 }
1775 case 0xe0: { // cpx imm(x)
1776 uint32_t low = 0;
1777 uint32_t high = Immediate(&low, true);
1778 Cpx(low, high);
1779 break;
1780 }
1781 case 0xe1: { // sbc idx
1782 uint32_t low = 0;
1783 uint32_t high = AdrIdx(&low);
1784 Sbc(low, high);
1785 break;
1786 }
1787 case 0xe2: { // sep imm(s)
1788 uint8_t val = ReadOpcode();
1789 CheckInt();
1790 SetFlags(status | val);
1791 callbacks_.idle(false);
1792 break;
1793 }
1794 case 0xe3: { // sbc sr
1795 uint32_t low = 0;
1796 uint32_t high = AdrSr(&low);
1797 Sbc(low, high);
1798 break;
1799 }
1800 case 0xe4: { // cpx dp
1801 uint32_t low = 0;
1802 uint32_t high = AdrDp(&low);
1803 Cpx(low, high);
1804 break;
1805 }
1806 case 0xe5: { // sbc dp
1807 uint32_t low = 0;
1808 uint32_t high = AdrDp(&low);
1809 Sbc(low, high);
1810 break;
1811 }
1812 case 0xe6: { // inc dp
1813 uint32_t low = 0;
1814 uint32_t high = AdrDp(&low);
1815 Inc(low, high);
1816 break;
1817 }
1818 case 0xe7: { // sbc idl
1819 uint32_t low = 0;
1820 uint32_t high = AdrIdl(&low);
1821 Sbc(low, high);
1822 break;
1823 }
1824 case 0xe8: { // inx imp
1825 AdrImp();
1826 if (GetIndexSize()) {
1827 X = (X + 1) & 0xff;
1828 } else {
1829 X++;
1830 }
1831 SetZN(X, GetIndexSize());
1832 break;
1833 }
1834 case 0xe9: { // sbc imm(m)
1835 uint32_t low = 0;
1836 uint32_t high = Immediate(&low, false);
1837 Sbc(low, high);
1838 break;
1839 }
1840 case 0xea: { // nop imp
1841 AdrImp();
1842 // no operation
1843 break;
1844 }
1845 case 0xeb: { // xba imp
1846 uint8_t low = A & 0xff;
1847 uint8_t high = A >> 8;
1848 A = (low << 8) | high;
1849 SetZN(high, true);
1850 callbacks_.idle(false);
1851 CheckInt();
1852 callbacks_.idle(false);
1853 break;
1854 }
1855 case 0xec: { // cpx abs
1856 uint32_t low = 0;
1857 uint32_t high = Absolute(&low);
1858 Cpx(low, high);
1859 break;
1860 }
1861 case 0xed: { // sbc abs
1862 uint32_t low = 0;
1863 uint32_t high = Absolute(&low);
1864 Sbc(low, high);
1865 break;
1866 }
1867 case 0xee: { // inc abs
1868 uint32_t low = 0;
1869 uint32_t high = Absolute(&low);
1870 Inc(low, high);
1871 break;
1872 }
1873 case 0xef: { // sbc abl
1874 uint32_t low = 0;
1875 uint32_t high = AdrAbl(&low);
1876 Sbc(low, high);
1877 break;
1878 }
1879 case 0xf0: { // beq rel
1881 break;
1882 }
1883 case 0xf1: { // sbc idy(r)
1884 uint32_t low = 0;
1885 uint32_t high = AdrIdy(&low, false);
1886 Sbc(low, high);
1887 break;
1888 }
1889 case 0xf2: { // sbc idp
1890 uint32_t low = 0;
1891 uint32_t high = AdrIdp(&low);
1892 Sbc(low, high);
1893 break;
1894 }
1895 case 0xf3: { // sbc isy
1896 uint32_t low = 0;
1897 uint32_t high = AdrIsy(&low);
1898 Sbc(low, high);
1899 break;
1900 }
1901 case 0xf4: { // pea imm(l)
1902 PushWord(ReadOpcodeWord(false), true);
1903 break;
1904 }
1905 case 0xf5: { // sbc dpx
1906 uint32_t low = 0;
1907 uint32_t high = AdrDpx(&low);
1908 Sbc(low, high);
1909 break;
1910 }
1911 case 0xf6: { // inc dpx
1912 uint32_t low = 0;
1913 uint32_t high = AdrDpx(&low);
1914 Inc(low, high);
1915 break;
1916 }
1917 case 0xf7: { // sbc ily
1918 uint32_t low = 0;
1919 uint32_t high = AdrIly(&low);
1920 Sbc(low, high);
1921 break;
1922 }
1923 case 0xf8: { // sed imp
1924 AdrImp();
1925 SetDecimalFlag(true);
1926 break;
1927 }
1928 case 0xf9: { // sbc aby(r)
1929 uint32_t low = 0;
1930 uint32_t high = AdrAby(&low, false);
1931 Sbc(low, high);
1932 break;
1933 }
1934 case 0xfa: { // plx imp
1935 callbacks_.idle(false);
1936 callbacks_.idle(false);
1937 if (GetIndexSize()) {
1938 CheckInt();
1939 X = PopByte();
1940 } else {
1941 X = PopWord(true);
1942 }
1943 SetZN(X, GetIndexSize());
1944 break;
1945 }
1946 case 0xfb: { // xce imp
1947 AdrImp();
1948 bool temp = GetCarryFlag();
1949 SetCarryFlag(E);
1950 E = temp;
1951 SetFlags(status); // updates x and m flags, clears upper half of x and y
1952 // if needed
1953 break;
1954 }
1955 case 0xfc: { // jsr iax
1956 uint8_t adrl = ReadOpcode();
1957 PushWord(PC, false);
1958 uint16_t adr = adrl | (ReadOpcode() << 8);
1959 callbacks_.idle(false);
1960 uint16_t value = ReadWord((PB << 16) | ((adr + X) & 0xffff),
1961 (PB << 16) | ((adr + X + 1) & 0xffff), true);
1962 PC = value;
1963 break;
1964 }
1965 case 0xfd: { // sbc abx(r)
1966 uint32_t low = 0;
1967 uint32_t high = AdrAbx(&low, false);
1968 Sbc(low, high);
1969 break;
1970 }
1971 case 0xfe: { // inc abx
1972 uint32_t low = 0;
1973 uint32_t high = AdrAbx(&low, true);
1974 Inc(low, high);
1975 break;
1976 }
1977 case 0xff: { // sbc alx
1978 uint32_t low = 0;
1979 uint32_t high = AdrAlx(&low);
1980 Sbc(low, high);
1981 break;
1982 }
1983 }
1984 // REMOVED: Old log_instructions_ check - now using on_instruction_executed_
1985 // callback which is more efficient and always active (records to
1986 // DisassemblyViewer)
1987 LogInstructions(cache_pc, opcode, operand, immediate, accumulator_mode);
1988}
1989
1990void Cpu::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
1991 bool immediate, bool accumulator_mode) {
1992 // Build full 24-bit address
1993 uint32_t full_address = (PB << 16) | PC;
1994
1995 // Extract operand bytes based on instruction size
1996 std::vector<uint8_t> operand_bytes;
1997 std::string operand_str;
1998
1999 if (operand) {
2000 if (immediate) {
2001 operand_str += "#";
2002 }
2003
2004 if (accumulator_mode) {
2005 // 8-bit operand
2006 operand_bytes.push_back(operand & 0xFF);
2007 operand_str += absl::StrFormat("$%02X", operand & 0xFF);
2008 } else {
2009 // 16-bit operand (little-endian)
2010 operand_bytes.push_back(operand & 0xFF);
2011 operand_bytes.push_back((operand >> 8) & 0xFF);
2012 operand_str += absl::StrFormat("$%04X", operand);
2013 }
2014 }
2015
2016 // Get mnemonic
2017 const std::string& mnemonic = opcode_to_mnemonic.at(opcode);
2018
2019 // ALWAYS record to DisassemblyViewer (sparse, Mesen-style, zero cost)
2020 // The callback only fires if set, and DisassemblyViewer only stores unique
2021 // addresses
2022 // - First execution: Add to map (O(log n))
2023 // - Subsequent: Increment counter (O(log n))
2024 // - Total overhead: ~0.1% even with millions of instructions
2026 on_instruction_executed_(full_address, opcode, operand_bytes, mnemonic,
2027 operand_str);
2028 }
2029}
2030
2031void Cpu::SaveState(std::ostream& stream) {
2032 // Registers
2033 stream.write(reinterpret_cast<const char*>(&A), sizeof(A));
2034 stream.write(reinterpret_cast<const char*>(&X), sizeof(X));
2035 stream.write(reinterpret_cast<const char*>(&Y), sizeof(Y));
2036 stream.write(reinterpret_cast<const char*>(&D), sizeof(D));
2037 stream.write(reinterpret_cast<const char*>(&DB), sizeof(DB));
2038 stream.write(reinterpret_cast<const char*>(&PB), sizeof(PB));
2039 stream.write(reinterpret_cast<const char*>(&PC), sizeof(PC));
2040 stream.write(reinterpret_cast<const char*>(&status), sizeof(status));
2041
2042 // Flags and State
2043 stream.write(reinterpret_cast<const char*>(&E), sizeof(E));
2044 stream.write(reinterpret_cast<const char*>(&waiting_), sizeof(waiting_));
2045 stream.write(reinterpret_cast<const char*>(&stopped_), sizeof(stopped_));
2046 stream.write(reinterpret_cast<const char*>(&irq_wanted_), sizeof(irq_wanted_));
2047 stream.write(reinterpret_cast<const char*>(&nmi_wanted_), sizeof(nmi_wanted_));
2048 stream.write(reinterpret_cast<const char*>(&reset_wanted_), sizeof(reset_wanted_));
2049 stream.write(reinterpret_cast<const char*>(&int_wanted_), sizeof(int_wanted_));
2050 stream.write(reinterpret_cast<const char*>(&int_delay_), sizeof(int_delay_));
2051
2052 // Breakpoints
2053 constexpr uint32_t kMaxBreakpoints = 1024;
2054 uint32_t bp_count =
2055 static_cast<uint32_t>(std::min<size_t>(breakpoints_.size(), kMaxBreakpoints));
2056 stream.write(reinterpret_cast<const char*>(&bp_count), sizeof(bp_count));
2057 if (bp_count > 0) {
2058 stream.write(reinterpret_cast<const char*>(breakpoints_.data()), bp_count * sizeof(uint32_t));
2059 }
2060}
2061
2062void Cpu::LoadState(std::istream& stream) {
2063 // Registers
2064 stream.read(reinterpret_cast<char*>(&A), sizeof(A));
2065 stream.read(reinterpret_cast<char*>(&X), sizeof(X));
2066 stream.read(reinterpret_cast<char*>(&Y), sizeof(Y));
2067 stream.read(reinterpret_cast<char*>(&D), sizeof(D));
2068 stream.read(reinterpret_cast<char*>(&DB), sizeof(DB));
2069 stream.read(reinterpret_cast<char*>(&PB), sizeof(PB));
2070 stream.read(reinterpret_cast<char*>(&PC), sizeof(PC));
2071 stream.read(reinterpret_cast<char*>(&status), sizeof(status));
2072
2073 // Flags and State
2074 stream.read(reinterpret_cast<char*>(&E), sizeof(E));
2075 stream.read(reinterpret_cast<char*>(&waiting_), sizeof(waiting_));
2076 stream.read(reinterpret_cast<char*>(&stopped_), sizeof(stopped_));
2077 stream.read(reinterpret_cast<char*>(&irq_wanted_), sizeof(irq_wanted_));
2078 stream.read(reinterpret_cast<char*>(&nmi_wanted_), sizeof(nmi_wanted_));
2079 stream.read(reinterpret_cast<char*>(&reset_wanted_), sizeof(reset_wanted_));
2080 stream.read(reinterpret_cast<char*>(&int_wanted_), sizeof(int_wanted_));
2081 stream.read(reinterpret_cast<char*>(&int_delay_), sizeof(int_delay_));
2082
2083 // Breakpoints
2084 uint32_t bp_count;
2085 stream.read(reinterpret_cast<char*>(&bp_count), sizeof(bp_count));
2086 constexpr uint32_t kMaxBreakpoints = 1024;
2087 const uint32_t safe_count = std::min(bp_count, kMaxBreakpoints);
2088 breakpoints_.resize(safe_count);
2089 if (safe_count > 0) {
2090 stream.read(reinterpret_cast<char*>(breakpoints_.data()), safe_count * sizeof(uint32_t));
2091 }
2092 // Discard any excess breakpoints to keep stream position consistent.
2093 if (bp_count > safe_count) {
2094 std::vector<char> discard((bp_count - safe_count) * sizeof(uint32_t));
2095 stream.read(discard.data(), discard.size());
2096 }
2097}
2098} // namespace emu
2099} // namespace yaze
uint16_t SP() const
Definition cpu.h:765
uint16_t D
Definition cpu.h:77
void Stx(uint32_t low, uint32_t high)
debug::DisassemblyViewer & disassembly_viewer()
Definition cpu.cc:19
uint8_t status
Definition cpu.h:81
bool GetNegativeFlag() const
Definition cpu.h:158
uint32_t AdrAby(uint32_t *low, bool write)
bool GetInterruptFlag() const
Definition cpu.h:162
std::function< void(uint32_t address, uint8_t opcode, const std::vector< uint8_t > &operands, const std::string &mnemonic, const std::string &operand_str) on_instruction_executed_)
Definition cpu.h:71
uint32_t AdrAbl(uint32_t *low)
void Asl(uint32_t low, uint32_t high)
uint32_t AdrIdy(uint32_t *low, bool write)
Definition addressing.cc:55
void Inc(uint32_t low, uint32_t high)
bool stopped_
Definition cpu.h:826
uint8_t DB
Definition cpu.h:78
uint32_t AdrSr(uint32_t *low)
Definition addressing.cc:87
void SetZN(uint16_t value, bool byte)
Definition cpu.h:130
void Ldy(uint32_t low, uint32_t high)
uint32_t Immediate(uint32_t *low, bool xFlag)
Definition addressing.cc:18
uint16_t ReadWord(uint32_t address)
Definition cpu.h:181
uint16_t X
Definition cpu.h:75
void Sta(uint32_t low, uint32_t high)
uint8_t ReadByte(uint32_t address)
Definition cpu.h:178
uint32_t AdrIdl(uint32_t *low)
Definition addressing.cc:67
void Cpy(uint32_t low, uint32_t high)
void SetDecimalFlag(bool set)
Definition cpu.h:152
uint16_t Y
Definition cpu.h:76
uint8_t ReadOpcode()
Definition cpu.h:168
bool GetZeroFlag() const
Definition cpu.h:163
uint32_t AdrAbx(uint32_t *low, bool write)
void CheckInt()
Definition cpu.h:784
void SaveState(std::ostream &stream)
Definition cpu.cc:2031
uint32_t AdrDp(uint32_t *low)
void Bit(uint32_t low, uint32_t high)
std::function< bool(uint32_t pc)> on_breakpoint_hit_
Definition cpu.h:65
void LoadState(std::istream &stream)
Definition cpu.cc:2062
bool waiting_
Definition cpu.h:825
int GetIndexSize() const
Definition cpu.h:144
void And(uint32_t low, uint32_t high)
void SetZeroFlag(bool set)
Definition cpu.h:154
void WriteByte(uint32_t address, uint8_t value)
Definition cpu.h:204
bool reset_wanted_
Definition cpu.h:830
uint16_t PC
Definition cpu.h:80
void ORA(uint32_t low, uint32_t high)
uint16_t A
Definition cpu.h:74
uint32_t AdrIdp(uint32_t *low)
Definition addressing.cc:46
void Sbc(uint32_t low, uint32_t high)
void Trb(uint32_t low, uint32_t high)
void Lda(uint32_t low, uint32_t high)
void Cpx(uint32_t low, uint32_t high)
void Rol(uint32_t low, uint32_t high)
uint32_t AdrDpy(uint32_t *low)
Definition addressing.cc:37
uint8_t PB
Definition cpu.h:79
void Tsb(uint32_t low, uint32_t high)
void Dec(uint32_t low, uint32_t high)
void SetFlags(uint8_t val)
Definition cpu.h:117
void DoInterrupt()
Definition cpu.cc:253
void Ldx(uint32_t low, uint32_t high)
void PushByte(uint8_t value)
Definition cpu.h:228
void PushWord(uint16_t value, bool int_check=false)
Definition cpu.h:234
int GetAccumulatorSize() const
Definition cpu.h:143
uint32_t AdrIly(uint32_t *low)
Definition addressing.cc:77
void LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand, bool immediate, bool accumulator_mode)
Definition cpu.cc:1990
void SetOverflowFlag(bool set)
Definition cpu.h:150
void ExecuteInstruction(uint8_t opcode)
Definition cpu.cc:270
uint32_t AdrIdx(uint32_t *low)
uint32_t Absolute(uint32_t *low)
uint32_t AdrAlx(uint32_t *low)
void Reset(bool hard=false)
Definition cpu.cc:34
uint16_t PopWord(bool int_check=false)
Definition cpu.h:251
void SetCarryFlag(bool set)
Definition cpu.h:155
void SetInterruptFlag(bool set)
Definition cpu.h:153
bool GetCarryFlag() const
Definition cpu.h:164
bool irq_wanted_
Definition cpu.h:828
void RunOpcode()
Definition cpu.cc:56
CpuCallbacks callbacks_
Definition cpu.h:835
void DoBranch(bool check)
Definition cpu.h:263
void Eor(uint32_t low, uint32_t high)
void SetSP(uint16_t value)
Definition cpu.h:766
uint32_t AdrIsy(uint32_t *low)
Definition addressing.cc:94
bool int_delay_
Definition cpu.h:832
debug::DisassemblyViewer * disassembly_viewer_
Definition cpu.h:86
void Stz(uint32_t low, uint32_t high)
void Cmp(uint32_t low, uint32_t high)
uint8_t PopByte()
Definition cpu.h:245
std::vector< uint32_t > breakpoints_
Definition cpu.h:57
uint16_t ReadOpcodeWord(bool int_check=false)
Definition cpu.h:170
uint8_t E
Definition cpu.h:103
void Ror(uint32_t low, uint32_t high)
bool GetOverflowFlag() const
Definition cpu.h:159
bool int_wanted_
Definition cpu.h:831
void Sty(uint32_t low, uint32_t high)
bool nmi_wanted_
Definition cpu.h:829
void Lsr(uint32_t low, uint32_t high)
uint32_t AdrDpx(uint32_t *low)
Definition addressing.cc:28
void Adc(uint32_t low, uint32_t high)
Advanced disassembly viewer with sparse storage and interactive features.
const std::unordered_map< uint8_t, std::string > opcode_to_mnemonic
Definition opcodes.h:7
#define LOG_DEBUG(category, format,...)
Definition log.h:103
#define LOG_INFO(category, format,...)
Definition log.h:105
std::function< void(bool waiting)> idle
Definition memory.h:53
std::function< uint8_t(uint32_t)> read_byte
Definition memory.h:51