6#include <unordered_set>
8#include "absl/strings/escaping.h"
9#include "absl/strings/str_format.h"
39 return SnesButton::SELECT;
41 return SnesButton::START;
43 return SnesButton::UP;
45 return SnesButton::DOWN;
47 return SnesButton::LEFT;
49 return SnesButton::RIGHT;
57 : emulator_(emulator) {}
63 CommandResponse* response) {
65 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
66 "Emulator not initialized.");
68 response->set_success(
true);
69 response->set_message(
"Emulator started.");
70 return grpc::Status::OK;
75 CommandResponse* response) {
77 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
78 "Emulator not initialized.");
80 response->set_success(
true);
81 response->set_message(
"Emulator stopped.");
82 return grpc::Status::OK;
87 CommandResponse* response) {
89 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
90 "Emulator not initialized.");
92 response->set_success(
true);
93 response->set_message(
"Emulator paused.");
94 return grpc::Status::OK;
99 CommandResponse* response) {
101 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
102 "Emulator not initialized.");
104 response->set_success(
true);
105 response->set_message(
"Emulator resumed.");
106 return grpc::Status::OK;
110 const Empty* request,
111 CommandResponse* response) {
113 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
114 "Emulator not initialized.");
116 response->set_success(
true);
117 response->set_message(
"Emulator reset.");
118 return grpc::Status::OK;
124 const ButtonRequest* request,
125 CommandResponse* response) {
127 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
128 "Emulator not initialized.");
130 for (
int i = 0; i < request->buttons_size(); i++) {
132 ToSnesButton(
static_cast<Button
>(request->buttons(i))));
134 std::this_thread::sleep_for(std::chrono::milliseconds(50));
135 for (
int i = 0; i < request->buttons_size(); i++) {
136 input_manager.ReleaseButton(
137 ToSnesButton(
static_cast<Button
>(request->buttons(i))));
139 response->set_success(
true);
140 return grpc::Status::OK;
144 const ButtonRequest* request,
145 CommandResponse* response) {
147 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
148 "Emulator not initialized.");
150 for (
int i = 0; i < request->buttons_size(); i++) {
152 ToSnesButton(
static_cast<Button
>(request->buttons(i))));
154 response->set_success(
true);
155 return grpc::Status::OK;
159 const ButtonHoldRequest* request,
160 CommandResponse* response) {
162 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
163 "Emulator not initialized.");
165 for (
int i = 0; i < request->buttons_size(); i++) {
167 ToSnesButton(
static_cast<Button
>(request->buttons(i))));
169 std::this_thread::sleep_for(
170 std::chrono::milliseconds(request->duration_ms()));
171 for (
int i = 0; i < request->buttons_size(); i++) {
172 input_manager.ReleaseButton(
173 ToSnesButton(
static_cast<Button
>(request->buttons(i))));
175 response->set_success(
true);
176 return grpc::Status::OK;
182 const GameStateRequest* request,
183 GameStateResponse* response) {
185 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
186 "SNES is not initialized.");
190 response->set_game_mode(memory.ReadByte(0x7E0010));
191 response->set_link_state(memory.ReadByte(0x7E005D));
192 response->set_link_pos_x(memory.ReadWord(0x7E0020));
193 response->set_link_pos_y(memory.ReadWord(0x7E0022));
194 response->set_link_health(memory.ReadByte(0x7EF36D));
196 for (
const auto& mem_req : request->memory_reads()) {
197 auto* mem_resp = response->add_memory_responses();
198 mem_resp->set_address(mem_req.address());
199 std::vector<uint8_t> data(mem_req.size());
200 for (uint32_t i = 0; i < mem_req.size(); ++i) {
201 data[i] = memory.ReadByte(mem_req.address() + i);
203 mem_resp->set_data(data.data(), data.size());
207 if (request->include_screenshot()) {
208 auto screenshot = yaze::test::CaptureHarnessScreenshot();
209 if (screenshot.ok()) {
211 std::ifstream file(screenshot->file_path, std::ios::binary);
213 std::string png_data((std::istreambuf_iterator<char>(file)),
214 std::istreambuf_iterator<char>());
215 response->set_screenshot_png(png_data);
221 return grpc::Status::OK;
225 const MemoryRequest* request,
226 MemoryResponse* response) {
228 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
229 "SNES is not initialized.");
232 response->set_address(request->address());
233 std::vector<uint8_t> data(request->size());
234 for (uint32_t i = 0; i < request->size(); ++i) {
235 data[i] = memory.ReadByte(request->address() + i);
237 response->set_data(data.data(), data.size());
238 return grpc::Status::OK;
242 const MemoryWriteRequest* request,
243 CommandResponse* response) {
245 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
246 "SNES is not initialized.");
249 const std::string& data = request->data();
250 for (uint32_t i = 0; i < data.size(); ++i) {
251 memory.WriteByte(request->address() + i,
static_cast<uint8_t
>(data[i]));
253 response->set_success(
true);
254 response->set_message(absl::StrFormat(
"Wrote %d bytes to 0x%X.", data.size(),
255 request->address()));
256 return grpc::Status::OK;
264 switch (proto_type) {
266 return BreakpointManager::Type::EXECUTE;
268 return BreakpointManager::Type::READ;
270 return BreakpointManager::Type::WRITE;
272 return BreakpointManager::Type::ACCESS;
274 return BreakpointManager::Type::CONDITIONAL;
276 return BreakpointManager::Type::EXECUTE;
285 return BreakpointManager::CpuType::CPU_65816;
287 return BreakpointManager::CpuType::SPC700;
289 return BreakpointManager::CpuType::CPU_65816;
297 case BreakpointManager::Type::EXECUTE:
299 case BreakpointManager::Type::READ:
301 case BreakpointManager::Type::WRITE:
303 case BreakpointManager::Type::ACCESS:
305 case BreakpointManager::Type::CONDITIONAL:
316 case BreakpointManager::CpuType::CPU_65816:
318 case BreakpointManager::CpuType::SPC700:
326 grpc::ServerContext* context,
const BreakpointRequest* request,
327 BreakpointResponse* response) {
329 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
330 "Emulator not initialized.");
336 ToCpuType(request->cpu()), request->condition(), request->description());
338 response->set_success(
true);
339 response->set_breakpoint_id(
id);
340 response->set_message(
341 absl::StrFormat(
"Breakpoint %d added at 0x%06X",
id, request->address()));
342 return grpc::Status::OK;
346 grpc::ServerContext* context,
const BreakpointIdRequest* request,
347 CommandResponse* response) {
349 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
350 "Emulator not initialized.");
354 response->set_success(
true);
355 response->set_message(
356 absl::StrFormat(
"Breakpoint %d removed", request->breakpoint_id()));
357 return grpc::Status::OK;
361 grpc::ServerContext* context,
const Empty* request,
362 BreakpointListResponse* response) {
364 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
365 "Emulator not initialized.");
369 for (
const auto& bp : breakpoints) {
370 auto* info = response->add_breakpoints();
372 info->set_address(bp.address);
375 info->set_enabled(bp.enabled);
376 info->set_condition(bp.condition);
377 info->set_description(bp.description);
378 info->set_hit_count(bp.hit_count);
381 return grpc::Status::OK;
385 grpc::ServerContext* context,
const BreakpointStateRequest* request,
386 CommandResponse* response) {
388 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
389 "Emulator not initialized.");
394 response->set_success(
true);
395 response->set_message(
396 absl::StrFormat(
"Breakpoint %d %s", request->breakpoint_id(),
397 request->enabled() ?
"enabled" :
"disabled"));
398 return grpc::Status::OK;
403 grpc::ServerContext* context,
const WatchpointRequest* request,
404 WatchpointResponse* response) {
406 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
407 "Watchpoints require WatchpointManager integration");
411 grpc::ServerContext* context,
const WatchpointIdRequest* request,
412 CommandResponse* response) {
413 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
414 "Watchpoints require WatchpointManager integration");
418 grpc::ServerContext* context,
const Empty* request,
419 WatchpointListResponse* response) {
420 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
421 "Watchpoints require WatchpointManager integration");
425 grpc::ServerContext* context,
const WatchpointHistoryRequest* request,
426 WatchpointHistoryResponse* response) {
427 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
428 "Watchpoints require WatchpointManager integration");
433 const Empty* request,
434 StepResponse* response) {
436 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
437 "SNES is not initialized.");
442 uint32_t pc_before = (cpu.PB << 16) | cpu.PC;
448 auto* cpu_state = response->mutable_cpu_state();
449 cpu_state->set_a(cpu.A);
450 cpu_state->set_x(cpu.X);
451 cpu_state->set_y(cpu.Y);
452 cpu_state->set_sp(cpu.SP());
453 cpu_state->set_pc(cpu.PC);
454 cpu_state->set_db(cpu.DB);
455 cpu_state->set_pb(cpu.PB);
456 cpu_state->set_d(cpu.D);
457 cpu_state->set_status(cpu.status);
458 cpu_state->set_flag_n(cpu.GetNegativeFlag());
459 cpu_state->set_flag_v(cpu.GetOverflowFlag());
460 cpu_state->set_flag_d(cpu.GetDecimalFlag());
461 cpu_state->set_flag_i(cpu.GetInterruptFlag());
462 cpu_state->set_flag_z(cpu.GetZeroFlag());
463 cpu_state->set_flag_c(cpu.GetCarryFlag());
466 response->set_success(
true);
467 response->set_message(absl::StrFormat(
"Stepped from 0x%06X to 0x%06X",
468 pc_before, (cpu.PB << 16) | cpu.PC));
469 return grpc::Status::OK;
473 grpc::ServerContext* context,
const Empty* request,
474 BreakpointHitResponse* response) {
476 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
477 "SNES is not initialized.");
482 const int kMaxInstructions = 1000000;
483 int instruction_count = 0;
488 while (instruction_count++ < kMaxInstructions) {
489 uint32_t pc = (cpu.PB << 16) | cpu.PC;
492 if (bp_manager.ShouldBreakOnExecute(
494 response->set_hit(
true);
495 response->set_message(
496 absl::StrFormat(
"Breakpoint hit at 0x%06X after %d instructions", pc,
500 auto* last_hit = bp_manager.GetLastHit();
502 auto* bp_info = response->mutable_breakpoint();
503 bp_info->set_id(last_hit->id);
504 bp_info->set_address(last_hit->address);
507 bp_info->set_enabled(last_hit->enabled);
508 bp_info->set_condition(last_hit->condition);
509 bp_info->set_description(last_hit->description);
510 bp_info->set_hit_count(last_hit->hit_count);
514 auto* cpu_state = response->mutable_cpu_state();
515 cpu_state->set_pc(cpu.PC);
516 cpu_state->set_pb(cpu.PB);
517 cpu_state->set_a(cpu.A);
518 cpu_state->set_x(cpu.X);
519 cpu_state->set_y(cpu.Y);
520 cpu_state->set_sp(cpu.SP());
521 cpu_state->set_db(cpu.DB);
522 cpu_state->set_d(cpu.D);
524 return grpc::Status::OK;
532 response->set_hit(
false);
533 response->set_message(absl::StrFormat(
534 "No breakpoint hit after %d instructions (timeout)", kMaxInstructions));
535 return grpc::Status::OK;
539 const Empty* request,
540 StepResponse* response) {
542 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
543 "SNES is not initialized.");
554 auto* cpu_state = response->mutable_cpu_state();
555 cpu_state->set_a(cpu.A);
556 cpu_state->set_x(cpu.X);
557 cpu_state->set_y(cpu.Y);
558 cpu_state->set_sp(cpu.SP());
559 cpu_state->set_pc(cpu.PC);
560 cpu_state->set_db(cpu.DB);
561 cpu_state->set_pb(cpu.PB);
562 cpu_state->set_d(cpu.D);
563 cpu_state->set_status(cpu.status);
564 cpu_state->set_flag_n(cpu.GetNegativeFlag());
565 cpu_state->set_flag_v(cpu.GetOverflowFlag());
566 cpu_state->set_flag_d(cpu.GetDecimalFlag());
567 cpu_state->set_flag_i(cpu.GetInterruptFlag());
568 cpu_state->set_flag_z(cpu.GetZeroFlag());
569 cpu_state->set_flag_c(cpu.GetCarryFlag());
572 response->set_success(result.success);
573 response->set_message(result.message);
574 return grpc::Status::OK;
578 const Empty* request,
579 StepResponse* response) {
581 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
582 "SNES is not initialized.");
590 response->set_success(
false);
591 response->set_message(
"Cannot step out - call stack is empty");
592 return grpc::Status::OK;
600 auto* cpu_state = response->mutable_cpu_state();
601 cpu_state->set_a(cpu.A);
602 cpu_state->set_x(cpu.X);
603 cpu_state->set_y(cpu.Y);
604 cpu_state->set_sp(cpu.SP());
605 cpu_state->set_pc(cpu.PC);
606 cpu_state->set_db(cpu.DB);
607 cpu_state->set_pb(cpu.PB);
608 cpu_state->set_d(cpu.D);
609 cpu_state->set_status(cpu.status);
610 cpu_state->set_flag_n(cpu.GetNegativeFlag());
611 cpu_state->set_flag_v(cpu.GetOverflowFlag());
612 cpu_state->set_flag_d(cpu.GetDecimalFlag());
613 cpu_state->set_flag_i(cpu.GetInterruptFlag());
614 cpu_state->set_flag_z(cpu.GetZeroFlag());
615 cpu_state->set_flag_c(cpu.GetCarryFlag());
618 response->set_success(result.success);
619 response->set_message(result.message);
620 return grpc::Status::OK;
629 return memory.ReadByte(addr);
639 return (cpu.PB << 16) | cpu.PC;
645 grpc::ServerContext* context,
const DisassemblyRequest* request,
646 DisassemblyResponse* response) {
648 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
649 "SNES is not initialized.");
660 auto read_byte = [&memory](uint32_t addr) -> uint8_t {
661 return memory.ReadByte(addr);
667 bool m_flag = cpu.GetAccumulatorSize();
668 bool x_flag = cpu.GetIndexSize();
670 uint32_t current_address = request->start_address();
671 uint32_t instructions_added = 0;
672 const uint32_t max_instructions = std::min(request->count(), 1000u);
677 std::unordered_set<uint32_t> bp_addresses;
678 for (
const auto& bp : breakpoints) {
680 bp_addresses.insert(bp.address);
684 while (instructions_added < max_instructions) {
687 disassembler.
Disassemble(current_address, read_byte, m_flag, x_flag);
689 auto* line = response->add_lines();
690 line->set_address(instruction.address);
691 line->set_opcode(instruction.opcode);
692 line->set_mnemonic(instruction.mnemonic);
693 line->set_operand_str(instruction.operand_str);
694 line->set_size(instruction.size);
695 line->set_execution_count(0);
698 for (
const auto&
byte : instruction.operands) {
699 line->add_operands(
byte);
703 line->set_is_breakpoint(bp_addresses.count(current_address) > 0);
705 current_address += instruction.
size;
706 instructions_added++;
709 return grpc::Status::OK;
713 grpc::ServerContext* context,
const TraceRequest* request,
714 TraceResponse* response) {
716 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
717 "Execution trace not yet implemented");
722 const SymbolFileRequest* request,
723 CommandResponse* response) {
724 std::string filepath = request->filepath();
725 if (filepath.empty()) {
726 response->set_success(
false);
727 response->set_message(
"No filepath specified");
728 return grpc::Status::OK;
733 switch (request->format()) {
734 case SymbolFormat::ASAR:
737 case SymbolFormat::WLA_DX:
740 case SymbolFormat::MESEN:
749 std::filesystem::path path(filepath);
752 if (std::filesystem::is_directory(path)) {
759 response->set_success(
true);
760 response->set_message(
761 absl::StrFormat(
"Loaded %zu symbols from %s",
764 response->set_success(
false);
765 response->set_message(std::string(status.message().data(), status.message().size()));
768 return grpc::Status::OK;
772 grpc::ServerContext* context,
const SymbolLookupRequest* request,
773 SymbolLookupResponse* response) {
774 std::string symbol_name = request->symbol_name();
779 response->set_found(
true);
780 response->set_symbol_name(symbol->name);
781 response->set_address(symbol->address);
782 response->set_type(symbol->is_local ?
"local_label" :
"label");
783 response->set_description(symbol->comment);
784 return grpc::Status::OK;
788 if (symbol_name.find(
'*') != std::string::npos ||
789 symbol_name.find(
'?') != std::string::npos) {
791 if (!matches.empty()) {
793 const auto& first_match = matches[0];
794 response->set_found(
true);
795 response->set_symbol_name(first_match.name);
796 response->set_address(first_match.address);
797 response->set_type(first_match.is_local ?
"local_label" :
"label");
798 response->set_description(
799 absl::StrFormat(
"First of %zu matches", matches.size()));
800 return grpc::Status::OK;
804 response->set_found(
false);
805 response->set_symbol_name(symbol_name);
806 response->set_description(
"Symbol not found");
807 return grpc::Status::OK;
811 const AddressRequest* request,
812 SymbolLookupResponse* response) {
813 uint32_t address = request->address();
818 response->set_found(
true);
819 response->set_symbol_name(symbol->name);
820 response->set_address(symbol->address);
821 response->set_type(symbol->is_local ?
"local_label" :
"label");
822 response->set_description(symbol->comment);
823 return grpc::Status::OK;
828 if (nearest && (address - nearest->address) <= 0x100) {
830 uint32_t offset = address - nearest->address;
831 response->set_found(
true);
832 response->set_symbol_name(
833 absl::StrFormat(
"%s+$%X", nearest->name, offset));
834 response->set_address(address);
835 response->set_type(
"offset");
836 response->set_description(
837 absl::StrFormat(
"Offset $%X from %s", offset, nearest->name));
838 return grpc::Status::OK;
841 response->set_found(
false);
842 response->set_address(address);
843 response->set_description(absl::StrFormat(
"No symbol at $%06X", address));
844 return grpc::Status::OK;
849 grpc::ServerContext* context,
const DebugSessionRequest* request,
850 DebugSessionResponse* response) {
852 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
853 "Emulator not initialized.");
859 response->set_success(
true);
860 response->set_session_id(request->session_name());
861 response->set_message(
862 absl::StrFormat(
"Debug session '%s' created", request->session_name()));
863 return grpc::Status::OK;
867 grpc::ServerContext* context,
const Empty* request,
868 DebugStatusResponse* response) {
870 return grpc::Status(grpc::StatusCode::UNAVAILABLE,
871 "Emulator not initialized.");
881 uint32_t active_bp_count = 0;
882 for (
const auto& bp : breakpoints) {
886 response->set_active_breakpoints(active_bp_count);
887 response->set_active_watchpoints(
892 auto* cpu_state = response->mutable_cpu_state();
893 cpu_state->set_a(cpu.A);
894 cpu_state->set_x(cpu.X);
895 cpu_state->set_y(cpu.Y);
896 cpu_state->set_sp(cpu.SP());
897 cpu_state->set_pc(cpu.PC);
898 cpu_state->set_db(cpu.DB);
899 cpu_state->set_pb(cpu.PB);
900 cpu_state->set_d(cpu.D);
901 cpu_state->set_status(cpu.status);
902 cpu_state->set_flag_n(cpu.GetNegativeFlag());
903 cpu_state->set_flag_v(cpu.GetOverflowFlag());
904 cpu_state->set_flag_d(cpu.GetDecimalFlag());
905 cpu_state->set_flag_i(cpu.GetInterruptFlag());
906 cpu_state->set_flag_z(cpu.GetZeroFlag());
907 cpu_state->set_flag_c(cpu.GetCarryFlag());
913 auto* bp_info = response->mutable_last_breakpoint_hit();
914 bp_info->set_id(last_hit->id);
915 bp_info->set_address(last_hit->address);
918 bp_info->set_enabled(last_hit->enabled);
919 bp_info->set_hit_count(last_hit->hit_count);
922 return grpc::Status::OK;
grpc::Status RemoveBreakpoint(grpc::ServerContext *context, const BreakpointIdRequest *request, CommandResponse *response) override
void InitializeStepController()
grpc::Status GetWatchpointHistory(grpc::ServerContext *context, const WatchpointHistoryRequest *request, WatchpointHistoryResponse *response) override
grpc::Status Stop(grpc::ServerContext *context, const Empty *request, CommandResponse *response) override
EmulatorServiceImpl(yaze::emu::Emulator *emulator)
grpc::Status PressButtons(grpc::ServerContext *context, const ButtonRequest *request, CommandResponse *response) override
grpc::Status ListWatchpoints(grpc::ServerContext *context, const Empty *request, WatchpointListResponse *response) override
grpc::Status StepOver(grpc::ServerContext *context, const Empty *request, StepResponse *response) override
grpc::Status GetSymbolAt(grpc::ServerContext *context, const AddressRequest *request, SymbolLookupResponse *response) override
grpc::Status ListBreakpoints(grpc::ServerContext *context, const Empty *request, BreakpointListResponse *response) override
grpc::Status GetExecutionTrace(grpc::ServerContext *context, const TraceRequest *request, TraceResponse *response) override
grpc::Status ResolveSymbol(grpc::ServerContext *context, const SymbolLookupRequest *request, SymbolLookupResponse *response) override
grpc::Status Pause(grpc::ServerContext *context, const Empty *request, CommandResponse *response) override
grpc::Status StepOut(grpc::ServerContext *context, const Empty *request, StepResponse *response) override
grpc::Status ReleaseButtons(grpc::ServerContext *context, const ButtonRequest *request, CommandResponse *response) override
grpc::Status RunToBreakpoint(grpc::ServerContext *context, const Empty *request, BreakpointHitResponse *response) override
grpc::Status Reset(grpc::ServerContext *context, const Empty *request, CommandResponse *response) override
grpc::Status LoadSymbols(grpc::ServerContext *context, const SymbolFileRequest *request, CommandResponse *response) override
grpc::Status WriteMemory(grpc::ServerContext *context, const MemoryWriteRequest *request, CommandResponse *response) override
grpc::Status GetDisassembly(grpc::ServerContext *context, const DisassemblyRequest *request, DisassemblyResponse *response) override
grpc::Status CreateDebugSession(grpc::ServerContext *context, const DebugSessionRequest *request, DebugSessionResponse *response) override
yaze::emu::debug::SymbolProvider symbol_provider_
grpc::Status HoldButtons(grpc::ServerContext *context, const ButtonHoldRequest *request, CommandResponse *response) override
grpc::Status ReadMemory(grpc::ServerContext *context, const MemoryRequest *request, MemoryResponse *response) override
grpc::Status AddBreakpoint(grpc::ServerContext *context, const BreakpointRequest *request, BreakpointResponse *response) override
grpc::Status Start(grpc::ServerContext *context, const Empty *request, CommandResponse *response) override
grpc::Status RemoveWatchpoint(grpc::ServerContext *context, const WatchpointIdRequest *request, CommandResponse *response) override
grpc::Status StepInstruction(grpc::ServerContext *context, const Empty *request, StepResponse *response) override
grpc::Status SetBreakpointEnabled(grpc::ServerContext *context, const BreakpointStateRequest *request, CommandResponse *response) override
yaze::emu::debug::StepController step_controller_
grpc::Status GetGameState(grpc::ServerContext *context, const GameStateRequest *request, GameStateResponse *response) override
grpc::Status AddWatchpoint(grpc::ServerContext *context, const WatchpointRequest *request, WatchpointResponse *response) override
yaze::emu::Emulator * emulator_
grpc::Status GetDebugStatus(grpc::ServerContext *context, const Empty *request, DebugStatusResponse *response) override
grpc::Status Resume(grpc::ServerContext *context, const Empty *request, CommandResponse *response) override
Manages CPU and SPC700 breakpoints for debugging.
void RemoveBreakpoint(uint32_t id)
Remove a breakpoint by ID.
void SetEnabled(uint32_t id, bool enabled)
Enable or disable a breakpoint.
std::vector< Breakpoint > GetAllBreakpoints() const
Get all breakpoints.
const Breakpoint * GetLastHit() const
Get the last breakpoint that was hit.
uint32_t AddBreakpoint(uint32_t address, Type type, CpuType cpu, const std::string &condition="", const std::string &description="")
Add a new breakpoint.
A class for emulating and debugging SNES games.
BreakpointManager & breakpoint_manager()
double GetCurrentFPS() const
void set_debugging(bool debugging)
uint64_t GetCurrentCycle()
void StepSingleInstruction()
input::InputManager & input_manager()
void set_running(bool running)
bool is_snes_initialized() const
auto running() const -> bool
65816 CPU disassembler for debugging and ROM hacking
DisassembledInstruction Disassemble(uint32_t address, MemoryReader read_byte, bool m_flag=true, bool x_flag=true) const
Disassemble a single instruction.
void SetMemoryReader(MemoryReader reader)
void SetPcGetter(PcGetter getter)
StepResult StepOver(uint32_t max_instructions=1000000)
Step over the current instruction.
size_t GetCallDepth() const
Get the current call depth.
void SetSingleStepper(SingleStepper stepper)
StepResult StepOut(uint32_t max_instructions=1000000)
Step out of the current subroutine.
size_t GetSymbolCount() const
Get total number of loaded symbols.
absl::Status LoadAsarAsmDirectory(const std::string &directory_path)
Load symbols from a directory of ASM files.
absl::Status LoadSymbolFile(const std::string &path, SymbolFormat format=SymbolFormat::kAuto)
Load symbols from a .sym file (various formats)
std::optional< Symbol > GetNearestSymbol(uint32_t address) const
Get nearest symbol at or before an address.
std::optional< Symbol > GetSymbol(uint32_t address) const
Get full symbol info for an address.
std::optional< Symbol > FindSymbol(const std::string &name) const
Find symbol by name.
std::vector< Symbol > FindSymbolsMatching(const std::string &pattern) const
Find symbols matching a pattern (supports wildcards)
emu::input::SnesButton ToSnesButton(Button button)
emu::BreakpointManager::CpuType ToCpuType(CpuType proto_cpu)
CpuType ToProtoCpuType(emu::BreakpointManager::CpuType cpu)
BreakpointType ToProtoBreakpointType(emu::BreakpointManager::Type type)
emu::BreakpointManager::Type ToBreakpointType(BreakpointType proto_type)
SymbolFormat
Supported symbol file formats.