Scenario: Label / page calls share a single call stack

This allows the debugger to present a linear backtrace.
It's still possible to return from the other call type.
This commit is contained in:
kichikuou
2024-12-27 16:08:58 +09:00
parent a13719d84c
commit d6e3cb8415
2 changed files with 86 additions and 18 deletions
+68 -10
View File
@@ -1,4 +1,5 @@
#include "scenario.h"
#include <algorithm>
#include <string.h>
#include "common.h"
#include "encoding.h"
@@ -44,35 +45,92 @@ void Scenario::get_syseng_string(char* buf, int size, Encoding *enc, uint8_t ter
void Scenario::label_call(int label)
{
if (label == 0) {
if (label_stack.empty()) {
// Return
auto it = std::find_if(call_stack.rbegin(), call_stack.rend(),
[](const StackFrame& frame) { return !frame.is_page_call; });
if (it == call_stack.rend()) {
WARNING("Label stack underflow");
return;
}
jump_to(label_stack.back());
label_stack.pop_back();
if (it != call_stack.rbegin()) {
WARNING("Return from non-top label call");
}
if (it->page != page_) {
sys_error("Illegal label return at %d:%04x", page_, cmd_addr_);
}
jump_to(it->addr);
call_stack.erase(std::next(it).base());
} else {
label_stack.push_back(addr_);
call_stack.emplace_back(false, page_, addr_);
jump_to(label);
}
}
size_t Scenario::label_stack_size() const
{
return std::count_if(call_stack.begin(), call_stack.end(),
[](const StackFrame& frame) { return !frame.is_page_call; });
}
void Scenario::label_stack_pop()
{
auto it = std::find_if(call_stack.rbegin(), call_stack.rend(),
[](const StackFrame& frame) { return !frame.is_page_call; });
if (it == call_stack.rend())
return;
call_stack.erase(std::next(it).base());
}
void Scenario::label_stack_clear()
{
call_stack.erase(std::remove_if(call_stack.begin(), call_stack.end(),
[](const StackFrame& frame) { return !frame.is_page_call; }), call_stack.end());
}
void Scenario::page_call(int target_page)
{
if (target_page == 0) {
if (page_stack.empty()) {
// Return
auto it = std::find_if(call_stack.rbegin(), call_stack.rend(),
[](const StackFrame& frame) { return frame.is_page_call; });
if (it == call_stack.rend()) {
WARNING("Page stack underflow");
return;
}
auto& pair = page_stack.back();
page_jump(pair.first, pair.second);
page_stack.pop_back();
if (it != call_stack.rbegin()) {
WARNING("Return from non-top page call");
}
page_jump(it->page, it->addr);
call_stack.erase(std::next(it).base());
} else {
page_stack.emplace_back(page_, addr_);
call_stack.emplace_back(true, page_, addr_);
page_jump(target_page, 2);
}
}
[[noreturn]] void Scenario::unknown_command(uint8_t cmd) {
size_t Scenario::page_stack_size() const
{
return std::count_if(call_stack.begin(), call_stack.end(),
[](const StackFrame& frame) { return frame.is_page_call; });
}
void Scenario::page_stack_pop()
{
auto it = std::find_if(call_stack.rbegin(), call_stack.rend(),
[](const StackFrame& frame) { return frame.is_page_call; });
if (it == call_stack.rend())
return;
call_stack.erase(std::next(it).base());
}
void Scenario::page_stack_clear()
{
call_stack.erase(std::remove_if(call_stack.begin(), call_stack.end(),
[](const StackFrame& frame) { return frame.is_page_call; }), call_stack.end());
}
[[noreturn]] void Scenario::unknown_command(uint8_t cmd)
{
if (cmd >= 0x20 && cmd < 0x7f) {
sys_error("Unknown Command: '%c' at %d:%04x", cmd, page_, cmd_addr_);
} else {
+18 -8
View File
@@ -40,25 +40,35 @@ public:
void get_syseng_string(char* buf, int size, Encoding *enc, uint8_t terminator);
void label_call(int label);
size_t label_stack_size() const { return label_stack.size(); }
void label_stack_pop() { label_stack.pop_back(); }
void label_stack_clear() { label_stack.clear(); }
size_t label_stack_size() const;
void label_stack_pop();
void label_stack_clear();
void page_call(int page);
size_t page_stack_size() const { return page_stack.size(); }
void page_stack_pop() { page_stack.pop_back(); }
void page_stack_clear() { page_stack.clear(); }
size_t page_stack_size() const;
void page_stack_pop();
void page_stack_clear();
[[noreturn]] void unknown_command(uint8_t cmd);
struct StackFrame {
bool is_page_call;
uint8_t page;
uint16_t addr;
StackFrame(bool is_page_call, uint8_t page, uint16_t addr)
: is_page_call(is_page_call), page(page), addr(addr) {}
};
const std::vector<StackFrame>& get_call_stack() const { return call_stack; }
int write_instruction(int page, int addr, uint8_t op);
private:
Dri adisk;
std::vector<uint8_t> data_;
int page_;
int addr_;
int cmd_addr_;
std::vector<int> label_stack;
std::vector<std::pair<int, int>> page_stack;
std::vector<StackFrame> call_stack;
};
#endif // _SCENARIO_H_