10#include "absl/strings/str_format.h"
59 uint32_t current_pc = (
PB << 16) |
PC;
76 sp = (sp & 0xff) | 0x100;
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);
96 static int stopped_log_count = 0;
97 if (stopped_log_count++ < 5) {
99 "CPU is STOPPED at $%02X:%04X (STP instruction executed)",
PB,
106 static int waiting_log_count = 0;
107 if (waiting_log_count++ < 5) {
109 "CPU is WAITING at $%02X:%04X - irq_wanted=%d nmi_wanted=%d "
134 static int instruction_count = 0;
136 uint16_t cur_pc =
PC - 1;
139 static bool entered_bank00 =
false;
140 static bool logged_first_nmi =
false;
142 if (
PB == 0x00 && !entered_bank00) {
144 "=== ENTERED BANK $00 at PC=$%04X (instruction #%d) ===", cur_pc,
146 entered_bank00 =
true;
151 LOG_INFO(
"CPU_AUDIO",
"=== FIRST NMI TRIGGERED at PC=$%02X:%04X ===",
PB,
153 logged_first_nmi =
true;
158 static bool logged_routines[0x10000] = {
false};
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]) {
165 "NMI code: PC=$00:%04X A=$%02X X=$%04X Y=$%04X", cur_pc,
167 logged_routines[cur_pc] =
true;
176 if (cur_pc >= 0x8888 && cur_pc <= 0x88FF) {
178 if (cur_pc == 0x8888) {
180 ">>> LoadSongBank ENTRY at $8888! A=$%02X X=$%04X",
A & 0xFF,
187 static int exec_count_8888 = 0;
188 if (exec_count_8888++ < 100 && !logged_routines[cur_pc]) {
190 " LoadSongBank: PC=$%04X A=$%02X X=$%04X Y=$%04X SP=$%04X "
192 cur_pc,
A & 0xFF,
X,
Y,
SP(), exec_count_8888);
193 logged_routines[cur_pc] =
true;
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",
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) {
213 "Handshake wait: PC=$%04X A=$%02X F4=$%02X X=$%04X [loop #%d]",
214 cur_pc,
A & 0xFF, f4_val,
X, handshake_log_count);
221 bool should_log = instruction_count < 50;
223 LOG_DEBUG(
"CPU",
"Boot #%d: $%02X:%04X opcode=$%02X", instruction_count,
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) {
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);
239 if (stuck_count > 50) {
241 "Moved from $%02X:%04X (was stuck %d times) to $%02X:%04X",
242 PB, last_stuck_pc, stuck_count,
PB,
PC - 1);
245 last_stuck_pc =
PC - 1;
271 uint16_t cache_pc =
PC;
272 uint32_t operand = 0;
273 bool immediate =
false;
278 uint32_t vector = (
E) ? 0xfffe : 0xffe6;
292 uint32_t high =
AdrIdx(&low);
297 uint32_t vector = (
E) ? 0xfff4 : 0xffe4;
311 uint32_t high =
AdrSr(&low);
317 uint32_t high =
AdrDp(&low);
323 uint32_t high =
AdrDp(&low);
329 uint32_t high =
AdrDp(&low);
335 uint32_t high =
AdrIdl(&low);
355 A = (
A & 0xff00) | ((
A << 1) & 0xff);
388 uint32_t high =
AdrAbl(&low);
398 uint32_t high =
AdrIdy(&low,
false);
404 uint32_t high =
AdrIdp(&low);
410 uint32_t high =
AdrIsy(&low);
416 uint32_t high =
AdrDp(&low);
422 uint32_t high =
AdrDpx(&low);
428 uint32_t high =
AdrDpx(&low);
434 uint32_t high =
AdrIly(&low);
445 uint32_t high =
AdrAby(&low,
false);
452 A = (
A & 0xff00) | ((
A + 1) & 0xff);
472 uint32_t high =
AdrAbx(&low,
false);
478 uint32_t high =
AdrAbx(&low,
true);
484 uint32_t high =
AdrAlx(&low);
497 uint32_t high =
AdrIdx(&low);
513 uint32_t high =
AdrSr(&low);
519 uint32_t high =
AdrDp(&low);
525 uint32_t high =
AdrDp(&low);
531 uint32_t high =
AdrDp(&low);
537 uint32_t high =
AdrIdl(&low);
559 A = (
A & 0xff00) | (result & 0xff);
594 uint32_t high =
AdrAbl(&low);
604 uint32_t high =
AdrIdy(&low,
false);
610 uint32_t high =
AdrIdp(&low);
616 uint32_t high =
AdrIsy(&low);
622 uint32_t high =
AdrDpx(&low);
628 uint32_t high =
AdrDpx(&low);
634 uint32_t high =
AdrDpx(&low);
640 uint32_t high =
AdrIly(&low);
651 uint32_t high =
AdrAby(&low,
false);
658 A = (
A & 0xff00) | ((
A - 1) & 0xff);
673 uint32_t high =
AdrAbx(&low,
false);
679 uint32_t high =
AdrAbx(&low,
false);
685 uint32_t high =
AdrAbx(&low,
true);
691 uint32_t high =
AdrAlx(&low);
706 uint32_t high =
AdrIdx(&low);
717 uint32_t high =
AdrSr(&low);
743 uint32_t high =
AdrDp(&low);
749 uint32_t high =
AdrDp(&low);
755 uint32_t high =
AdrIdl(&low);
779 A = (
A & 0xff00) | ((
A >> 1) & 0x7f);
810 uint32_t high =
AdrAbl(&low);
820 uint32_t high =
AdrIdy(&low,
false);
826 uint32_t high =
AdrIdp(&low);
832 uint32_t high =
AdrIsy(&low);
858 uint32_t high =
AdrDpx(&low);
864 uint32_t high =
AdrDpx(&low);
870 uint32_t high =
AdrIly(&low);
881 uint32_t high =
AdrAby(&low,
false);
910 uint32_t high =
AdrAbx(&low,
false);
916 uint32_t high =
AdrAbx(&low,
true);
922 uint32_t high =
AdrAlx(&low);
936 uint32_t high =
AdrIdx(&low);
948 uint32_t high =
AdrSr(&low);
954 uint32_t high =
AdrDp(&low);
960 uint32_t high =
AdrDp(&low);
966 uint32_t high =
AdrDp(&low);
972 uint32_t high =
AdrIdl(&low);
999 A = (
A & 0xff00) | ((
A >> 1) & 0x7f) | (C << 7);
1001 A = (
A >> 1) | (C << 15);
1017 PC =
ReadWord(adr, (adr + 1) & 0xffff,
true);
1034 uint32_t high =
AdrAbl(&low);
1044 uint32_t high =
AdrIdy(&low,
false);
1050 uint32_t high =
AdrIdp(&low);
1056 uint32_t high =
AdrIsy(&low);
1062 uint32_t high =
AdrDpx(&low);
1068 uint32_t high =
AdrDpx(&low);
1074 uint32_t high =
AdrDpx(&low);
1080 uint32_t high =
AdrIly(&low);
1091 uint32_t high =
AdrAby(&low,
false);
1117 ((
PB << 16) | ((adr +
X + 1) & 0xffff)),
true);
1122 uint32_t high =
AdrAbx(&low,
false);
1128 uint32_t high =
AdrAbx(&low,
true);
1134 uint32_t high =
AdrAlx(&low);
1144 uint32_t high =
AdrIdx(&low);
1156 uint32_t high =
AdrSr(&low);
1162 uint32_t high =
AdrDp(&low);
1168 uint32_t high =
AdrDp(&low);
1174 uint32_t high =
AdrDp(&low);
1180 uint32_t high =
AdrIdl(&low);
1208 A = (
A & 0xff00) | (
X & 0xff);
1241 uint32_t high =
AdrAbl(&low);
1251 uint32_t high =
AdrIdy(&low,
true);
1257 uint32_t high =
AdrIdp(&low);
1263 uint32_t high =
AdrIsy(&low);
1269 uint32_t high =
AdrDpx(&low);
1275 uint32_t high =
AdrDpx(&low);
1281 uint32_t high =
AdrDpy(&low);
1287 uint32_t high =
AdrIly(&low);
1294 A = (
A & 0xff00) | (
Y & 0xff);
1303 uint32_t high =
AdrAby(&low,
true);
1330 uint32_t high =
AdrAbx(&low,
true);
1336 uint32_t high =
AdrAbx(&low,
true);
1342 uint32_t high =
AdrAlx(&low);
1354 uint32_t high =
AdrIdx(&low);
1366 uint32_t high =
AdrSr(&low);
1372 uint32_t high =
AdrDp(&low);
1378 uint32_t high =
AdrDp(&low);
1384 uint32_t high =
AdrDp(&low);
1390 uint32_t high =
AdrIdl(&low);
1448 uint32_t high =
AdrAbl(&low);
1458 uint32_t high =
AdrIdy(&low,
false);
1464 uint32_t high =
AdrIdp(&low);
1470 uint32_t high =
AdrIsy(&low);
1476 uint32_t high =
AdrDpx(&low);
1482 uint32_t high =
AdrDpx(&low);
1488 uint32_t high =
AdrDpy(&low);
1494 uint16_t cur_pc =
PC - 1;
1495 if (
PB == 0x00 && (cur_pc == 0x88CF || cur_pc == 0x88D4)) {
1500 uint32_t ptr = dp0 | (dp1 << 8) | (dp2 << 16);
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",
1509 uint32_t high =
AdrIly(&low);
1512 if (
PB == 0x00 && (cur_pc == 0x88CF || cur_pc == 0x88D4)) {
1513 LOG_DEBUG(
"CPU",
" -> Read value A=$%04X",
A);
1524 uint32_t high =
AdrAby(&low,
false);
1550 uint32_t high =
AdrAbx(&low,
false);
1556 uint32_t high =
AdrAbx(&low,
false);
1562 uint32_t high =
AdrAby(&low,
false);
1568 uint32_t high =
AdrAlx(&low);
1580 uint32_t high =
AdrIdx(&low);
1593 uint32_t high =
AdrSr(&low);
1599 uint32_t high =
AdrDp(&low);
1605 uint32_t high =
AdrDp(&low);
1611 uint32_t high =
AdrDp(&low);
1617 uint32_t high =
AdrIdl(&low);
1673 uint32_t high =
AdrAbl(&low);
1683 uint32_t high =
AdrIdy(&low,
false);
1689 uint32_t high =
AdrIdp(&low);
1695 uint32_t high =
AdrIsy(&low);
1701 uint32_t high =
AdrDp(&low);
1707 uint32_t high =
AdrDpx(&low);
1713 uint32_t high =
AdrDpx(&low);
1719 uint32_t high =
AdrIly(&low);
1730 uint32_t high =
AdrAby(&low,
false);
1752 PC =
ReadWord(adr, ((adr + 1) & 0xffff),
false);
1759 uint32_t high =
AdrAbx(&low,
false);
1765 uint32_t high =
AdrAbx(&low,
true);
1771 uint32_t high =
AdrAlx(&low);
1783 uint32_t high =
AdrIdx(&low);
1796 uint32_t high =
AdrSr(&low);
1802 uint32_t high =
AdrDp(&low);
1808 uint32_t high =
AdrDp(&low);
1814 uint32_t high =
AdrDp(&low);
1820 uint32_t high =
AdrIdl(&low);
1846 uint8_t low =
A & 0xff;
1847 uint8_t high =
A >> 8;
1848 A = (low << 8) | high;
1875 uint32_t high =
AdrAbl(&low);
1885 uint32_t high =
AdrIdy(&low,
false);
1891 uint32_t high =
AdrIdp(&low);
1897 uint32_t high =
AdrIsy(&low);
1907 uint32_t high =
AdrDpx(&low);
1913 uint32_t high =
AdrDpx(&low);
1919 uint32_t high =
AdrIly(&low);
1930 uint32_t high =
AdrAby(&low,
false);
1960 uint16_t value =
ReadWord((
PB << 16) | ((adr +
X) & 0xffff),
1961 (
PB << 16) | ((adr +
X + 1) & 0xffff),
true);
1967 uint32_t high =
AdrAbx(&low,
false);
1973 uint32_t high =
AdrAbx(&low,
true);
1979 uint32_t high =
AdrAlx(&low);
1987 LogInstructions(cache_pc, opcode, operand, immediate, accumulator_mode);
1991 bool immediate,
bool accumulator_mode) {
1993 uint32_t full_address = (
PB << 16) |
PC;
1996 std::vector<uint8_t> operand_bytes;
1997 std::string operand_str;
2004 if (accumulator_mode) {
2006 operand_bytes.push_back(operand & 0xFF);
2007 operand_str += absl::StrFormat(
"$%02X", operand & 0xFF);
2010 operand_bytes.push_back(operand & 0xFF);
2011 operand_bytes.push_back((operand >> 8) & 0xFF);
2012 operand_str += absl::StrFormat(
"$%04X", operand);
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));
2043 stream.write(
reinterpret_cast<const char*
>(&
E),
sizeof(
E));
2053 constexpr uint32_t kMaxBreakpoints = 1024;
2055 static_cast<uint32_t
>(std::min<size_t>(
breakpoints_.size(), kMaxBreakpoints));
2056 stream.write(
reinterpret_cast<const char*
>(&bp_count),
sizeof(bp_count));
2058 stream.write(
reinterpret_cast<const char*
>(
breakpoints_.data()), bp_count *
sizeof(uint32_t));
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));
2074 stream.read(
reinterpret_cast<char*
>(&
E),
sizeof(
E));
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);
2089 if (safe_count > 0) {
2090 stream.read(
reinterpret_cast<char*
>(
breakpoints_.data()), safe_count *
sizeof(uint32_t));
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());
void Stx(uint32_t low, uint32_t high)
debug::DisassemblyViewer & disassembly_viewer()
bool GetNegativeFlag() const
uint32_t AdrAby(uint32_t *low, bool write)
bool GetInterruptFlag() const
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_)
uint32_t AdrAbl(uint32_t *low)
void Asl(uint32_t low, uint32_t high)
uint32_t AdrIdy(uint32_t *low, bool write)
void Inc(uint32_t low, uint32_t high)
uint32_t AdrSr(uint32_t *low)
void SetZN(uint16_t value, bool byte)
void Ldy(uint32_t low, uint32_t high)
uint32_t Immediate(uint32_t *low, bool xFlag)
uint16_t ReadWord(uint32_t address)
void Sta(uint32_t low, uint32_t high)
uint8_t ReadByte(uint32_t address)
uint32_t AdrIdl(uint32_t *low)
void Cpy(uint32_t low, uint32_t high)
void SetDecimalFlag(bool set)
uint32_t AdrAbx(uint32_t *low, bool write)
void SaveState(std::ostream &stream)
uint32_t AdrDp(uint32_t *low)
void Bit(uint32_t low, uint32_t high)
std::function< bool(uint32_t pc)> on_breakpoint_hit_
void LoadState(std::istream &stream)
void And(uint32_t low, uint32_t high)
void SetZeroFlag(bool set)
void WriteByte(uint32_t address, uint8_t value)
void ORA(uint32_t low, uint32_t high)
uint32_t AdrIdp(uint32_t *low)
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)
void Tsb(uint32_t low, uint32_t high)
void Dec(uint32_t low, uint32_t high)
void SetFlags(uint8_t val)
void Ldx(uint32_t low, uint32_t high)
void PushByte(uint8_t value)
void PushWord(uint16_t value, bool int_check=false)
int GetAccumulatorSize() const
uint32_t AdrIly(uint32_t *low)
void LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand, bool immediate, bool accumulator_mode)
void SetOverflowFlag(bool set)
void ExecuteInstruction(uint8_t opcode)
uint32_t AdrIdx(uint32_t *low)
uint32_t Absolute(uint32_t *low)
uint32_t AdrAlx(uint32_t *low)
void Reset(bool hard=false)
uint16_t PopWord(bool int_check=false)
void SetCarryFlag(bool set)
void SetInterruptFlag(bool set)
bool GetCarryFlag() const
void DoBranch(bool check)
void Eor(uint32_t low, uint32_t high)
void SetSP(uint16_t value)
uint32_t AdrIsy(uint32_t *low)
debug::DisassemblyViewer * disassembly_viewer_
void Stz(uint32_t low, uint32_t high)
void Cmp(uint32_t low, uint32_t high)
std::vector< uint32_t > breakpoints_
uint16_t ReadOpcodeWord(bool int_check=false)
void Ror(uint32_t low, uint32_t high)
bool GetOverflowFlag() const
void Sty(uint32_t low, uint32_t high)
void Lsr(uint32_t low, uint32_t high)
uint32_t AdrDpx(uint32_t *low)
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
#define LOG_DEBUG(category, format,...)
#define LOG_INFO(category, format,...)
std::function< void(bool waiting)> idle
std::function< uint8_t(uint32_t)> read_byte