summaryrefslogtreecommitdiff
path: root/emulator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'emulator.cpp')
-rw-r--r--emulator.cpp168
1 files changed, 166 insertions, 2 deletions
diff --git a/emulator.cpp b/emulator.cpp
index 0e3fb29..1605995 100644
--- a/emulator.cpp
+++ b/emulator.cpp
@@ -2,17 +2,124 @@
*/
#include "bus.hpp"
+#include "m68k_debugging.hpp"
+#include "gdbremote_parser.hpp"
#include "musashi-m68k/m68k.h"
+#include <cassert>
#include <cstdio>
+#include <cstdint>
#include <cstdlib>
+#include <cstring>
#include <cstdarg>
#include <ctime>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
#if !defined(DEBUG_TRACE_INSTRUCTIONS)
# define DEBUG_TRACE_INSTRUCTIONS 0
#endif
+#define MESSAGE_BUFFER_SIZE 1024
+
+char msg_buf[MESSAGE_BUFFER_SIZE];
+
+static int set_socket_reuseaddr(int socket_fd)
+{
+ const int val = 1;
+ const socklen_t len = sizeof(val);
+ return setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, len);
+}
+
+static inline struct sockaddr_in sockaddr_in_any_ip_with_port(uint16_t port) {
+ struct sockaddr_in server{};
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = htons(port);
+ return server;
+}
+
+static int setup_socket(uint16_t port)
+{
+ // This creates the socket - or quits
+ const int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (socket_fd == -1) {
+ perror("Could not create socket");
+ return -1;
+ }
+ // Make TCP port reusable in case of kill or crash.
+ // Deliberate explanation: https://stackoverflow.com/a/3233022
+ if (set_socket_reuseaddr(socket_fd) == -1) {
+ perror("setsockopt failed");
+ close(socket_fd);
+ return -1;
+ }
+ puts("Socket created");
+ const struct sockaddr_in server = sockaddr_in_any_ip_with_port(port);
+ if (bind(socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
+ perror("Bind failed");
+ close(socket_fd);
+ return -1;
+ }
+ printf("Binding to 0.0.0.0:%u done\n", port);
+ return socket_fd;
+}
+
+static inline void ConvertByteToHex(uint8_t byte, char* out)
+{
+ const uint8_t c1 = (byte >> 4) & 0x0f;
+ const uint8_t c2 = byte& 0x0f;
+ out[0] = static_cast<char>(c1 < 0xa ? c1 + '0' : c1 + ('a' - 0xa));
+ out[1] = static_cast<char>(c2 < 0xa ? c2 + '0' : c2 + ('a' - 0xa));
+}
+
+static std::string CreateResponse(
+ M68KDebuggingControl& m68k_debug,
+ const GDBRemote::Packet& packet)
+{
+ using namespace GDBRemote;
+ if (0) {
+ } else if (packet.type == PacketType::kQueryHaltReason) {
+ return "S05";
+ } else if (packet.type == PacketType::kStep) {
+ m68k_execute(1);
+ return "S05";
+ } else if (packet.type == PacketType::kSetThreadForCont) {
+ return "OK";
+ } else if (packet.type == PacketType::kQueryAttached) {
+ return "1";
+ } else if (packet.type == PacketType::kInterrupt) {
+ return "OK";
+ } else if (packet.type == PacketType::kReadMemory) {
+ const auto * const data =
+ reinterpret_cast<const PacketDataReadMemory*>(packet.data.get());
+ const uint32_t offset = data->offset;
+ const uint32_t length = data->length;
+ auto ret_data = std::string(length * 2, '\0');
+ for (uint32_t i = 0; i < length; i++) {
+ const uint8_t byte = m68k_debug.Read8(i + offset);
+ ConvertByteToHex(byte, &ret_data[i*2]);
+ }
+ return ret_data;
+ } else if (packet.type == PacketType::kReadGeneralRegisters) {
+ const M68KCPUState state = m68k_debug.GetCPUState();
+ std::string result{};
+ for (size_t i = 0; i < state.registers_count ;i++)
+ {
+ constexpr size_t value_size = 8;
+ char value[value_size + 1]{};
+ const int ret = snprintf(value, value_size + 1, "%08x", state.registers[i]);
+ assert(ret == value_size);
+ result += std::string(value, value_size);
+ }
+ return result;
+ } else if (packet.type == PacketType::kContinueAskSupported) {
+ return "vCont:c:s";
+ }
+ return "";
+}
+
static void exit_error(const char* fmt, ...)
{
va_list args;
@@ -61,10 +168,65 @@ void m68k_instr_callback(int pc)
m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
char buff2[100];
make_hex(buff2, pc, instr_size);
- printf("E %08X: %-20s: %s\n", pc, buff2, buff);
+ printf(" %08X: %-20s: %s\n", pc, buff2, buff);
fflush(stdout);
}
+int emulator(M68KDebuggingControl& m68k_debug)
+{
+ const int port = 3333;
+ const int socket_fd = setup_socket(port);
+ if (socket_fd == -1)
+ return EXIT_FAILURE;
+ printf("Listening TCP 0.0.0.0:%u\n", port);
+ listen(socket_fd, 4); // Mark socket as listener
+ struct sockaddr client_address;
+ socklen_t address_len;
+ const int conn_fd = accept(socket_fd, &client_address, &address_len);
+ if (conn_fd == -1) {
+ perror("Accept failed");
+ close(socket_fd);
+ return EXIT_FAILURE;
+ }
+ puts("Connection accepted");
+ GDBRemote::ExchangeContext exchange_ctx{};
+ ssize_t read_size;
+ while ((read_size = recv(conn_fd, msg_buf, MESSAGE_BUFFER_SIZE, 0)) > 0) {
+ for (size_t i = 0; i < static_cast<size_t>(read_size); i++) {
+ const auto res = exchange_ctx.Consume(msg_buf[i]);
+ if (res == nullptr) continue;
+ if (res->packet.length() > 0) {
+ if (0) printf("<- \"%s\"\n", exchange_ctx.GetLastPacket().c_str());
+ const auto packet = GDBRemote::Packet::Parse(res->packet);
+ if (0) printf(
+ " Packet type: \"%s\"\n",
+ GDBRemote::Packet::PacketTypeToString(packet.type));
+ }
+ if (res->ack.length() > 0) {
+ if (0) printf("-> \"%s\"\n", res->ack.c_str());
+ if (send(conn_fd, &res->ack[0], res->ack.length(), 0) == -1)
+ perror("Send failed (ack/nak)");
+ }
+ if (res->packet.length() > 0) {
+ const auto packet = GDBRemote::Packet::Parse(res->packet);
+ const auto response =
+ exchange_ctx.WrapDataToSend(CreateResponse(m68k_debug, packet));
+ if (0) printf("-> \"%s\"\n", response.c_str());
+ if (send(conn_fd, &response[0], response.length(), 0) == -1)
+ perror("Send failed (response)");
+ }
+ }
+ memset(msg_buf, '\0', MESSAGE_BUFFER_SIZE);
+ }
+ if (read_size == 0) {
+ puts("Client disconnected");
+ } else if (read_size == -1) {
+ perror("Recv failed");
+ }
+ close(socket_fd);
+ return 0;
+}
+
int main(int argc, char* argv[])
{
if (argc != 2)
@@ -87,7 +249,9 @@ int main(int argc, char* argv[])
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_pulse_reset();
- while (1)
+ M68KDebuggingControl m68k_debug{};
+ emulator(m68k_debug);
+ while (0)
{
// Values to execute determine the interleave rate.
// Smaller values allow for more accurate interleaving with multiple