summaryrefslogtreecommitdiff
path: root/eater_cpu/cpp/simpc_curses.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'eater_cpu/cpp/simpc_curses.cpp')
-rw-r--r--eater_cpu/cpp/simpc_curses.cpp237
1 files changed, 237 insertions, 0 deletions
diff --git a/eater_cpu/cpp/simpc_curses.cpp b/eater_cpu/cpp/simpc_curses.cpp
new file mode 100644
index 0000000..b6dd230
--- /dev/null
+++ b/eater_cpu/cpp/simpc_curses.cpp
@@ -0,0 +1,237 @@
+#include "disas.h"
+#include "simpc_config.h"
+#include "simpc_ui.h"
+
+#include <ncurses.h>
+
+#define PRINT_ME(y, x, ...) \
+ { \
+ mvprintw(y, x, __VA_ARGS__); \
+ }
+#define PRINT_ME_W(w, y, x, ...) \
+ { \
+ mvwprintw(w, y, x, __VA_ARGS__); \
+ }
+#define PRINT_NEXT(dly) \
+ { \
+ if (resized) { \
+ /* ????*/ \
+ resized = 0; \
+ clear(); \
+ } \
+ refresh(); \
+ wrefresh(status_top); \
+ wrefresh(clock_regs); \
+ wrefresh(MEM); \
+ if (dly) { \
+ napms(NCUR_DELAY_MS); \
+ } \
+ }
+
+#define SIMPLE_BORDER(w, lr, tb, c) \
+ { \
+ wborder(w, lr, lr, tb, tb, c, c, c, c); \
+ }
+
+static WINDOW *status_top = NULL;
+static WINDOW *clock_regs = NULL;
+static WINDOW *MEM = NULL;
+
+#include "Veater_computer.h"
+#include "Veater_computer_eater_alu.h"
+#include "Veater_computer_eater_computer.h"
+#include "Veater_computer_eater_register.h"
+#include "Veater_computer_my_mem__DB10.h"
+#include "verilated.h"
+
+bool paused = true;
+static bool resized = false;
+
+static void handle_key();
+
+// void simpc_ui_write(const std::unique_ptr<Veater_computer> &topp, uint64_t
+// &i) {
+void simpc_ui_write(const std::unique_ptr<Veater_computer> &topp, uint64_t i) {
+ // clk hi->lo doesn't do anything, just skip this.
+ if (i != 0 && !topp->clk_in)
+ return;
+ uint8_t opcode = topp->eater_computer->INS->r_datastore;
+ uint8_t halt = topp->halt;
+
+ PRINT_ME_W(status_top, 1, 1, "Step: %10lu", i);
+ PRINT_ME_W(status_top, 2, 1, "%-20s", paused ? "Paused" : "Running");
+
+ PRINT_ME_W(clock_regs, 1, 1, "CLK: %4d\tPC: 0x%02X\tINS: 0x%02X\tHLT: %6d",
+ topp->clk_in,
+ // wrong
+ // topp->eater_computer->clk_in,
+ topp->eater_computer->PC_out, opcode, topp->halt);
+ // const wchar_t flag_on = L'\u26ab';
+ // const wchar_t flag_off = L'\u26aa';
+ const char flag_on = 'X';
+ const char flag_off = ' ';
+ PRINT_ME_W(
+ clock_regs, 2, 1,
+ "| %c | %c | %c %c | %c %c | %c %c | %c %c | %c %c | %c | %c %c %c |",
+ halt ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__MAR_in ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__RAM_in ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__RAM_out ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__INS_in ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__INS_out ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__A_in ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__A_out ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__ALU_out ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__ALU_subtract_nadd ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__B_in ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__B_out ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__OUT_in ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__PC_count ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__PC_out ? flag_on : flag_off,
+ topp->eater_computer->flags.__PVT__PC_in ? flag_on : flag_off);
+ PRINT_ME_W(clock_regs, 3, 1,
+ "| H | M | R R | I I | A A | A S | B B | O | C C J | \n");
+ PRINT_ME_W(clock_regs, 4, 1,
+ "| L | A | A A | S S | I O | L U | I O | I | E O M | \n");
+ PRINT_ME_W(clock_regs, 5, 1,
+ "| T | I | I O | I O | | O B | | N | P | \n");
+
+ // PRINT_ME_W(
+ // clock_regs, 2, 1, "A: 0x%02X\tD: 0x%02X\tM: 0x%02X\tRES: 0x%02X",
+ // topp->eater_computer->reg_A_int, topp->eater_computer->reg_D_int,
+ // topp->eater_computer->reg_pA_int, topp->eater_computer->result_int);
+ // PRINT_ME_W(clock_regs, 3, 1, "%c%8d\t%c %8d\t%c %8d\t%11d",
+ // topp->eater_computer->store_to_A_int ? '*' : ' ',
+ // topp->eater_computer->reg_A_int,
+ // topp->eater_computer->store_to_D_int ? '*' : ' ',
+ // topp->eater_computer->reg_D_int,
+ // topp->eater_computer->store_to_pA_int ? '*' : ' ',
+ // topp->eater_computer->reg_pA_int,
+ // topp->eater_computer->result_int);
+
+ for (int adr = 0; adr < 16; adr++) {
+ const int ypos_base = 1;
+ const int adr_factored = adr % 8;
+ const int xpos_base = adr < 8 ? 1 : 21;
+ const char *prefix = adr == topp->eater_computer->MAR_out ? "> " : " ";
+ {
+ const uint16_t program_op_code =
+ topp->eater_computer->RAM->r_datastore[adr];
+ std::string disas_code = disas(program_op_code);
+ PRINT_ME_W(MEM, ypos_base + adr_factored, xpos_base,
+ "%02X %s%02X %-8s %c", adr, prefix, program_op_code,
+ disas_code.c_str(), xpos_base == 1 ? '|' : ' ');
+ // mvchgat in bold
+ }
+ }
+
+ // borders at the bottom, because of wrapping logic I don't grasp
+ SIMPLE_BORDER(MEM, '|', '-', '+');
+ PRINT_ME_W(MEM, 0, 1, "--- MEM ---");
+
+ // PRINT_ME(7 + NCUR_OFFSET, NCUR_X, "ALU");
+ // PRINT_ME(8 + NCUR_OFFSET, NCUR_X, "X: %5d\tY: %5d",
+ // topp->eater_computer->CPU->my_alu->int_op_x,
+ // topp->eater_computer->CPU->my_alu->int_op_y);
+
+ PRINT_ME(getmaxy(stdscr) - 1, 1,
+ " q - Quit; p - (Un)pause; s - step (while paused) ");
+
+ PRINT_NEXT(true);
+
+ handle_key();
+}
+
+void simpc_ui_finish_message(const std::unique_ptr<VerilatedContext> &contextp,
+ const std::unique_ptr<Veater_computer> &topp) {
+ attron(A_BOLD);
+ auto xpos = 20;
+ PRINT_ME_W(status_top, 1, xpos, "Simulation finished.");
+ const char *msg;
+ if (topp->halt) {
+ msg = "Halt encountered.";
+ } else if (!contextp->gotFinish()) {
+ msg = "Step count exceeded.";
+ } else {
+ msg = "Regular finish.";
+ }
+ PRINT_ME_W(status_top, 2, xpos, "%s", msg);
+ PRINT_NEXT(false);
+ attroff(A_BOLD);
+}
+
+void simpc_ui_init(void) {
+#if NCUR
+ initscr();
+ curs_set(0);
+
+ // lines, cols, ypos, xpos
+ status_top = newwin(4, 50, 0, 0);
+ wrefresh(status_top);
+ clock_regs = newwin(7, 80, 3, 0);
+ wrefresh(clock_regs);
+ auto numlines = 8 + 2;
+ auto romwidth = 41;
+ MEM = newwin(numlines, romwidth, 10, 0);
+ wrefresh(MEM);
+
+ nodelay(stdscr, TRUE);
+ noecho();
+ cbreak();
+
+#endif
+}
+
+void simpc_ui_cleanup(void) {
+#if NCUR
+ nocbreak();
+ echo();
+
+ auto ws = {status_top, clock_regs, MEM};
+
+ for (auto &w : ws) {
+ if (w) {
+ delwin(w);
+ }
+ }
+
+ endwin();
+#endif
+}
+
+void simpc_ui_confirm_finish(void) {
+#if NCUR
+ nodelay(stdscr, FALSE);
+ getch();
+#endif
+}
+
+static void handle_key() {
+ bool block_here = paused;
+
+ do {
+ int ch = getch();
+
+ switch (ch) {
+ case 'p':
+ // pass *current* state.
+ // pass false (currently running) - getch will block (entering step mode).
+ // pass true (currently paused) - getch will be non-blocking.
+ nodelay(stdscr, paused);
+ paused = !paused;
+ block_here = paused;
+ break;
+ case 'q':
+ simpc_ui_cleanup();
+ exit(0);
+ break;
+ case 's':
+ block_here = false;
+ break;
+
+ case KEY_RESIZE:
+ resized = 1;
+ break;
+ }
+ } while (block_here);
+}