diff options
author | Oxore <oxore@protonmail.com> | 2022-09-23 10:00:55 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2022-09-25 15:06:52 +0300 |
commit | 2e363155df0380bed5210e41d395015320a9bb74 (patch) | |
tree | da88603bdb250e40aa4c6853d6c37325a2d04aa4 | |
parent | 2233177e7ada45838dc61d1a5f98ff44f7fbc3a6 (diff) |
Impl monitor reset and reset halt commands
-rw-r--r-- | emulator.cpp | 24 | ||||
-rw-r--r-- | gdbremote_parser.cpp | 28 | ||||
-rw-r--r-- | gdbremote_parser.hpp | 9 |
3 files changed, 60 insertions, 1 deletions
diff --git a/emulator.cpp b/emulator.cpp index 051c6db..5dd266a 100644 --- a/emulator.cpp +++ b/emulator.cpp @@ -95,11 +95,20 @@ static int setup_socket(uint16_t port) return socket_fd; } +static inline bool IsReset(const std::string& command) +{ + if (command == "reset") return true; + if (command == "reset halt") return true; + if (command == "system_reset") return true; + return false; +} + static std::string CreateResponse( M68KDebuggingControl& m68k_debug, const GDBRemote::Packet& packet) { using namespace GDBRemote; + // TODO use switch-case if (0) { } else if (packet.type == PacketType::kQueryHaltReason) { return "S05"; // TODO real reason @@ -116,6 +125,20 @@ static std::string CreateResponse( return "OK"; } else if (packet.type == PacketType::kQueryAttached) { return "1"; + } else if (packet.type == PacketType::kQueryRcmd) { + const auto * const packet_data = + static_cast<const PacketDataRcmd*>(packet.data.get()); + if (IsReset(packet_data->data)) { + m68k_pulse_reset(); + // I don't want to skip reset cycles here, because GDB does not + // re-read registers every time, and if we skip reset cycles here, + // the consequent "stepi" in gdb will end up on second instruction + // of reset handler. If we don't skip reset cycles, the first + // "stepi" after "monitor reset" will land us on the first + // instruction in reset handler - I'd prefer this exact behavior for + // now. + return "OK"; + } } else if (packet.type == PacketType::kInterrupt) { return "OK"; } else if (packet.type == PacketType::kSetBreakpoint) { @@ -356,6 +379,7 @@ int main(int argc, char* argv[]) m68k_init(); m68k_set_cpu_type(M68K_CPU_TYPE_68000); m68k_pulse_reset(); + m68k_execute(1); // Skip reset cycles emulator(g_m68k_debug); while (0) diff --git a/gdbremote_parser.cpp b/gdbremote_parser.cpp index b9115be..98533c5 100644 --- a/gdbremote_parser.cpp +++ b/gdbremote_parser.cpp @@ -79,6 +79,15 @@ struct Token { } }; +static std::string DecodeBinaryHex(const std::string& data_hex) +{ + std::string data(data_hex.size()/2, '\0'); + for (size_t i = 0; i < data.size(); i++) { + data[i] = Utils::ParseByteFromHexChars(data_hex[i * 2], data_hex[i * 2 + 1]); + } + return data; +} + struct Command { std::string name; Packet (*parse)(const std::vector<Token>&&); @@ -122,6 +131,22 @@ struct Command { { return Packet{PacketType::kQueryTraceStatus}; } + static Packet parseQueryRcmd(const std::vector<Token>&& tokens) + { + if (tokens.size() < 3) + return Packet::None(); + if (tokens[1].type != TokenType::kSeparatorComma) + return Packet::None(); + if (tokens[2].type != TokenType::kHexNumeric) + return Packet::None(); + const std::string& data_encoded = tokens[2].data; + const std::string data = DecodeBinaryHex(data_encoded); + printf("%s\n", data.c_str()); + return Packet{ + PacketType::kQueryRcmd, + std::make_unique<const PacketDataRcmd>(std::move(data)), + }; + } static Packet parseSetThreadForCont(const std::vector<Token>&&) { // TODO arguments @@ -146,7 +171,7 @@ struct Command { } static Packet parseContinueVCont(const std::vector<Token>&& tokens) { - const std::string first_arg = tokens[1].data; + const std::string first_arg = tokens.size() > 1 ? tokens[1].data : ""; // Check if it is "vCont?" command if (first_arg == "?") { return Packet{PacketType::kContinueAskSupported}; @@ -260,6 +285,7 @@ static const Command commands[] = { { "qL", Command::parseQueryRTOSThreadInfo }, { "qAttached", Command::parseQueryAttached }, { "qTStatus", Command::parseQueryTraceStatus }, + { "qRcmd", Command::parseQueryRcmd }, { "Hc", Command::parseSetThreadForCont }, { "Hg", Command::parseSetThreadForOps }, { "vMustReplyEmpty", Command::parseMustReplyEmpty }, diff --git a/gdbremote_parser.hpp b/gdbremote_parser.hpp index 370e8cc..a6d76fc 100644 --- a/gdbremote_parser.hpp +++ b/gdbremote_parser.hpp @@ -51,6 +51,7 @@ enum class PacketType: int { kQueryRTOSThreadInfo, kQueryAttached, kQueryTraceStatus, + kQueryRcmd, kSetThreadForCont, kSetThreadForOps, kVMustReplyEmpty, @@ -94,6 +95,12 @@ struct PacketDataWriteMemory: public PacketData { virtual ~PacketDataWriteMemory() {} }; +struct PacketDataRcmd: public PacketData { + PacketDataRcmd(const std::string&& a_data): data(std::move(a_data)) {} + std::string data{}; + virtual ~PacketDataRcmd() {} +}; + enum class BreakpointType: uint32_t { kMin = 0, kSoftwareBreakpoint = 0, @@ -146,6 +153,8 @@ struct Packet { return "qAttached"; case PacketType::kQueryTraceStatus: return "qTStatus"; + case PacketType::kQueryRcmd: + return "qRcmd"; case PacketType::kSetThreadForCont: return "Hc"; case PacketType::kSetThreadForOps: |