diff options
| author | Alejandro Soto <alejandro@34project.org> | 2022-12-06 13:04:15 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2022-12-06 13:04:15 -0600 |
| commit | 064b72ae4eb22336438288a9664a37c0dd07f4bc (patch) | |
| tree | bfbe072702b667299979d6ceb76a3ef444fb9c1a /tb/top/conspiracion.cpp | |
| parent | df69f7b7c73be01968ba767ab112b227533bbd70 (diff) | |
Implement gdbstub
Diffstat (limited to '')
| -rw-r--r-- | tb/top/conspiracion.cpp | 187 |
1 files changed, 147 insertions, 40 deletions
diff --git a/tb/top/conspiracion.cpp b/tb/top/conspiracion.cpp index 07b35a5..15da2ea 100644 --- a/tb/top/conspiracion.cpp +++ b/tb/top/conspiracion.cpp @@ -197,11 +197,21 @@ int main(int argc, char **argv) parser, "no-tty", "Disable TTY takeoveer", {"no-tty"} ); + args::Flag start_halted + ( + parser, "start-halted", "Halt before running the first instruction", {"start-halted"} + ); + args::ValueFlag<unsigned> cycles ( parser, "cycles", "Number of core cycles to run", {"cycles"}, 256 ); + args::ValueFlag<int> control_fd + ( + parser, "fd", "Control file descriptor", {"control-fd"}, -1 + ); + args::ValueFlagList<mem_region> dump_mem ( parser, "addr,length", "Dump a memory region", {"dump-mem"} @@ -209,7 +219,7 @@ int main(int argc, char **argv) args::ValueFlagList<mem_init> const_ ( - parser, "addr,value", "Add a constant map", {"const"} + parser, "addr,value", "Add a constant mapping", {"const"} ); args::ValueFlagList<file_load> loads @@ -241,6 +251,13 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + FILE *ctrl = stdout; + if(*control_fd != -1 && (ctrl = fdopen(*control_fd, "r+")) == nullptr) + { + std::perror("fdopen()"); + return EXIT_FAILURE; + } + Vconspiracion top; VerilatedVcdC trace; @@ -369,17 +386,136 @@ int main(int argc, char **argv) ttyJ0.takeover(); } - top.halt = 0; + top.halt = start_halted; top.rst_n = 0; cycle(); top.rst_n = 1; - for(unsigned i = 0; i < *cycles; ++i) + auto do_reg_dump = [&]() + { + std::fputs("=== dump-regs ===\n", ctrl); + + const auto &core = *top.conspiracion->core; + const auto ®file = core.regs->a->file; + + int i = 0; + for(const auto *name : gp_regs) + { + std::fprintf(ctrl, "%08x %s\n", regfile[i++], name); + } + + std::fprintf(ctrl, "%08x pc\n", core.control->pc << 2); + std::fprintf(ctrl, "%08x cpsr\n", core.psr->cpsr_word); + std::fprintf(ctrl, "%08x spsr_svc\n", core.psr->spsr_svc_word); + std::fprintf(ctrl, "%08x spsr_abt\n", core.psr->spsr_abt_word); + std::fprintf(ctrl, "%08x spsr_und\n", core.psr->spsr_und_word); + std::fprintf(ctrl, "%08x spsr_fiq\n", core.psr->spsr_fiq_word); + std::fprintf(ctrl, "%08x spsr_irq\n", core.psr->spsr_irq_word); + std::fputs("=== end-regs ===\n", ctrl); + }; + + auto do_mem_dump = [&](const mem_region *dumps, std::size_t count) { - cycle(); - if(failed) + std::fputs("=== dump-mem ===\n", ctrl); + for(std::size_t i = 0; i < count; ++i) { - break; + const auto &dump = dumps[i]; + + std::fprintf(ctrl, "%08x ", static_cast<std::uint32_t>(dump.start)); + for(std::size_t i = 0; i < dump.length; ++i) + { + auto word = avl.dump(dump.start + i); + word = (word & 0xff) << 24 + | ((word >> 8) & 0xff) << 16 + | ((word >> 16) & 0xff) << 8 + | ((word >> 24) & 0xff); + + std::fprintf(ctrl, "%08x", word); + } + + std::fputc('\n', ctrl); + } + + std::fputs("=== end-mem ===\n", ctrl); + }; + + unsigned i = 0; + while(!failed && i < *cycles) + { + for(; i < *cycles; ++i) + { + cycle(); + if(failed || top.cpu_halted) [[unlikely]] + { + break; + } + } + + if(top.cpu_halted) + { + do_reg_dump(); + std::fputs("=== halted ===\n", ctrl); + + char *line = nullptr; + std::size_t buf_size = 0; + + while(true) + { + ssize_t read = getline(&line, &buf_size, ctrl); + if(read == -1) + { + if(!std::feof(ctrl)) + { + std::perror("getline()"); + failed = true; + } + + break; + } + + if(read > 0 && line[read - 1] == '\n') + { + line[read - 1] = '\0'; + } + + const char *cmd = std::strtok(line, " "); + if(!std::strcmp(cmd, "continue")) + { + top.halt = false; + break; + } else if(!std::strcmp(cmd, "dump-mem")) + { + mem_region dump = {}; + std::sscanf(std::strtok(nullptr, " "), "%zu", &dump.start); + std::sscanf(std::strtok(nullptr, " "), "%zu", &dump.length); + do_mem_dump(&dump, 1); + } else if(!std::strcmp(cmd, "patch-mem")) + { + std::uint32_t addr; + std::sscanf(std::strtok(nullptr, " "), "%u", &addr); + + const char *data = std::strtok(nullptr, " "); + std::size_t length = std::strlen(data); + + while(data && length >= 8) + { + std::uint32_t word; + std::sscanf(data, "%08x", &word); + + data += 8; + length -= 8; + + word = (word & 0xff) << 24 + | ((word >> 8) & 0xff) << 16 + | ((word >> 16) & 0xff) << 8 + | ((word >> 24) & 0xff); + + avl.patch(addr++, word); + } + } + } + + std::free(line); } } @@ -395,49 +531,20 @@ int main(int argc, char **argv) if(dump_regs || failed) { - std::puts("=== dump-regs ==="); - - const auto &core = *top.conspiracion->core; - const auto ®file = core.regs->a->file; - - int i = 0; - for(const auto *name : gp_regs) - { - std::printf("%08x %s\n", regfile[i++], name); - } - - std::printf("%08x pc\n", core.control->pc << 2); - std::printf("%08x cpsr\n", core.psr->cpsr_word); - std::printf("%08x spsr_svc\n", core.psr->spsr_svc_word); - std::printf("%08x spsr_abt\n", core.psr->spsr_abt_word); - std::printf("%08x spsr_und\n", core.psr->spsr_und_word); - std::printf("%08x spsr_fiq\n", core.psr->spsr_fiq_word); - std::printf("%08x spsr_irq\n", core.psr->spsr_irq_word); + do_reg_dump(); } const auto &dumps = *dump_mem; if(!dumps.empty()) { - std::puts("=== dump-mem ==="); + do_mem_dump(dumps.data(), dumps.size()); } - for(const auto &dump : dumps) + top.final(); + if(ctrl != stdout) { - std::printf("%08x ", static_cast<std::uint32_t>(dump.start)); - for(std::size_t i = 0; i < dump.length; ++i) - { - auto word = avl.dump(dump.start + i); - word = (word & 0xff) << 24 - | ((word >> 8) & 0xff) << 16 - | ((word >> 16) & 0xff) << 8 - | ((word >> 24) & 0xff); - - std::printf("%08x", word); - } - - std::putchar('\n'); + std::fclose(ctrl); } - top.final(); return failed ? EXIT_FAILURE : EXIT_SUCCESS; } |
