yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
emulator_service_impl.cc
Go to the documentation of this file.
2#include "app/emu/emulator.h"
4#include "app/emu/input/input_backend.h" // Required for SnesButton enum
8#include "absl/strings/escaping.h"
9#include "absl/strings/str_format.h"
10#include <fstream>
11#include <thread>
12
13namespace yaze::agent {
14
15namespace {
16// Helper to convert our gRPC Button enum to the emulator's SnesButton enum
19 switch (button) {
20 case A: return SnesButton::A;
21 case B: return SnesButton::B;
22 case X: return SnesButton::X;
23 case Y: return SnesButton::Y;
24 case L: return SnesButton::L;
25 case R: return SnesButton::R;
26 case SELECT: return SnesButton::SELECT;
27 case START: return SnesButton::START;
28 case UP: return SnesButton::UP;
29 case DOWN: return SnesButton::DOWN;
30 case LEFT: return SnesButton::LEFT;
31 case RIGHT: return SnesButton::RIGHT;
32 default:
33 return SnesButton::B; // Default fallback
34 }
35}
36} // namespace
37
40
41// --- Lifecycle ---
42
43grpc::Status EmulatorServiceImpl::Start(grpc::ServerContext* context, const Empty* request, CommandResponse* response) {
44 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
46 response->set_success(true);
47 response->set_message("Emulator started.");
48 return grpc::Status::OK;
49}
50
51grpc::Status EmulatorServiceImpl::Stop(grpc::ServerContext* context, const Empty* request, CommandResponse* response) {
52 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
53 emulator_->set_running(false);
54 response->set_success(true);
55 response->set_message("Emulator stopped.");
56 return grpc::Status::OK;
57}
58
59grpc::Status EmulatorServiceImpl::Pause(grpc::ServerContext* context, const Empty* request, CommandResponse* response) {
60 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
61 emulator_->set_running(false);
62 response->set_success(true);
63 response->set_message("Emulator paused.");
64 return grpc::Status::OK;
65}
66
67grpc::Status EmulatorServiceImpl::Resume(grpc::ServerContext* context, const Empty* request, CommandResponse* response) {
68 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
70 response->set_success(true);
71 response->set_message("Emulator resumed.");
72 return grpc::Status::OK;
73}
74
75grpc::Status EmulatorServiceImpl::Reset(grpc::ServerContext* context, const Empty* request, CommandResponse* response) {
76 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
77 emulator_->snes().Reset(true); // Hard reset
78 response->set_success(true);
79 response->set_message("Emulator reset.");
80 return grpc::Status::OK;
81}
82
83// --- Input Control ---
84
85grpc::Status EmulatorServiceImpl::PressButtons(grpc::ServerContext* context, const ButtonRequest* request, CommandResponse* response) {
86 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
87 auto& input_manager = emulator_->input_manager();
88 for (int i = 0; i < request->buttons_size(); i++) {
89 input_manager.PressButton(ToSnesButton(static_cast<Button>(request->buttons(i))));
90 }
91 std::this_thread::sleep_for(std::chrono::milliseconds(50));
92 for (int i = 0; i < request->buttons_size(); i++) {
93 input_manager.ReleaseButton(ToSnesButton(static_cast<Button>(request->buttons(i))));
94 }
95 response->set_success(true);
96 return grpc::Status::OK;
97}
98
99grpc::Status EmulatorServiceImpl::ReleaseButtons(grpc::ServerContext* context, const ButtonRequest* request, CommandResponse* response) {
100 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
101 auto& input_manager = emulator_->input_manager();
102 for (int i = 0; i < request->buttons_size(); i++) {
103 input_manager.ReleaseButton(ToSnesButton(static_cast<Button>(request->buttons(i))));
104 }
105 response->set_success(true);
106 return grpc::Status::OK;
107}
108
109grpc::Status EmulatorServiceImpl::HoldButtons(grpc::ServerContext* context, const ButtonHoldRequest* request, CommandResponse* response) {
110 if (!emulator_) return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
111 auto& input_manager = emulator_->input_manager();
112 for (int i = 0; i < request->buttons_size(); i++) {
113 input_manager.PressButton(ToSnesButton(static_cast<Button>(request->buttons(i))));
114 }
115 std::this_thread::sleep_for(std::chrono::milliseconds(request->duration_ms()));
116 for (int i = 0; i < request->buttons_size(); i++) {
117 input_manager.ReleaseButton(ToSnesButton(static_cast<Button>(request->buttons(i))));
118 }
119 response->set_success(true);
120 return grpc::Status::OK;
121}
122
123// --- State Inspection ---
124
125grpc::Status EmulatorServiceImpl::GetGameState(grpc::ServerContext* context, const GameStateRequest* request, GameStateResponse* response) {
127 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "SNES is not initialized.");
128 }
129 auto& memory = emulator_->snes().memory();
130
131 response->set_game_mode(memory.ReadByte(0x7E0010));
132 response->set_link_state(memory.ReadByte(0x7E005D));
133 response->set_link_pos_x(memory.ReadWord(0x7E0020));
134 response->set_link_pos_y(memory.ReadWord(0x7E0022));
135 response->set_link_health(memory.ReadByte(0x7EF36D));
136
137 for (const auto& mem_req : request->memory_reads()) {
138 auto* mem_resp = response->add_memory_responses();
139 mem_resp->set_address(mem_req.address());
140 std::vector<uint8_t> data(mem_req.size());
141 for (uint32_t i = 0; i < mem_req.size(); ++i) {
142 data[i] = memory.ReadByte(mem_req.address() + i);
143 }
144 mem_resp->set_data(data.data(), data.size());
145 }
146
147#ifdef YAZE_WITH_GRPC
148 if (request->include_screenshot()) {
149 auto screenshot = yaze::test::CaptureHarnessScreenshot();
150 if (screenshot.ok()) {
151 // Read the screenshot file and convert to PNG data
152 std::ifstream file(screenshot->file_path, std::ios::binary);
153 if (file.good()) {
154 std::string png_data((std::istreambuf_iterator<char>(file)),
155 std::istreambuf_iterator<char>());
156 response->set_screenshot_png(png_data);
157 }
158 }
159 }
160#endif
161
162 return grpc::Status::OK;
163}
164
165grpc::Status EmulatorServiceImpl::ReadMemory(grpc::ServerContext* context, const MemoryRequest* request, MemoryResponse* response) {
167 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "SNES is not initialized.");
168 }
169 auto& memory = emulator_->snes().memory();
170 response->set_address(request->address());
171 std::vector<uint8_t> data(request->size());
172 for (uint32_t i = 0; i < request->size(); ++i) {
173 data[i] = memory.ReadByte(request->address() + i);
174 }
175 response->set_data(data.data(), data.size());
176 return grpc::Status::OK;
177}
178
179grpc::Status EmulatorServiceImpl::WriteMemory(grpc::ServerContext* context, const MemoryWriteRequest* request, CommandResponse* response) {
181 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "SNES is not initialized.");
182 }
183 auto& memory = emulator_->snes().memory();
184 const std::string& data = request->data();
185 for (uint32_t i = 0; i < data.size(); ++i) {
186 memory.WriteByte(request->address() + i, static_cast<uint8_t>(data[i]));
187 }
188 response->set_success(true);
189 response->set_message(absl::StrFormat("Wrote %d bytes to 0x%X.", data.size(), request->address()));
190 return grpc::Status::OK;
191}
192
193// --- Advanced Debugging ---
194
195// Helper to convert proto breakpoint type to manager type
198 switch (proto_type) {
199 case EXECUTE: return BreakpointManager::Type::EXECUTE;
200 case READ: return BreakpointManager::Type::READ;
201 case WRITE: return BreakpointManager::Type::WRITE;
202 case ACCESS: return BreakpointManager::Type::ACCESS;
203 case CONDITIONAL: return BreakpointManager::Type::CONDITIONAL;
204 default: return BreakpointManager::Type::EXECUTE;
205 }
206}
207
208// Helper to convert proto CPU type to manager CPU type
211 switch (proto_cpu) {
212 case CPU_65816: return BreakpointManager::CpuType::CPU_65816;
213 case SPC700: return BreakpointManager::CpuType::SPC700;
214 default: return BreakpointManager::CpuType::CPU_65816;
215 }
216}
217
218// Helper to convert manager type back to proto
221 switch (type) {
222 case BreakpointManager::Type::EXECUTE: return EXECUTE;
223 case BreakpointManager::Type::READ: return READ;
224 case BreakpointManager::Type::WRITE: return WRITE;
225 case BreakpointManager::Type::ACCESS: return ACCESS;
226 case BreakpointManager::Type::CONDITIONAL: return CONDITIONAL;
227 default: return EXECUTE;
228 }
229}
230
231// Helper to convert manager CPU type back to proto
234 switch (cpu) {
235 case BreakpointManager::CpuType::CPU_65816: return CPU_65816;
236 case BreakpointManager::CpuType::SPC700: return SPC700;
237 default: return CPU_65816;
238 }
239}
240
241grpc::Status EmulatorServiceImpl::AddBreakpoint(grpc::ServerContext* context,
242 const BreakpointRequest* request,
243 BreakpointResponse* response) {
244 if (!emulator_) {
245 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
246 }
247
248 auto& bp_manager = emulator_->breakpoint_manager();
249 uint32_t id = bp_manager.AddBreakpoint(
250 request->address(),
251 ToBreakpointType(request->type()),
252 ToCpuType(request->cpu()),
253 request->condition(),
254 request->description()
255 );
256
257 response->set_success(true);
258 response->set_breakpoint_id(id);
259 response->set_message(absl::StrFormat("Breakpoint %d added at 0x%06X", id, request->address()));
260 return grpc::Status::OK;
261}
262
263grpc::Status EmulatorServiceImpl::RemoveBreakpoint(grpc::ServerContext* context,
264 const BreakpointIdRequest* request,
265 CommandResponse* response) {
266 if (!emulator_) {
267 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
268 }
269
270 emulator_->breakpoint_manager().RemoveBreakpoint(request->breakpoint_id());
271 response->set_success(true);
272 response->set_message(absl::StrFormat("Breakpoint %d removed", request->breakpoint_id()));
273 return grpc::Status::OK;
274}
275
276grpc::Status EmulatorServiceImpl::ListBreakpoints(grpc::ServerContext* context,
277 const Empty* request,
278 BreakpointListResponse* response) {
279 if (!emulator_) {
280 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
281 }
282
283 auto breakpoints = emulator_->breakpoint_manager().GetAllBreakpoints();
284 for (const auto& bp : breakpoints) {
285 auto* info = response->add_breakpoints();
286 info->set_id(bp.id);
287 info->set_address(bp.address);
288 info->set_type(ToProtoBreakpointType(bp.type));
289 info->set_cpu(ToProtoCpuType(bp.cpu));
290 info->set_enabled(bp.enabled);
291 info->set_condition(bp.condition);
292 info->set_description(bp.description);
293 info->set_hit_count(bp.hit_count);
294 }
295
296 return grpc::Status::OK;
297}
298
299grpc::Status EmulatorServiceImpl::SetBreakpointEnabled(grpc::ServerContext* context,
300 const BreakpointStateRequest* request,
301 CommandResponse* response) {
302 if (!emulator_) {
303 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
304 }
305
306 emulator_->breakpoint_manager().SetEnabled(request->breakpoint_id(), request->enabled());
307 response->set_success(true);
308 response->set_message(absl::StrFormat("Breakpoint %d %s",
309 request->breakpoint_id(),
310 request->enabled() ? "enabled" : "disabled"));
311 return grpc::Status::OK;
312}
313
314// Watchpoints - Note: Emulator needs WatchpointManager integration first
315grpc::Status EmulatorServiceImpl::AddWatchpoint(grpc::ServerContext* context,
316 const WatchpointRequest* request,
317 WatchpointResponse* response) {
318 // TODO: Integrate WatchpointManager into Emulator class
319 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
320 "Watchpoints require WatchpointManager integration");
321}
322
323grpc::Status EmulatorServiceImpl::RemoveWatchpoint(grpc::ServerContext* context,
324 const WatchpointIdRequest* request,
325 CommandResponse* response) {
326 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
327 "Watchpoints require WatchpointManager integration");
328}
329
330grpc::Status EmulatorServiceImpl::ListWatchpoints(grpc::ServerContext* context,
331 const Empty* request,
332 WatchpointListResponse* response) {
333 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
334 "Watchpoints require WatchpointManager integration");
335}
336
337grpc::Status EmulatorServiceImpl::GetWatchpointHistory(grpc::ServerContext* context,
338 const WatchpointHistoryRequest* request,
339 WatchpointHistoryResponse* response) {
340 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
341 "Watchpoints require WatchpointManager integration");
342}
343
344// Execution Control
345grpc::Status EmulatorServiceImpl::StepInstruction(grpc::ServerContext* context,
346 const Empty* request,
347 StepResponse* response) {
349 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "SNES is not initialized.");
350 }
351
352 // Capture state before step
353 auto& cpu = emulator_->snes().cpu();
354 uint32_t pc_before = (cpu.PB << 16) | cpu.PC;
355
356 // Execute one instruction
358
359 // Fill response with new CPU state
360 auto* cpu_state = response->mutable_cpu_state();
361 cpu_state->set_a(cpu.A);
362 cpu_state->set_x(cpu.X);
363 cpu_state->set_y(cpu.Y);
364 cpu_state->set_sp(cpu.SP());
365 cpu_state->set_pc(cpu.PC);
366 cpu_state->set_db(cpu.DB);
367 cpu_state->set_pb(cpu.PB);
368 cpu_state->set_d(cpu.D);
369 cpu_state->set_status(cpu.status);
370 cpu_state->set_flag_n(cpu.GetNegativeFlag());
371 cpu_state->set_flag_v(cpu.GetOverflowFlag());
372 cpu_state->set_flag_d(cpu.GetDecimalFlag());
373 cpu_state->set_flag_i(cpu.GetInterruptFlag());
374 cpu_state->set_flag_z(cpu.GetZeroFlag());
375 cpu_state->set_flag_c(cpu.GetCarryFlag());
376 cpu_state->set_cycles(emulator_->GetCurrentCycle());
377
378 response->set_success(true);
379 response->set_message(absl::StrFormat("Stepped from 0x%06X to 0x%06X",
380 pc_before,
381 (cpu.PB << 16) | cpu.PC));
382 return grpc::Status::OK;
383}
384
385grpc::Status EmulatorServiceImpl::RunToBreakpoint(grpc::ServerContext* context,
386 const Empty* request,
387 BreakpointHitResponse* response) {
389 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "SNES is not initialized.");
390 }
391
392 // Run emulator until breakpoint is hit (max 1 million instructions to prevent hangs)
393 const int kMaxInstructions = 1000000;
394 int instruction_count = 0;
395
396 auto& bp_manager = emulator_->breakpoint_manager();
397 auto& cpu = emulator_->snes().cpu();
398
399 while (instruction_count++ < kMaxInstructions) {
400 uint32_t pc = (cpu.PB << 16) | cpu.PC;
401
402 // Check for execute breakpoint
403 if (bp_manager.ShouldBreakOnExecute(pc, emu::BreakpointManager::CpuType::CPU_65816)) {
404 response->set_hit(true);
405 response->set_message(absl::StrFormat("Breakpoint hit at 0x%06X after %d instructions", pc, instruction_count));
406
407 // Fill breakpoint info
408 auto* last_hit = bp_manager.GetLastHit();
409 if (last_hit) {
410 auto* bp_info = response->mutable_breakpoint();
411 bp_info->set_id(last_hit->id);
412 bp_info->set_address(last_hit->address);
413 bp_info->set_type(ToProtoBreakpointType(last_hit->type));
414 bp_info->set_cpu(ToProtoCpuType(last_hit->cpu));
415 bp_info->set_enabled(last_hit->enabled);
416 bp_info->set_condition(last_hit->condition);
417 bp_info->set_description(last_hit->description);
418 bp_info->set_hit_count(last_hit->hit_count);
419 }
420
421 // Fill CPU state
422 auto* cpu_state = response->mutable_cpu_state();
423 cpu_state->set_pc(cpu.PC);
424 cpu_state->set_pb(cpu.PB);
425 cpu_state->set_a(cpu.A);
426 cpu_state->set_x(cpu.X);
427 cpu_state->set_y(cpu.Y);
428 cpu_state->set_sp(cpu.SP());
429 cpu_state->set_db(cpu.DB);
430 cpu_state->set_d(cpu.D);
431
432 return grpc::Status::OK;
433 }
434
435 // Execute instruction
437 }
438
439 // No breakpoint hit
440 response->set_hit(false);
441 response->set_message(absl::StrFormat("No breakpoint hit after %d instructions (timeout)", kMaxInstructions));
442 return grpc::Status::OK;
443}
444
445grpc::Status EmulatorServiceImpl::StepOver(grpc::ServerContext* context,
446 const Empty* request,
447 StepResponse* response) {
448 // TODO: Implement step-over (step, but skip over JSR/JSL calls)
449 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
450 "StepOver not yet implemented");
451}
452
453grpc::Status EmulatorServiceImpl::StepOut(grpc::ServerContext* context,
454 const Empty* request,
455 StepResponse* response) {
456 // TODO: Implement step-out (run until RTS/RTL)
457 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
458 "StepOut not yet implemented");
459}
460
461// Disassembly
462grpc::Status EmulatorServiceImpl::GetDisassembly(grpc::ServerContext* context,
463 const DisassemblyRequest* request,
464 DisassemblyResponse* response) {
466 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "SNES is not initialized.");
467 }
468
469 // Option 1: Use DisassemblyViewer to get recorded instructions
470 // Option 2: Disassemble directly from memory at start_address
471
472 // For now, disassemble directly from SNES memory
473 // TODO: Enhance DisassemblyViewer with GetInstructionsInRange() method
474 auto& cpu = emulator_->snes().cpu();
475 auto& memory = emulator_->snes().memory();
476
477 uint32_t current_address = request->start_address();
478 uint32_t instructions_added = 0;
479
480 while (instructions_added < request->count() && instructions_added < 1000) {
481 uint8_t bank = (current_address >> 16) & 0xFF;
482 uint16_t offset = current_address & 0xFFFF;
483
484 // Read opcode and disassemble
485 uint8_t opcode = memory.ReadByte(current_address);
486
487 // Basic disassembly (simplified - real implementation would use CPU's disassembler)
488 auto* line = response->add_lines();
489 line->set_address(current_address);
490 line->set_opcode(opcode);
491
492 // TODO: Use proper 65816 disassembler to get instruction details
493 // For now, just provide basic info
494 line->set_mnemonic(absl::StrFormat("OPCODE_%02X", opcode));
495 line->set_size(1); // Simplified - actual size varies
496 line->set_execution_count(0); // Would need to query DisassemblyViewer
497 line->set_is_breakpoint(false); // Would need to query BreakpointManager
498
499 current_address++;
500 instructions_added++;
501 }
502
503 return grpc::Status::OK;
504}
505
506grpc::Status EmulatorServiceImpl::GetExecutionTrace(grpc::ServerContext* context,
507 const TraceRequest* request,
508 TraceResponse* response) {
509 // TODO: Implement execution trace (requires trace buffer in CPU)
510 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
511 "Execution trace not yet implemented");
512}
513
514// Symbol Management
515grpc::Status EmulatorServiceImpl::LoadSymbols(grpc::ServerContext* context,
516 const SymbolFileRequest* request,
517 CommandResponse* response) {
518 // TODO: Implement symbol file loading
519 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
520 "Symbol loading not yet implemented");
521}
522
523grpc::Status EmulatorServiceImpl::ResolveSymbol(grpc::ServerContext* context,
524 const SymbolLookupRequest* request,
525 SymbolLookupResponse* response) {
526 // TODO: Implement symbol resolution
527 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
528 "Symbol resolution not yet implemented");
529}
530
531grpc::Status EmulatorServiceImpl::GetSymbolAt(grpc::ServerContext* context,
532 const AddressRequest* request,
533 SymbolLookupResponse* response) {
534 // TODO: Implement reverse symbol lookup
535 return grpc::Status(grpc::StatusCode::UNIMPLEMENTED,
536 "Reverse symbol lookup not yet implemented");
537}
538
539// Debug Session
540grpc::Status EmulatorServiceImpl::CreateDebugSession(grpc::ServerContext* context,
541 const DebugSessionRequest* request,
542 DebugSessionResponse* response) {
543 if (!emulator_) {
544 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
545 }
546
547 // Enable debugging mode
549
550 response->set_success(true);
551 response->set_session_id(request->session_name());
552 response->set_message(absl::StrFormat("Debug session '%s' created", request->session_name()));
553 return grpc::Status::OK;
554}
555
556grpc::Status EmulatorServiceImpl::GetDebugStatus(grpc::ServerContext* context,
557 const Empty* request,
558 DebugStatusResponse* response) {
559 if (!emulator_) {
560 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "Emulator not initialized.");
561 }
562
563 response->set_is_running(emulator_->running());
564 response->set_is_paused(!emulator_->running());
565 response->set_fps(emulator_->GetCurrentFPS());
566 response->set_cycles(emulator_->GetCurrentCycle());
567
568 // Get active counts
569 auto breakpoints = emulator_->breakpoint_manager().GetAllBreakpoints();
570 uint32_t active_bp_count = 0;
571 for (const auto& bp : breakpoints) {
572 if (bp.enabled) active_bp_count++;
573 }
574 response->set_active_breakpoints(active_bp_count);
575 response->set_active_watchpoints(0); // TODO: When WatchpointManager is integrated
576
577 // Fill CPU state
578 auto& cpu = emulator_->snes().cpu();
579 auto* cpu_state = response->mutable_cpu_state();
580 cpu_state->set_a(cpu.A);
581 cpu_state->set_x(cpu.X);
582 cpu_state->set_y(cpu.Y);
583 cpu_state->set_sp(cpu.SP());
584 cpu_state->set_pc(cpu.PC);
585 cpu_state->set_db(cpu.DB);
586 cpu_state->set_pb(cpu.PB);
587 cpu_state->set_d(cpu.D);
588 cpu_state->set_status(cpu.status);
589 cpu_state->set_flag_n(cpu.GetNegativeFlag());
590 cpu_state->set_flag_v(cpu.GetOverflowFlag());
591 cpu_state->set_flag_d(cpu.GetDecimalFlag());
592 cpu_state->set_flag_i(cpu.GetInterruptFlag());
593 cpu_state->set_flag_z(cpu.GetZeroFlag());
594 cpu_state->set_flag_c(cpu.GetCarryFlag());
595 cpu_state->set_cycles(emulator_->GetCurrentCycle());
596
597 // Last breakpoint hit
598 auto* last_hit = emulator_->breakpoint_manager().GetLastHit();
599 if (last_hit) {
600 auto* bp_info = response->mutable_last_breakpoint_hit();
601 bp_info->set_id(last_hit->id);
602 bp_info->set_address(last_hit->address);
603 bp_info->set_type(ToProtoBreakpointType(last_hit->type));
604 bp_info->set_cpu(ToProtoCpuType(last_hit->cpu));
605 bp_info->set_enabled(last_hit->enabled);
606 bp_info->set_hit_count(last_hit->hit_count);
607 }
608
609 return grpc::Status::OK;
610}
611
612} // namespace yaze::agent
grpc::Status RemoveBreakpoint(grpc::ServerContext *context, const BreakpointIdRequest *request, CommandResponse *response) override
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
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
grpc::Status GetGameState(grpc::ServerContext *context, const GameStateRequest *request, GameStateResponse *response) override
grpc::Status AddWatchpoint(grpc::ServerContext *context, const WatchpointRequest *request, WatchpointResponse *response) override
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.
Definition emulator.h:36
BreakpointManager & breakpoint_manager()
Definition emulator.h:71
double GetCurrentFPS() const
Definition emulator.h:81
void set_debugging(bool debugging)
Definition emulator.h:75
uint64_t GetCurrentCycle()
Definition emulator.h:82
void StepSingleInstruction()
Definition emulator.h:85
input::InputManager & input_manager()
Definition emulator.h:73
void set_running(bool running)
Definition emulator.h:49
bool is_snes_initialized() const
Definition emulator.h:77
auto snes() -> Snes &
Definition emulator.h:47
auto running() const -> bool
Definition emulator.h:48
void PressButton(SnesButton button)
void ReleaseButton(SnesButton 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)
SnesButton
SNES controller button mapping (platform-agnostic)