summaryrefslogtreecommitdiff
path: root/eater_cpu
diff options
context:
space:
mode:
authoruvok2026-01-23 20:32:19 +0100
committeruvok2026-01-23 20:32:19 +0100
commit57775b39a940da5e5f29b9cb2ce6611ba107c587 (patch)
treeddbf90611edd78c58365faaac8c6c7cbb3e5aaee /eater_cpu
parente99939491820df300a6179719d807f810e7f1680 (diff)
Add ncurses and disassembly
Diffstat (limited to 'eater_cpu')
-rw-r--r--eater_cpu/cpp/CMakeLists.txt18
-rw-r--r--eater_cpu/cpp/Veater_computer__main.cpp9
-rw-r--r--eater_cpu/cpp/disas.h30
-rw-r--r--eater_cpu/cpp/simpc_config.h2
-rw-r--r--eater_cpu/cpp/simpc_curses.cpp237
-rw-r--r--eater_cpu/cpp/simpc_term.cpp12
6 files changed, 288 insertions, 20 deletions
diff --git a/eater_cpu/cpp/CMakeLists.txt b/eater_cpu/cpp/CMakeLists.txt
index 771db9d..d0349e7 100644
--- a/eater_cpu/cpp/CMakeLists.txt
+++ b/eater_cpu/cpp/CMakeLists.txt
@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.20)
project(sim_eater_pc)
+set(CMAKE_CXX_STANDARD 23)
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(verilator REQUIRED HINTS $ENV{VERILATOR_ROOT})
@@ -40,12 +42,10 @@ verilate(Veater_computer
VERILATOR_ARGS -CFLAGS -I${CMAKE_CURRENT_SOURCE_DIR}
)
-# if (USE_NCURSES)
-# target_compile_definitions(Veater_computer PRIVATE NCUR)
-# target_link_libraries(Veater_computer PRIVATE Curses::Curses)
-# target_sources(Veater_computer PUBLIC simpc_ui.cpp)
-# else()
-# target_sources(Veater_computer PUBLIC simpc_term.cpp)
-# endif()
-
-target_sources(Veater_computer PUBLIC simpc_term.cpp)
+if (USE_NCURSES)
+ target_compile_definitions(Veater_computer PRIVATE NCUR)
+ target_link_libraries(Veater_computer PRIVATE Curses::Curses)
+ target_sources(Veater_computer PUBLIC simpc_curses.cpp)
+else()
+ target_sources(Veater_computer PUBLIC simpc_term.cpp)
+endif()
diff --git a/eater_cpu/cpp/Veater_computer__main.cpp b/eater_cpu/cpp/Veater_computer__main.cpp
index 40b39b3..3bdb786 100644
--- a/eater_cpu/cpp/Veater_computer__main.cpp
+++ b/eater_cpu/cpp/Veater_computer__main.cpp
@@ -94,16 +94,17 @@ int main(int argc, char **argv, char **) {
tfp->close();
simpc_ui_finish_message(contextp, topp);
- if (VL_LIKELY(!contextp->gotFinish())) {
- VL_DEBUG_IF(VL_PRINTF("+ Exiting without $finish; no events left\n"););
- }
+ // if (VL_LIKELY(!contextp->gotFinish())) {
+ // VL_DEBUG_IF(VL_PRINTF("+ Exiting without $finish; no events left\n"););
+ // }
// Execute 'final' processes
topp->final();
// Print statistical summary report
- contextp->statsPrintSummary();
+ // contextp->statsPrintSummary();
+ simpc_ui_confirm_finish();
simpc_ui_cleanup();
return 0;
diff --git a/eater_cpu/cpp/disas.h b/eater_cpu/cpp/disas.h
new file mode 100644
index 0000000..9685e15
--- /dev/null
+++ b/eater_cpu/cpp/disas.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <cstdint>
+#include <format>
+#include <string>
+
+static std::string disas(uint8_t ins) {
+ switch (ins >> 4) {
+ case 0:
+ return "nop";
+ case 1:
+ return std::format("lda {}", ins & 0x0f);
+ case 2:
+ return std::format("add {}", ins & 0x0f);
+ case 3:
+ return std::format("sub {}", ins & 0x0f);
+ case 4:
+ return std::format("sta {}", ins & 0x0f);
+ case 5:
+ return std::format("ldi {}", ins & 0x0f);
+ case 6:
+ return std::format("jmp");
+ case 14:
+ return std::format("out");
+ case 15:
+ return std::format("halt");
+ default:
+ return "???";
+ }
+}
diff --git a/eater_cpu/cpp/simpc_config.h b/eater_cpu/cpp/simpc_config.h
index 56c9ad8..cc00199 100644
--- a/eater_cpu/cpp/simpc_config.h
+++ b/eater_cpu/cpp/simpc_config.h
@@ -1,4 +1,4 @@
#pragma once
// #define TICKS_PER_CLOCK_PERIOD 1
-// #define NCUR_DELAY_MS 10
+#define NCUR_DELAY_MS 10
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);
+}
diff --git a/eater_cpu/cpp/simpc_term.cpp b/eater_cpu/cpp/simpc_term.cpp
index 2ac3895..b0396a1 100644
--- a/eater_cpu/cpp/simpc_term.cpp
+++ b/eater_cpu/cpp/simpc_term.cpp
@@ -1,5 +1,4 @@
-#include "Veater_computer_eater_register.h"
-#include "Veater_computer_my_mem__DB10.h"
+
#include "simpc_ui.h"
#define NCUR_X 5
@@ -25,6 +24,8 @@
#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"
#include <cstdint>
#include <cstdio>
@@ -38,10 +39,8 @@ 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;
- // uint16_t opcode = topp->eater_computer->;
uint8_t opcode = topp->eater_computer->INS->r_datastore;
- // topp->halt
- uint8_t halt = topp->eater_computer->flags.__PVT__halt;
+ uint8_t halt = topp->halt;
PRINT_ME_W(status_top, 0, 0, "Step: %10lu", i);
PRINT_ME_W(status_top, 1, 0, "%-20s", paused ? "Paused" : "Running");
@@ -113,7 +112,8 @@ void simpc_ui_finish_message(const std::unique_ptr<VerilatedContext> &contextp,
for (int idx = 0; idx < topp->eater_computer->RAM->r_datastore.size();
idx++) {
- printf("Mem[%2d] = 0X%02X\n", idx, topp->eater_computer->RAM->r_datastore[idx]);
+ printf("Mem[%2d] = 0X%02X\n", idx,
+ topp->eater_computer->RAM->r_datastore[idx]);
}
}