yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
apu_debugger.cc
Go to the documentation of this file.
1// apu_debugger.cc - APU Handshake Tracker Implementation
2
4
5#include "absl/strings/str_format.h"
6#include "util/log.h"
7
8namespace yaze {
9namespace emu {
10namespace debug {
11
15
18 handshake_complete_ = false;
19 ipl_rom_enabled_ = true;
22
23 memset(cpu_ports_, 0, sizeof(cpu_ports_));
24 memset(spc_ports_, 0, sizeof(spc_ports_));
25
26 blocks_.clear();
27 port_history_.clear();
28
29 LOG_DEBUG("APU_DEBUG", "Handshake tracker reset");
30}
31
32void ApuHandshakeTracker::OnCpuPortWrite(uint8_t port, uint8_t value, uint32_t pc) {
33 if (port > 3) return;
34
35 cpu_ports_[port] = value;
36
37 // Check for handshake acknowledge
38 if (phase_ == Phase::WAITING_BBAA && port == 0 && value == 0xCC) {
41 LogPortWrite(true, port, value, pc, "HANDSHAKE ACKNOWLEDGE");
42 LOG_INFO("APU_DEBUG", "✓ CPU sent handshake $CC at PC=$%06X", pc);
43 return;
44 }
45
46 // Track transfer counter writes
48 if (port == 0) {
49 transfer_counter_ = value;
51 LogPortWrite(true, port, value, pc,
52 absl::StrFormat("Counter=%d", transfer_counter_));
53 } else if (port == 1) {
54 // F5 = continuation flag (0=more blocks, 1=final block)
55 bool is_final = (value & 0x01) != 0;
56 LogPortWrite(true, port, value, pc,
57 is_final ? "FINAL BLOCK" : "More blocks");
58 } else if (port == 2 || port == 3) {
59 // F6:F7 = destination address
60 LogPortWrite(true, port, value, pc, "Dest addr");
61 }
62 } else {
63 LogPortWrite(true, port, value, pc, "");
64 }
65}
66
67void ApuHandshakeTracker::OnSpcPortWrite(uint8_t port, uint8_t value, uint16_t pc) {
68 if (port > 3) return;
69
70 spc_ports_[port] = value;
71
72 // Check for ready signal ($BBAA in F4:F5)
73 if (phase_ == Phase::IPL_BOOT && port == 0 && value == 0xAA) {
74 if (spc_ports_[1] == 0xBB || port == 1) { // Check if both ready
76 LogPortWrite(false, port, value, pc, "READY SIGNAL $BBAA");
77 LOG_INFO("APU_DEBUG", "✓ SPC ready signal: F4=$AA F5=$BB at PC=$%04X", pc);
78 return;
79 }
80 }
81
82 if (phase_ == Phase::IPL_BOOT && port == 1 && value == 0xBB) {
83 if (spc_ports_[0] == 0xAA) {
85 LogPortWrite(false, port, value, pc, "READY SIGNAL $BBAA");
86 LOG_INFO("APU_DEBUG", "✓ SPC ready signal: F4=$AA F5=$BB at PC=$%04X", pc);
87 return;
88 }
89 }
90
91 // Track counter echo during transfer
92 if (phase_ == Phase::TRANSFER_ACTIVE && port == 0) {
93 int echoed_counter = value;
94 if (echoed_counter == transfer_counter_) {
96 LogPortWrite(false, port, value, pc,
97 absl::StrFormat("Echo counter=%d (byte %d)",
98 echoed_counter, total_bytes_transferred_));
99 } else {
100 LogPortWrite(false, port, value, pc,
101 absl::StrFormat("Counter mismatch! Expected=%d Got=%d",
102 transfer_counter_, echoed_counter));
103 LOG_WARN("APU_DEBUG", "Counter mismatch at PC=$%04X: expected %d, got %d",
104 pc, transfer_counter_, echoed_counter);
105 }
106 } else {
107 LogPortWrite(false, port, value, pc, "");
108 }
109}
110
111void ApuHandshakeTracker::OnSpcPCChange(uint16_t old_pc, uint16_t new_pc) {
112 // Detect IPL ROM boot sequence
113 if (phase_ == Phase::RESET && new_pc >= 0xFFC0 && new_pc <= 0xFFFF) {
115 LOG_INFO("APU_DEBUG", "✓ SPC entered IPL ROM at PC=$%04X", new_pc);
116 }
117
118 // Detect IPL ROM disable (jump to uploaded driver)
119 if (ipl_rom_enabled_ && new_pc < 0xFFC0) {
120 ipl_rom_enabled_ = false;
123 LOG_INFO("APU_DEBUG", "✓ Transfer complete! SPC jumped to $%04X (audio driver entry)",
124 new_pc);
125 }
127 }
128}
129
131 if (phase_ != new_phase) {
132 LOG_DEBUG("APU_DEBUG", "Phase change: %s → %s",
133 GetPhaseString().c_str(),
134 [new_phase]() {
135 switch (new_phase) {
136 case Phase::RESET: return "RESET";
137 case Phase::IPL_BOOT: return "IPL_BOOT";
138 case Phase::WAITING_BBAA: return "WAITING_BBAA";
139 case Phase::HANDSHAKE_CC: return "HANDSHAKE_CC";
140 case Phase::TRANSFER_ACTIVE: return "TRANSFER_ACTIVE";
141 case Phase::TRANSFER_DONE: return "TRANSFER_DONE";
142 case Phase::RUNNING: return "RUNNING";
143 default: return "UNKNOWN";
144 }
145 }());
146 phase_ = new_phase;
147 }
148}
149
150void ApuHandshakeTracker::LogPortWrite(bool is_cpu, uint8_t port, uint8_t value,
151 uint32_t pc, const std::string& desc) {
152 PortWrite entry;
153 entry.timestamp = port_history_.size();
154 entry.pc = static_cast<uint16_t>(pc & 0xFFFF);
155 entry.port = port;
156 entry.value = value;
157 entry.is_cpu = is_cpu;
158 entry.description = desc;
159
160 port_history_.push_back(entry);
161
162 // Keep history bounded
163 if (port_history_.size() > kMaxHistorySize) {
164 port_history_.pop_front();
165 }
166}
167
169 switch (phase_) {
170 case Phase::RESET: return "RESET";
171 case Phase::IPL_BOOT: return "IPL_BOOT";
172 case Phase::WAITING_BBAA: return "WAITING_BBAA";
173 case Phase::HANDSHAKE_CC: return "HANDSHAKE_CC";
174 case Phase::TRANSFER_ACTIVE: return "TRANSFER_ACTIVE";
175 case Phase::TRANSFER_DONE: return "TRANSFER_DONE";
176 case Phase::RUNNING: return "RUNNING";
177 default: return "UNKNOWN";
178 }
179}
180
182 return absl::StrFormat(
183 "Phase: %s | Handshake: %s | Bytes: %d | Blocks: %d",
185 handshake_complete_ ? "✓" : "✗",
187 blocks_.size());
188}
189
192 return "";
193 }
194
195 // Estimate progress (typical ALTTP upload is ~8KB)
196 int estimated_total = 8192;
197 int percent = (total_bytes_transferred_ * 100) / estimated_total;
198 percent = std::min(percent, 100);
199
200 int bar_width = 20;
201 int filled = (percent * bar_width) / 100;
202
203 std::string bar = "[";
204 for (int i = 0; i < bar_width; ++i) {
205 bar += (i < filled) ? "█" : "░";
206 }
207 bar += absl::StrFormat("] %d%%", percent);
208
209 return bar;
210}
211
212} // namespace debug
213} // namespace emu
214} // namespace yaze
215
void OnCpuPortWrite(uint8_t port, uint8_t value, uint32_t pc)
void OnSpcPCChange(uint16_t old_pc, uint16_t new_pc)
void LogPortWrite(bool is_cpu, uint8_t port, uint8_t value, uint32_t pc, const std::string &desc)
std::vector< TransferBlock > blocks_
static constexpr size_t kMaxHistorySize
void OnSpcPortWrite(uint8_t port, uint8_t value, uint16_t pc)
std::deque< PortWrite > port_history_
#define LOG_DEBUG(category, format,...)
Definition log.h:104
#define LOG_WARN(category, format,...)
Definition log.h:108
#define LOG_INFO(category, format,...)
Definition log.h:106
Main namespace for the application.