#include "disas.h" #include "simpc_config.h" #include "simpc_ui.h" #include #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 &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: %2d\tState: 0x%02X\tHLT: %-2d", topp->clk_in, topp->eater_computer->decoder__DOT__internal_state, topp->halt); PRINT_ME_W(clock_regs, 2, 1, "BUS: %02X\tPC: @0x%02X\tINS: 0x%02X", topp->eater_computer->bus, topp->eater_computer->PC_out, opcode); PRINT_ME_W(clock_regs, 3, 1, "A : 0x%02X\tB : 0x%02X\tALU: 0x%02X\tOUT: 0x%02X", topp->eater_computer->A->r_datastore, topp->eater_computer->B->r_datastore, topp->eater_computer->alu->result, topp->eater_computer->OUT->r_datastore); // "PC: 0x%02X, INS: 0x%02X", topp->eater_computer->PC_out, opcode; // const wchar_t flag_on = L'\u26ab'; // const wchar_t flag_off = L'\u26aa'; const char flag_on = 'X'; const char flag_off = ' '; const int flagstart = 4; PRINT_ME_W( clock_regs, flagstart, 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, flagstart + 1, 1, "| H | M | R R | I I | A A | A S | B B | O | C C J | \n"); PRINT_ME_W(clock_regs, flagstart + 2, 1, "| L | A | A A | S S | I O | L U | I O | I | E O M | \n"); PRINT_ME_W(clock_regs, flagstart + 3, 1, "| T | I | I O | I O | | O B | | N | P | \n"); 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 &contextp, const std::unique_ptr &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(9, 80, 3, 0); wrefresh(clock_regs); auto numlines = 8 + 2; auto romwidth = 41; MEM = newwin(numlines, romwidth, 12, 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); }