yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
step_controller.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EMU_DEBUG_STEP_CONTROLLER_H_
2#define YAZE_APP_EMU_DEBUG_STEP_CONTROLLER_H_
3
4#include <cstdint>
5#include <functional>
6#include <optional>
7#include <stack>
8#include <string>
9#include <vector>
10
11namespace yaze {
12namespace emu {
13namespace debug {
14
28 uint32_t call_address; // Address where the call was made
29 uint32_t target_address; // Target of the call (subroutine start)
30 uint32_t return_address; // Expected return address
31 bool is_long; // True for JSL, false for JSR
32 std::string symbol; // Symbol name at target (if available)
33
34 CallStackEntry(uint32_t call, uint32_t target, uint32_t ret, bool long_call)
35 : call_address(call),
36 target_address(target),
37 return_address(ret),
38 is_long(long_call) {}
39};
40
44struct StepResult {
45 bool success;
46 uint32_t new_pc; // New program counter
47 uint32_t instructions_executed; // Number of instructions stepped
48 std::string message;
49 std::optional<CallStackEntry> call; // If a call was made
50 std::optional<CallStackEntry> ret; // If a return was made
51};
52
71 public:
72 using MemoryReader = std::function<uint8_t(uint32_t)>;
73 using SingleStepper = std::function<void()>;
74 using PcGetter = std::function<uint32_t()>;
75
76 StepController() = default;
77
78 void SetMemoryReader(MemoryReader reader) { read_byte_ = reader; }
79 void SetSingleStepper(SingleStepper stepper) { step_ = stepper; }
80 void SetPcGetter(PcGetter getter) { get_pc_ = getter; }
81
87
97 StepResult StepOver(uint32_t max_instructions = 1000000);
98
107 StepResult StepOut(uint32_t max_instructions = 1000000);
108
112 const std::vector<CallStackEntry>& GetCallStack() const {
113 return call_stack_;
114 }
115
119 size_t GetCallDepth() const { return call_stack_.size(); }
120
124 void ClearCallStack() { call_stack_.clear(); }
125
129 static bool IsCallInstruction(uint8_t opcode);
130
134 static bool IsReturnInstruction(uint8_t opcode);
135
139 static bool IsBranchInstruction(uint8_t opcode);
140
144 static uint8_t GetInstructionSize(uint8_t opcode, bool m_flag, bool x_flag);
145
146 private:
147 // Process instruction and update call stack
148 void ProcessInstruction(uint32_t pc);
149
150 // Calculate return address for call
151 uint32_t CalculateReturnAddress(uint32_t pc, uint8_t opcode) const;
152
153 // Calculate target address for call
154 uint32_t CalculateCallTarget(uint32_t pc, uint8_t opcode) const;
155
159 std::vector<CallStackEntry> call_stack_;
160};
161
162// Static helper functions for opcode classification
163namespace opcode {
164
165// Call instructions
166constexpr uint8_t JSR = 0x20; // Jump to Subroutine (absolute)
167constexpr uint8_t JSL = 0x22; // Jump to Subroutine Long
168constexpr uint8_t JSR_X = 0xFC; // Jump to Subroutine (absolute,X)
169
170// Return instructions
171constexpr uint8_t RTS = 0x60; // Return from Subroutine
172constexpr uint8_t RTL = 0x6B; // Return from Subroutine Long
173constexpr uint8_t RTI = 0x40; // Return from Interrupt
174
175// Branch instructions (conditional)
176constexpr uint8_t BCC = 0x90; // Branch if Carry Clear
177constexpr uint8_t BCS = 0xB0; // Branch if Carry Set
178constexpr uint8_t BEQ = 0xF0; // Branch if Equal (Z=1)
179constexpr uint8_t BMI = 0x30; // Branch if Minus (N=1)
180constexpr uint8_t BNE = 0xD0; // Branch if Not Equal (Z=0)
181constexpr uint8_t BPL = 0x10; // Branch if Plus (N=0)
182constexpr uint8_t BVC = 0x50; // Branch if Overflow Clear
183constexpr uint8_t BVS = 0x70; // Branch if Overflow Set
184constexpr uint8_t BRA = 0x80; // Branch Always (relative)
185constexpr uint8_t BRL = 0x82; // Branch Long (relative long)
186
187// Jump instructions
188constexpr uint8_t JMP_ABS = 0x4C; // Jump Absolute
189constexpr uint8_t JMP_IND = 0x6C; // Jump Indirect
190constexpr uint8_t JMP_ABS_X = 0x7C; // Jump Absolute Indexed Indirect
191constexpr uint8_t JMP_LONG = 0x5C; // Jump Long
192constexpr uint8_t JMP_IND_L = 0xDC; // Jump Indirect Long
193
194} // namespace opcode
195
196} // namespace debug
197} // namespace emu
198} // namespace yaze
199
200#endif // YAZE_APP_EMU_DEBUG_STEP_CONTROLLER_H_
Controller for intelligent step operations.
StepResult StepInto()
Step a single instruction and update call stack.
uint32_t CalculateCallTarget(uint32_t pc, uint8_t opcode) const
uint32_t CalculateReturnAddress(uint32_t pc, uint8_t opcode) const
std::function< uint8_t(uint32_t)> MemoryReader
void SetMemoryReader(MemoryReader reader)
void SetPcGetter(PcGetter getter)
StepResult StepOver(uint32_t max_instructions=1000000)
Step over the current instruction.
std::function< void()> SingleStepper
static bool IsReturnInstruction(uint8_t opcode)
Check if an opcode is a return instruction (RTS/RTL/RTI)
static bool IsCallInstruction(uint8_t opcode)
Check if an opcode is a call instruction (JSR/JSL)
static bool IsBranchInstruction(uint8_t opcode)
Check if an opcode is a branch instruction.
void ClearCallStack()
Clear the call stack (e.g., on reset)
std::function< uint32_t()> PcGetter
size_t GetCallDepth() const
Get the current call depth.
static uint8_t GetInstructionSize(uint8_t opcode, bool m_flag, bool x_flag)
Get instruction size for step over calculations.
std::vector< CallStackEntry > call_stack_
const std::vector< CallStackEntry > & GetCallStack() const
Get the current call stack.
void SetSingleStepper(SingleStepper stepper)
StepResult StepOut(uint32_t max_instructions=1000000)
Step out of the current subroutine.
constexpr uint8_t JMP_IND
constexpr uint8_t JMP_LONG
constexpr uint8_t JMP_IND_L
constexpr uint8_t JMP_ABS
constexpr uint8_t JMP_ABS_X
Tracks call stack for intelligent stepping.
CallStackEntry(uint32_t call, uint32_t target, uint32_t ret, bool long_call)
Result of a step operation.
std::optional< CallStackEntry > call
std::optional< CallStackEntry > ret