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