diff options
Diffstat (limited to 'eater_cpu/cpp/simpc_curses.cpp')
| -rw-r--r-- | eater_cpu/cpp/simpc_curses.cpp | 237 |
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); +} |
