diff --git a/rtl/vproc_top.sv b/rtl/vproc_top.sv index 36ffa4d7..1e284971 100644 --- a/rtl/vproc_top.sv +++ b/rtl/vproc_top.sv @@ -24,6 +24,10 @@ module vproc_top import vproc_pkg::*; #( input logic mem_rvalid_i, input logic mem_err_i, input logic [MEM_W -1:0] mem_rdata_i, +`ifdef VPROC_SIMULATION + output logic uart_we_o, + output logic [7:0] uart_data_o, +`endif output logic [31:0] pend_vreg_wr_map_o ); @@ -710,4 +714,15 @@ module vproc_top import vproc_pkg::*; #( (imem_req_addr[0][$clog2(MEM_W)-1:0] & {3'b000, {($clog2(MEM_W/8)-2){1'b1}}, 2'b00})*8 +: 32]; assign dmem_rdata = mem_rdata_i; + // Additional UART logic for simulation with caches + // During simulation, we need to read and write from UART + // Since it's a simple simulation, when the status registers of UART never changes + // Then, after setting the initial value correctly, nothing needs to be done + // However, for writes, we need to correctly handle these access as non-cacheable + // Thus, we bypass the cache and send then directly to vproc_tb.sv and verilator_main.cpp +`ifdef VPROC_SIMULATION + assign uart_we_o = data_req & data_we & (data_addr == 32'hFF000000); + assign uart_data_o = data_wdata[7:0]; // only the lowest byte +`endif + endmodule diff --git a/sim/Makefile b/sim/Makefile index f2569cce..84a45730 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -62,19 +62,19 @@ verilator-version-check: verilator: verilator-version-check $(PROJ_DIR)/obj_dir/Vvproc_top.mk make -C $(PROJ_DIR)/obj_dir -f Vvproc_top.mk Vvproc_top; \ $(PROJ_DIR)/obj_dir/Vvproc_top $(abspath $(PROG_PATHS)) $(MEM_W) \ - $(MEM_SZ) $(MEM_LATENCY) $$(($(VREG_W) * 2)) $(abspath $(TRACE_FILE)) \ + $(MEM_SZ) $(MEM_LATENCY) $$(($(VREG_W) * 2)) $(VREG_W) $(abspath $(TRACE_FILE)) \ $(abspath $(TRACE_VCD)) $(abspath $(TRACE_FST)) $(PROJ_DIR)/obj_dir/Vvproc_top.mk: verilator-version-check $(VPROC_CONFIG_PKG) cp $(SIM_DIR)/verilator_main.cpp $(PROJ_DIR)/ cd $(PROJ_DIR); \ - options=""; \ + options="-DVPROC_SIMULATION"; \ cflags=""; \ if [ -n "$(TRACE_VCD)" ]; then \ - options="--trace"; \ + options="$$options --trace"; \ cflags="-CFLAGS -DTRACE_VCD"; \ elif [ -n "$(TRACE_FST)" ]; then \ - options="--trace-fst"; \ + options="$$options --trace-fst"; \ cflags="-CFLAGS -DTRACE_FST"; \ fi; \ if [ -n "$(SIM_ABORT_CYCLES)" ]; then \ diff --git a/sim/verilator_main.cpp b/sim/verilator_main.cpp index 66588789..c93188c5 100644 --- a/sim/verilator_main.cpp +++ b/sim/verilator_main.cpp @@ -24,12 +24,12 @@ typedef int VerilatedTrace_t; static void log_cycle(Vvproc_top *top, VerilatedTrace_t *tfp, FILE *fcsv); int main(int argc, char **argv) { - if (argc != 7 && argc != 8) { - fprintf(stderr, "Usage: %s PROG_PATHS_LIST MEM_W MEM_SZ MEM_LATENCY EXTRA_CYCLES TRACE_FILE [WAVEFORM_FILE]\n", argv[0]); + if (argc != 8 && argc != 9) { + fprintf(stderr, "Usage: %s PROG_PATHS_LIST MEM_W MEM_SZ MEM_LATENCY EXTRA_CYCLES VLEN TRACE_FILE [WAVEFORM_FILE]\n", argv[0]); return 1; } - int mem_w, mem_sz, mem_latency, extra_cycles; + int mem_w, mem_sz, mem_latency, extra_cycles, vlen; { char *endptr; mem_w = strtol(argv[2], &endptr, 10); @@ -52,6 +52,11 @@ int main(int argc, char **argv) { fprintf(stderr, "ERROR: invalid EXTRA_CYCLES argument\n"); return 1; } + vlen = strtol(argv[6], &endptr, 10); + if (*endptr != 0) { + fprintf(stderr, "ERROR: invalid VLEN argument\n"); + return 1; + } } Verilated::traceEverOn(true); @@ -63,9 +68,9 @@ int main(int argc, char **argv) { return 2; } - FILE *fcsv = fopen(argv[6], "w"); + FILE *fcsv = fopen(argv[7], "w"); if (fcsv == NULL) { - fprintf(stderr, "ERROR: opening `%s': %s\n", argv[6], strerror(errno)); + fprintf(stderr, "ERROR: opening `%s': %s\n", argv[7], strerror(errno)); return 2; } fprintf(fcsv, "rst_ni;mem_req;mem_addr;pend_vreg_wr_map_o;\n"); @@ -82,10 +87,10 @@ int main(int argc, char **argv) { Vvproc_top *top = new Vvproc_top; VerilatedTrace_t *tfp = NULL; #if defined(TRACE_VCD) || defined(TRACE_FST) - if (argc == 8) { + if (argc == 9) { tfp = new VerilatedTrace_t; top->trace(tfp, 99); // Trace 99 levels of hierarchy - tfp->open(argv[7]); + tfp->open(argv[8]); } #endif @@ -209,22 +214,30 @@ int main(int argc, char **argv) { mem_rdata_queue[0] |= ((int64_t)mem[addr+i]) << (i*8); } } + // Cache access to the UART else if (top->mem_req_o) { // test for memory-mapped registers in case of a request for an invalid addr - switch (addr) { + switch (top->mem_addr_o) { case 0xFF000000u: // UART data register valid = true; mem_rdata_queue[0] = -1; // always reads as -1, i.e. no data received - if (top->mem_we_o) { - putc(top->mem_wdata_o & 0xFF, stdout); - } break; case 0xFF000004u: // UART status register valid = true; mem_rdata_queue[0] = 0; // always ready to transmit break; + default: + if((top->mem_addr_o & ~(vlen/8 - 1)) == 0xFF000000u) { + valid = true; + mem_rdata_queue[0] = -1; + } + break; } } + // Print bypassed UART data + if (top->uart_we_o) { + putc(top->uart_data_o, stdout); + } mem_rvalid_queue[0] = top->mem_req_o; mem_err_queue [0] = !valid; diff --git a/sim/vproc_tb.sv b/sim/vproc_tb.sv index 625ea6e2..435b1043 100644 --- a/sim/vproc_tb.sv +++ b/sim/vproc_tb.sv @@ -31,6 +31,8 @@ module vproc_tb #( logic mem_rvalid; logic mem_err; logic [31:0] mem_rdata; + logic uart_we; + logic [7:0] uart_data; vproc_top #( .MEM_W ( MEM_W ), @@ -52,6 +54,8 @@ module vproc_tb #( .mem_rvalid_i ( mem_rvalid ), .mem_err_i ( mem_err ), .mem_rdata_i ( mem_rdata ), + .uart_we_o ( uart_we ), + .uart_data_o ( uart_data ), .pend_vreg_wr_map_o ( ) );