diff --git a/.github/workflows/c.yml b/.github/workflows/c.yml index 084cb2d6f..eb3f4d7d4 100644 --- a/.github/workflows/c.yml +++ b/.github/workflows/c.yml @@ -28,6 +28,7 @@ jobs: id: set-up-homebrew uses: Homebrew/actions/setup-homebrew@master - run: brew install bison expect icarus-verilog + - run: brew install verilator - if: runner.os == 'macOS' run: echo "$(brew --prefix)/opt/bison/bin" >> $GITHUB_PATH - if: matrix.SDL != 0 diff --git a/CMakeLists.txt b/CMakeLists.txt index bb9277d2d..cc6e427a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,8 @@ set(CMAKE_C_STANDARD_REQUIRED TRUE) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") -option(BUILD_EXAMPLES OFF "build examples from ex/") +option(BUILD_EXAMPLES "build examples from ex/" OFF) +option(VERILATOR "build the Verilator-based simulator" ON) # The TENYR language is self-hosted: tas, tld, and tsim are built by this # project into ${CMAKE_BINARY_DIR}/src. CMake enables the TENYR language @@ -27,6 +28,7 @@ if(BUILD_EXAMPLES OR TESTING) COMMAND ${CMAKE_COMMAND} -S "${CMAKE_SOURCE_DIR}" -B "${_boot_dir}" -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DJIT=${JIT} -DSDL=${SDL} -DICARUS=${ICARUS} + -DVERILATOR=${VERILATOR} -DBUILD_EXAMPLES=OFF -DTESTING=OFF RESULT_VARIABLE _boot_cfg_res) if(NOT _boot_cfg_res EQUAL 0) @@ -78,5 +80,6 @@ configure_file(src/tenyr_config.h.in tenyr_config.h) add_subdirectory(lib) add_subdirectory(hw/icarus) +add_subdirectory(hw/verilator) add_subdirectory(hw/vpi) add_subdirectory(src) diff --git a/Changelog.md b/Changelog.md index f671aac65..5071437c0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - Make SDL, JIT, and ICARUS selectable at build time (#97, #108) +- Verilator-based simulator (`vsim`) (#48) ### Changed - Adopt CMake as the build system (#97, #98) diff --git a/README.md b/README.md index 67cc95294..f0b359bf5 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ development board. * [assembler (tas)](https://github.com/kulp/tenyr/wiki/Assembler) * [linker (tld)](https://github.com/kulp/tenyr/wiki/Linker) * [simulator (tsim)](https://github.com/kulp/tenyr/wiki/Simulator) + * [Verilator simulator (vsim)](https://github.com/kulp/tenyr/tree/develop/hw/verilator) – runs tenyr code through the Verilog implementation, with serial text output and `-v` verbosity support * a [standard library](https://github.com/kulp/tenyr/tree/develop/lib) of tenyr code * some [example software](https://github.com/kulp/tenyr/tree/develop/ex), including : * [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) ([tenyr source code](https://github.com/kulp/tenyr/blob/develop/ex/bm_conway.tas)) diff --git a/ex/CMakeLists.txt b/ex/CMakeLists.txt index dbbc79adb..c594eb5b0 100644 --- a/ex/CMakeLists.txt +++ b/ex/CMakeLists.txt @@ -103,5 +103,14 @@ foreach(demo ${demos}) COST 0.5 ) + if(VERILATOR) + check_std_outputs( + NAME ${demo}_demo_verilog + COMMAND ${VSIM} + INPUT ${demo_executable} + PROPERTIES TIMEOUT 60 + ) + endif() + endforeach() endif() diff --git a/hw/verilator/.gitignore b/hw/verilator/.gitignore new file mode 100644 index 000000000..9486e8b3f --- /dev/null +++ b/hw/verilator/.gitignore @@ -0,0 +1,13 @@ +*.tree +*.dot +Vtop*.cpp +Vtop*.h +Vtop*.mk +Vtop*.vpp +Vtop +Vtop.xml +Vtop*.a +Vtop__*.* +Vtop_061_order_edges.txt +vsim +logs/ diff --git a/hw/verilator/CMakeLists.txt b/hw/verilator/CMakeLists.txt new file mode 100644 index 000000000..68c970491 --- /dev/null +++ b/hw/verilator/CMakeLists.txt @@ -0,0 +1,67 @@ +# Verilator-based simulator target. +if(NOT VERILATOR) + return() +endif() +find_program(VERILATOR_BIN verilator) +if(NOT VERILATOR_BIN) + message(FATAL_ERROR "Verilator not found. Install it or set VERILATOR=OFF") +endif() + +# Generate C++ model from Verilog sources +set(VFILES + ${CMAKE_SOURCE_DIR}/hw/verilog/top.v + ${CMAKE_SOURCE_DIR}/hw/verilog/sim/simclocks.v + ${CMAKE_SOURCE_DIR}/hw/verilog/tenyr.v + ${CMAKE_SOURCE_DIR}/hw/verilog/ram.v + ${CMAKE_SOURCE_DIR}/hw/verilog/seg7.v + ${CMAKE_CURRENT_SOURCE_DIR}/simserial.v + ${CMAKE_SOURCE_DIR}/hw/verilog/hex2segments.v + ${CMAKE_SOURCE_DIR}/hw/verilog/gpio.v + ${CMAKE_SOURCE_DIR}/3rdparty/wb_intercon/rtl/verilog/wb_mux.v + ${CMAKE_CURRENT_SOURCE_DIR}/sim_main.cpp +) + +set(VFLAGS + -Wall -Wno-fatal -Wno-style + -I${CMAKE_SOURCE_DIR}/hw/verilog + --cc --trace + -DSIMCLK=tenyr_mainclock + -DSERIAL + --Mdir ${CMAKE_CURRENT_BINARY_DIR} + --exe + --vpi --public-flat-rw + -CFLAGS "-I${CMAKE_SOURCE_DIR}/src -I${CMAKE_BINARY_DIR}/src -I${CMAKE_SOURCE_DIR}/src/os/default" + -LDFLAGS "-L${CMAKE_CURRENT_BINARY_DIR} -ldisasm -L${CMAKE_BINARY_DIR}/src -lcommon -lm" +) + +# macOS: C++ standard library include path +if(APPLE) + execute_process( + COMMAND xcrun --show-sdk-path + OUTPUT_VARIABLE SDK_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + list(APPEND VFLAGS -CFLAGS "-isysroot${SDK_PATH} -I${SDK_PATH}/usr/include/c++/v1") +endif() + + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/vsim + COMMAND ${VERILATOR_BIN} ${VFLAGS} ${VFILES} + COMMAND make -C ${CMAKE_CURRENT_BINARY_DIR} -f ${CMAKE_CURRENT_BINARY_DIR}/Vtop.mk Vtop + COMMAND ${CMAKE_COMMAND} -E rename Vtop vsim + DEPENDS ${VFILES} common disasm + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Building Verilator simulator (vsim)" +) + +add_custom_target(vsim ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/vsim +) + +# Convenience: run the simulator +add_custom_target(vsim-run + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/vsim ${vsim_args} + DEPENDS vsim + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/hw/verilator/sim_main.cpp b/hw/verilator/sim_main.cpp new file mode 100644 index 000000000..fb4a4343c --- /dev/null +++ b/hw/verilator/sim_main.cpp @@ -0,0 +1,338 @@ +// Verilated testbench for the tenyr CPU core. +// +// Runs tenyr code through the Verilog implementation with: +// - Serial text output via simserial.v +// - Verbosity levels (-v, -vv, -vvv, -vvvv) matching tsim +// - Disassembly and register dump using the same code as tsim (asm.c) +// - Binary loading from .texe (obj) files + +#include "Vtop.h" +#include "Vtop___024root.h" +#include "verilated.h" + +#include +#include +#include +#include +#include + +extern "C" { + +#include "tenyr_config.h" +#include "common.h" +#include "asm.h" +#include "stream.h" +#include + +} // extern "C" + +static vluint64_t main_time = 0; + +double sc_time_stamp() { + return static_cast(main_time); +} + +// --- Configuration --- + +// From tenyr.v +static const uint32_t RAM_BASE = 0x1000; +static const int RAM_SIZE = 8192; + +static int verbose = 0; +static const char *load_file = nullptr; +static int32_t load_addr = RAM_BASE; // --address=N, base for loading the image +static int32_t start_addr = RAM_BASE; // --start=N, initial program counter +static vluint64_t max_periods = 0x10000000ULL; + +// State machine states (Core localparams: s0=0 ... s7=7) +static const int S0 = 0; // execute +static const int S3 = 3; // data memory access +static const int S6 = 6; // latch instruction + +// --- RAM access --- + +static inline void ram_write(Vtop &top, uint32_t addr, uint32_t word) { + if (addr >= RAM_BASE && addr < RAM_BASE + RAM_SIZE) + top.rootp->Tenyr__DOT__ram__DOT__store[addr - RAM_BASE] = word; +} + +static inline uint32_t ram_read(Vtop &top, uint32_t addr) { + if (addr >= RAM_BASE && addr < RAM_BASE + RAM_SIZE) + return top.rootp->Tenyr__DOT__ram__DOT__store[addr - RAM_BASE]; + return 0xffffffff; // default slave +} + +// --- Memory access tracing (matching tsim's dispatch_op at verbose > 2) --- + +/// Buffer for a data memory operation observed at S3. +/// -1: none, 0: read, 1: write +static int mem_op = -1; +static uint32_t mem_addr = 0, mem_data = 0; + +/// True after the $finish instruction (0xffffffff) is detected at S0, so the +/// main loop can let it execute through S3 and print its data memory access +/// before halting (matching tsim, which prints the $finish data read before +/// the simulation ends). +static bool finish_pending = false; + +/// Print a single memory access line, matching tsim's dispatch_op format +/// (verbose > 2). +static inline void trace_memaccess(int is_write, uint32_t addr, uint32_t data) +{ + if (verbose > 2) + fprintf(stderr, "%-5s @ 0x%08x = 0x%08x\n", + is_write ? "write" : "read", addr, data); +} + +static int32_t read_sword_le(FILE *f) { + uint32_t val = 0; + if (fread(&val, 1, 4, f) != 4) return 0; + return static_cast(val); +} + +// --- .to (obj) file loader --- + +static void load_tofile(Vtop &top, const char *filename) { + FILE *f = fopen(filename, "rb"); + if (!f) { fprintf(stderr, "vsim: cannot open %s\n", filename); exit(1); } + + char magic[3]; + if (fread(magic, 1, 3, f) != 3 || memcmp(magic, "TOV", 3) != 0) { + fprintf(stderr, "vsim: %s: bad magic (expected TOV)\n", filename); + exit(1); + } + uint8_t version; fread(&version, 1, 1, f); + read_sword_le(f); // flags + int32_t rec_count = read_sword_le(f); + + for (int32_t r = 0; r < rec_count; r++) { + int32_t addr = read_sword_le(f); + int32_t size = read_sword_le(f); + for (int32_t i = 0; i < size; i++) { + uint32_t word = (uint32_t)read_sword_le(f); + uint32_t ram_addr = (uint32_t)(addr + load_addr + i); + trace_memaccess(1, ram_addr, word); + ram_write(top, ram_addr, word); + // Verification read (matching tsim's load_sim) + trace_memaccess(0, ram_addr, ram_read(top, ram_addr)); + } + } + + // Skip symbols + int32_t sym_count = read_sword_le(f); + for (int32_t s = 0; s < sym_count; s++) { + read_sword_le(f); int32_t name_len = read_sword_le(f); + fseek(f, (name_len + 3) & ~3, SEEK_CUR); + read_sword_le(f); read_sword_le(f); + } + // Skip relocations + int32_t rlc_count = read_sword_le(f); + for (int32_t r = 0; r < rlc_count; r++) { + read_sword_le(f); int32_t name_len = read_sword_le(f); + fseek(f, (name_len + 3) & ~3, SEEK_CUR); + read_sword_le(f); read_sword_le(f); read_sword_le(f); + } + fclose(f); +} + +// --- Register dump and trace (matching tsim's pre_insn + dispatch_op) --- + +static void trace_instruction(Vtop &top, uint32_t insn_word, uint32_t pc) { + // Print any buffered data memory operation from the previous instruction's + // S3 stage (matching tsim, where dispatch_op for OP_DATA_READ/OP_WRITE is + // called during run_instruction, which occurs after pre_insn of the + // current instruction but before pre_insn of the next). + if (mem_op >= 0) { + trace_memaccess(mem_op == 1, mem_addr, mem_data); + mem_op = -1; + } + + // Print instruction fetch read (matching tsim's dispatch_op for OP_INSN_READ, + // which is called before pre_insn in interp_step_sim). + trace_memaccess(0, pc, insn_word); + + // Build an element struct for the disassembler + struct element elem = {}; + elem.insn.u.word = static_cast(insn_word); + elem.insn.reladdr = static_cast(pc); + elem.insn.size = 1; + + struct stream stream = stream_make_from_file(stderr); + + if (verbose > 0) + fprintf(stderr, "IP = 0x%08x\t", pc); + + if (verbose > 1) { + int len = print_disassembly(&stream, &elem, ASM_AS_INSN); + fprintf(stderr, "%*s# ", 30 - len, ""); + print_disassembly(&stream, &elem, ASM_AS_DATA); + } + + if (verbose > 3) { + fprintf(stderr, "\n"); + + // Collect 16 registers: A-O from Verilog store, P from nextP + int32_t regs[16]; + for (int i = 0; i < 15; i++) + regs[i] = (int32_t)top.rootp->Tenyr__DOT__core__DOT__regs__DOT__store[i]; + regs[15] = (int32_t)(top.rootp->Tenyr__DOT__core__DOT__nextP - 1); + + print_registers(&stream, regs); + } + + if (verbose > 0) + fprintf(stderr, "\n"); +} + +// --- Command-line interface (a subset of tsim's) --- + +static const char shortopts[] = "as:vhV"; + +static const struct option longopts[] = { + { "address" , required_argument, NULL, 'a' }, + { "start" , required_argument, NULL, 's' }, + { "verbose" , no_argument, NULL, 'v' }, + { "help" , no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 }, +}; + +static const char *version(void) +{ + return "vsim version " BUILD_NAME " built " __DATE__; +} + +static void usage(const char *me) +{ + printf("Usage: %s [ OPTIONS ] image-file\n" + "Options:\n" + " -a, --address=N load instructions into memory at word address N\n" + " -s, --start=N start execution at word address N\n" + " -v, --verbose increase verbosity of output\n" + "\n" + " -h, --help display this message\n" + " -V, --version print a string describing the version\n" + "\n", me); +} + +// --- Main --- + +int main(int argc, char **argv) { + Verilated::commandArgs(argc, argv); + + int ch; + while ((ch = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + switch (ch) { + case 'a': load_addr = (int32_t)strtol(optarg, NULL, 0); break; + case 's': start_addr = (int32_t)strtol(optarg, NULL, 0); break; + case 'v': verbose++; break; + case 'h': usage(argv[0]); return 0; + case 'V': puts(version()); return 0; + default: usage(argv[0]); return 1; + } + } + + // The image file is a positional argument, matching tsim. + if (optind >= argc) { + usage(argv[0]); + return 1; + } + if (argc - optind > 1) { + fprintf(stderr, "vsim: too many arguments\n"); + usage(argv[0]); + return 1; + } + load_file = argv[optind]; + + Vtop top; + top.reset = 1; + top.clk = 0; + + load_tofile(top, load_file); + + top.eval(); + int prev_state = top.rootp->Tenyr__DOT__core__DOT__state; + + while (true) { + top.clk = !top.clk; + if (main_time < 10) top.rootp->Tenyr__DOT__core__DOT__nextP = start_addr; + if (main_time > 10) { + top.reset = 0; + // The Verilog reset vector is hardwired to 0x1000 (see RESETVECTOR + // in common.vh), which clobbers any --start address once the reset + // block de-asserts. Override adr_o at the first post-reset cycle so + // --start=N redirects the first instruction fetch. + if (main_time == 11) + top.rootp->Tenyr__DOT__core__DOT__adr_o = (uint32_t)start_addr; + } + top.eval(); + + int curr_state = top.rootp->Tenyr__DOT__core__DOT__state; + + // Buffer data memory operations at S3. d_stb is high during S5 + // (instruction fetch) and S3 (data access), so checking state==S3 + // distinguishes data from instruction traffic. + if (curr_state == S3 && top.rootp->Tenyr__DOT__d_stb) { + mem_op = top.rootp->Tenyr__DOT__d_wen ? 1 : 0; + mem_addr = top.rootp->Tenyr__DOT__d_adr; + mem_data = top.rootp->Tenyr__DOT__d_wen + ? top.rootp->Tenyr__DOT__d_to_slav + : top.rootp->Tenyr__DOT__d_to_mast; + } + + // Trace at the S6->S0 transition (instruction boundary) + if (curr_state == S0 && prev_state == S6) { + uint32_t insn = top.rootp->Tenyr__DOT__core__DOT__insn; + // nextP is already incremented (PC+1 after fetch); tsim shows + // the pre-fetch PC, so subtract 1 for both IP and register dump. + uint32_t pc = top.rootp->Tenyr__DOT__core__DOT__nextP - 1; + + // Skip the trace for the instruction at 0xffffffff that the + // processor fetches after $finish. tsim's pre_fetch catches + // regs[15] == halt_addr before fetching it, so no trace is + // emitted. In the Verilog, the fetch has already happened, so + // we suppress the trace here. + if (!(insn == 0xffffffffU && finish_pending)) { + trace_instruction(top, insn, pc); + } + } + + // Halt on error/retry signal (checked at every cycle, matching the + // original behaviour where halt = err_i | rty_i). + if (top.reset == 0 && top.rootp->Tenyr__DOT__core__DOT__halt) + break; + + // Halt on $finish instruction (0xffffffff). Only check at the S0 + // boundary (state just entered S0) so the $finish instruction can + // execute through S3 and its data memory access can be traced. + // Uses prev_state BEFORE it is updated below, so the check fires + // only on the S6->S0 transition -- not on the S0->S0 half-cycle. + if (top.reset == 0 && curr_state == S0 && prev_state != S0) { + uint32_t insn = top.rootp->Tenyr__DOT__core__DOT__insn; + if (insn == 0xffffffffU) { + if (!finish_pending) { + // First sighting of $finish: let it execute so we can + // trace its data memory access at S3. + finish_pending = true; + } else { + // Second sighting (the instruction at 0xffffffff that + // $finish branched to): print any buffered data from + // $finish's S3, then halt. + if (mem_op >= 0) { + trace_memaccess(mem_op == 1, mem_addr, mem_data); + mem_op = -1; + } + break; + } + } + } + + prev_state = curr_state; + + if (main_time >= max_periods) break; + main_time++; + } + + top.final(); + return 0; +} diff --git a/hw/verilator/simserial.v b/hw/verilator/simserial.v new file mode 100644 index 000000000..a8ffe79a8 --- /dev/null +++ b/hw/verilator/simserial.v @@ -0,0 +1,20 @@ +`timescale 1ns/10ps + +module SimWrap_simserial( + input clk, input enable, input rw, input reset, + input[31:0] addr, inout[31:0] data +); + parameter BASE = 0; + parameter SIZE = 0; + + wire in_range = (addr >= BASE && addr < SIZE + BASE); + + always @(posedge clk) begin + if (enable && in_range) begin + if (rw) + // Use Verilator to insert a direct C call + $c("putchar(",data,");"); + end + end +endmodule + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 23103d405..28cc58b8a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,6 +13,12 @@ target_include_directories(common PUBLIC .) target_include_directories(common INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(common PUBLIC os_support) +add_library(disasm STATIC + ${CMAKE_SOURCE_DIR}/src/asm.c + ${CMAKE_SOURCE_DIR}/src/obj.c +) +target_link_libraries(disasm PUBLIC common) + add_library(common-pic STATIC $) set_target_properties(common-pic PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(common-pic PUBLIC common) diff --git a/test/compare/vsim/err/bsearch_demo_verilog b/test/compare/vsim/err/bsearch_demo_verilog new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_add_verilator b/test/compare/vsim/err/op_add_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_and_verilator b/test/compare/vsim/err/op_and_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_andn_verilator b/test/compare/vsim/err/op_andn_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_at_verilator b/test/compare/vsim/err/op_at_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_eq_verilator b/test/compare/vsim/err/op_eq_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_gte_verilator b/test/compare/vsim/err/op_gte_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_lsh_verilator b/test/compare/vsim/err/op_lsh_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_lt_verilator b/test/compare/vsim/err/op_lt_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_mult_verilator b/test/compare/vsim/err/op_mult_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_or_verilator b/test/compare/vsim/err/op_or_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_orn_verilator b/test/compare/vsim/err/op_orn_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_pack_verilator b/test/compare/vsim/err/op_pack_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_rsha_verilator b/test/compare/vsim/err/op_rsha_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_rshl_verilator b/test/compare/vsim/err/op_rshl_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_sub_verilator b/test/compare/vsim/err/op_sub_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/op_xor_verilator b/test/compare/vsim/err/op_xor_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/qsort_demo_verilog b/test/compare/vsim/err/qsort_demo_verilog new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_at_rigorous_verilator b/test/compare/vsim/err/run_at_rigorous_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_code_modification_verilator b/test/compare/vsim/err/run_code_modification_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_escapes_verilator b/test/compare/vsim/err/run_escapes_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_increment_set_verilator b/test/compare/vsim/err/run_increment_set_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_jitops_verilator b/test/compare/vsim/err/run_jitops_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_linked_verilator b/test/compare/vsim/err/run_linked_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_longname_verilator b/test/compare/vsim/err/run_longname_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_loop_verilator b/test/compare/vsim/err/run_loop_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_overshift_type0_verilator b/test/compare/vsim/err/run_overshift_type0_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_overshift_type1_verilator b/test/compare/vsim/err/run_overshift_type1_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_overshift_type2_verilator b/test/compare/vsim/err/run_overshift_type2_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_precedence_verilator b/test/compare/vsim/err/run_precedence_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_px_verilator b/test/compare/vsim/err/run_px_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_reloc_maths_verilator b/test/compare/vsim/err/run_reloc_maths_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_reloc_pass_verilator b/test/compare/vsim/err/run_reloc_pass_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_reloc_special_verilator b/test/compare/vsim/err/run_reloc_special_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_reloc_verilator b/test/compare/vsim/err/run_reloc_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_selfmod_verilator b/test/compare/vsim/err/run_selfmod_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_strings_verilator b/test/compare/vsim/err/run_strings_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_sugar2_verilator b/test/compare/vsim/err/run_sugar2_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_sugar_verilator b/test/compare/vsim/err/run_sugar_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_unary_verilator b/test/compare/vsim/err/run_unary_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/run_zero_verilator b/test/compare/vsim/err/run_zero_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/trailz_demo_verilog b/test/compare/vsim/err/trailz_demo_verilog new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/err/verilator_failure_bad_magic b/test/compare/vsim/err/verilator_failure_bad_magic new file mode 100644 index 000000000..cca07a59a --- /dev/null +++ b/test/compare/vsim/err/verilator_failure_bad_magic @@ -0,0 +1 @@ +vsim: bad_magic.texe: bad magic (expected TOV) diff --git a/test/compare/vsim/out/bsearch_demo_verilog b/test/compare/vsim/out/bsearch_demo_verilog new file mode 100644 index 000000000..1e8793063 --- /dev/null +++ b/test/compare/vsim/out/bsearch_demo_verilog @@ -0,0 +1,145 @@ +error : not found +one +two +three +error : not found +five +error : not found +error : not found +eight +error : not found +error : not found +error : not found +error : not found +thirteen +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +twenty-one +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +thirty-four +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +fifty-five +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +eighty-nine +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +error : not found +one hundred forty-four diff --git a/test/compare/vsim/out/op_add_verilator b/test/compare/vsim/out/op_add_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_and_verilator b/test/compare/vsim/out/op_and_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_andn_verilator b/test/compare/vsim/out/op_andn_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_at_verilator b/test/compare/vsim/out/op_at_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_eq_verilator b/test/compare/vsim/out/op_eq_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_gte_verilator b/test/compare/vsim/out/op_gte_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_lsh_verilator b/test/compare/vsim/out/op_lsh_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_lt_verilator b/test/compare/vsim/out/op_lt_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_mult_verilator b/test/compare/vsim/out/op_mult_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_or_verilator b/test/compare/vsim/out/op_or_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_orn_verilator b/test/compare/vsim/out/op_orn_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_pack_verilator b/test/compare/vsim/out/op_pack_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_rsha_verilator b/test/compare/vsim/out/op_rsha_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_rshl_verilator b/test/compare/vsim/out/op_rshl_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_sub_verilator b/test/compare/vsim/out/op_sub_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/op_xor_verilator b/test/compare/vsim/out/op_xor_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/qsort_demo_verilog b/test/compare/vsim/out/qsort_demo_verilog new file mode 100644 index 000000000..77661227b --- /dev/null +++ b/test/compare/vsim/out/qsort_demo_verilog @@ -0,0 +1,11 @@ +one +two +three +five +eight +thirteen +twenty-one +thirty-four +fifty-five +eighty-nine +one hundred forty-four diff --git a/test/compare/vsim/out/run_at_rigorous_verilator b/test/compare/vsim/out/run_at_rigorous_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_code_modification_verilator b/test/compare/vsim/out/run_code_modification_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_escapes_verilator b/test/compare/vsim/out/run_escapes_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_increment_set_verilator b/test/compare/vsim/out/run_increment_set_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_jitops_verilator b/test/compare/vsim/out/run_jitops_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_linked_verilator b/test/compare/vsim/out/run_linked_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_longname_verilator b/test/compare/vsim/out/run_longname_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_loop_verilator b/test/compare/vsim/out/run_loop_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_overshift_type0_verilator b/test/compare/vsim/out/run_overshift_type0_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_overshift_type1_verilator b/test/compare/vsim/out/run_overshift_type1_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_overshift_type2_verilator b/test/compare/vsim/out/run_overshift_type2_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_precedence_verilator b/test/compare/vsim/out/run_precedence_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_px_verilator b/test/compare/vsim/out/run_px_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_reloc_maths_verilator b/test/compare/vsim/out/run_reloc_maths_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_reloc_pass_verilator b/test/compare/vsim/out/run_reloc_pass_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_reloc_special_verilator b/test/compare/vsim/out/run_reloc_special_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_reloc_verilator b/test/compare/vsim/out/run_reloc_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_selfmod_verilator b/test/compare/vsim/out/run_selfmod_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_strings_verilator b/test/compare/vsim/out/run_strings_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_sugar2_verilator b/test/compare/vsim/out/run_sugar2_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_sugar_verilator b/test/compare/vsim/out/run_sugar_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_unary_verilator b/test/compare/vsim/out/run_unary_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/run_zero_verilator b/test/compare/vsim/out/run_zero_verilator new file mode 100644 index 000000000..e69de29bb diff --git a/test/compare/vsim/out/trailz_demo_verilog b/test/compare/vsim/out/trailz_demo_verilog new file mode 100644 index 000000000..d8c96a9fa --- /dev/null +++ b/test/compare/vsim/out/trailz_demo_verilog @@ -0,0 +1,33 @@ +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good +good diff --git a/test/compare/vsim/out/verilator_failure_bad_magic b/test/compare/vsim/out/verilator_failure_bad_magic new file mode 100644 index 000000000..e69de29bb diff --git a/tests.cmake b/tests.cmake index 5771b31e2..8891606b0 100644 --- a/tests.cmake +++ b/tests.cmake @@ -573,6 +573,63 @@ foreach(stem ${icarus_stems}) endforeach() +# --------------------------------------------------------------------------- +# Verilated (vsim) simulator tests. +# +# vsim uses an in-process loader (load_tofile) with no VPI and no end-state +# dump, so it can only mirror tsim/vvp where the program's observable effect +# is serial output or a loader rejection -- not the register end-state dumps +# that the run_*/op_* benchmarks rely on (-p tsim.dump_end_state=1 / +DUMPENDSTATE). +# * run_* benchmarks and op_* opcode programs have no serial output: vsim +# asserts they execute cleanly (exit 0, no spurious output) -- a smoke +# guard against the Verilog core crashing/hanging/diverging. +# * ex/ demos (bsearch, qsort, trailz) print serial output: vsim goldens +# match tsim's serial output byte-for-byte (see ex/CMakeLists.txt). +# * bad_magic: vsim's loader rejects a corrupt TOV header (WILL_FAIL). +# * Toolarge is excluded: vsim's loader hangs on it (no size cap). +# * reloc_* are excluded: they need end-state/relocation semantics vsim lacks. +# * SDL runs are excluded (vsim has no framebuffer). +# +# vsim itself is built by `cmake --build` (hw/verilator: add_custom_target(vsim +# ALL)); these tests assume the binary is present, matching how tsim/vvp tests +# assume their binaries are pre-built. +if(VERILATOR) + set(VSIM ${CMAKE_BINARY_DIR}/hw/verilator/vsim) + + # Mirror the run_* program tests (smoke: clean run, deterministic output). + set(VSIM_RUNS ${RUNS}) + list(REMOVE_ITEM VSIM_RUNS ${SDL_RUNS}) + foreach(run_path ${VSIM_RUNS}) + get_filename_component(run "${run_path}" NAME_WLE) + check_std_outputs( + NAME "run ${run} verilator" + COMMAND ${VSIM} + INPUT "${run}.texe" + PROPERTIES TIMEOUT 60 + ) + endforeach() + + # Mirror the op_* opcode tests (smoke). + foreach(op_path ${OPS}) + get_filename_component(op "${op_path}" NAME_WLE) + check_std_outputs( + NAME "op ${op} verilator" + COMMAND ${VSIM} + INPUT "${op}.texe" + PROPERTIES TIMEOUT 60 + ) + endforeach() + + # Mirror bad_magic: vsim rejects a corrupt image. toolarge is excluded + # (vsim's loader hangs on it). + check_std_outputs( + NAME "verilator failure bad_magic" + COMMAND ${VSIM} + INPUT "bad_magic.texe" + PROPERTIES WILL_FAIL TRUE + ) +endif() + add_test( NAME "tld_stdin_accepted" COMMAND sh -c "${CMAKE_TENYR_LINKER} - < ${CMAKE_SOURCE_DIR}/test/misc/obj/empty.to"