mirror of
https://github.com/kichikuou/system3-sdl2.git
synced 2026-09-22 22:58:12 +03:00
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:
+68
-10
@@ -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
@@ -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_
|
||||
|
||||
Reference in New Issue
Block a user