diff --git a/CMake/add_test.cmake b/CMake/add_test.cmake index d0e1b5f..0adad6d 100644 --- a/CMake/add_test.cmake +++ b/CMake/add_test.cmake @@ -45,7 +45,7 @@ macro(add_unit_test TEST_NAME) #Add Test add_test(NAME ${TEST_NAME} - COMMAND ${MODEL_DIR}/verilated_model ${BUILD_DIR}/vector-tests/prog_${TEST_NAME}.txt 32 4194304 ${MEM_LATENCY} 1 ${TEST_NAME} ${VREG_W} ${TEST_CASE_NUM} ${VCD_TRACE_ARGS} + COMMAND ${MODEL_DIR}/verilated_model ${BUILD_DIR}/vector-tests/prog_${TEST_NAME}.txt ${MEM_PORTS} ${MEM_W} 4194304 ${MEM_LATENCY} 1 ${TEST_NAME} ${VREG_W} ${TEST_CASE_NUM} ${VCD_TRACE_ARGS} WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) message(STATUS "Successfully added ${TEST_NAME}") @@ -142,7 +142,8 @@ macro(add_legacy_test TEST_NAME) COMMAND echo -n "${TEST_BUILD_PATH}/${TEST_NAME}_result.txt " >> prog_${TEST_NAME}.txt COMMAND readelf -s ${folder}-${TEST_NAME}.elf | sed '2,13 s/ //1' | grep vdata_start | cut -d " " -f 6 | tr [=["\n"]=] " " >> prog_${TEST_NAME}.txt COMMAND readelf -s ${folder}-${TEST_NAME}.elf | sed '2,13 s/ //1' | grep vdata_end | cut -d " " -f 6 | tr [=["\n"]=] " " >> prog_${TEST_NAME}.txt - COMMAND ${CMAKE_OBJDUMP} -D ${folder}-${TEST_NAME}.elf > ${TEST_NAME}_dump.txt) + COMMAND ${CMAKE_OBJDUMP} -D ${folder}-${TEST_NAME}.elf > ${TEST_NAME}_dump.txt + ) #If trace option is selected, provide the paths for the .csv and .vcd trace files. Due to argument parsing in verilator_main.cpp, both must be provided diff --git a/CMake/run_legacy_test.cmake b/CMake/run_legacy_test.cmake index 9d18148..f0e663a 100644 --- a/CMake/run_legacy_test.cmake +++ b/CMake/run_legacy_test.cmake @@ -3,7 +3,7 @@ #For reuse, provide the direct path to the files for VERILATED_DIR and BUILD_DIR #Provide the paths for the mem_trace .csv and signal trace .vcd as XXX_TRACE_ARGS to get those outputs. #For test case counting, set argument to 1 for compliance with chipsalliance -execute_process(COMMAND ${VERILATED_DIR}/verilated_model ${BUILD_DIR}/prog_${TEST_NAME}.txt ${MEM_W} 4194304 ${MEM_LATENCY} 1 ${TEST_NAME} ${VREG_W} 1 ${VCD_TRACE_ARGS} +execute_process(COMMAND ${VERILATED_DIR}/verilated_model ${BUILD_DIR}/prog_${TEST_NAME}.txt ${MEM_PORTS} ${MEM_W} 4194304 ${MEM_LATENCY} 1 ${TEST_NAME} ${VREG_W} 1 ${VCD_TRACE_ARGS} RESULT_VARIABLE RETURN_SIM) execute_process(COMMAND diff ${BUILD_DIR}/${TEST_NAME}_result.txt ${BUILD_DIR}/${TEST_NAME}_reference.txt RESULT_VARIABLE RETURN_DIFF) diff --git a/CMake/run_test.cmake b/CMake/run_test.cmake index 51b14d3..c6d7e29 100644 --- a/CMake/run_test.cmake +++ b/CMake/run_test.cmake @@ -2,7 +2,7 @@ #All variables must be passed in from the Add_Tests COMMAND argument #For reuse, provide the direct path to the files for VERILATED_DIR and BUILD_DIR #Provide the paths for the mem_trace .csv and signal trace .vcd as XXX_TRACE_ARGS to get those outputs. -execute_process(COMMAND ${VERILATED_DIR}/verilated_model ${BUILD_DIR}/prog_${TEST_NAME}.txt ${MEM_W} 4194304 ${MEM_LATENCY} 1 ${TEST_NAME} ${VREG_W} ${VCD_TRACE_ARGS} +execute_process(COMMAND ${VERILATED_DIR}/verilated_model ${BUILD_DIR}/prog_${TEST_NAME}.txt ${MEM_PORTS} ${MEM_W} 4194304 ${MEM_LATENCY} 1 ${TEST_NAME} ${VREG_W} ${VCD_TRACE_ARGS} RESULT_VARIABLE RETURN_SIM) if(RETURN_SIM) diff --git a/build_model/CMakeLists.txt b/build_model/CMakeLists.txt index d1d1733..e47e9ec 100644 --- a/build_model/CMakeLists.txt +++ b/build_model/CMakeLists.txt @@ -27,6 +27,8 @@ set(CMAKE_CXX_STANDARD 14) option(TRACE "Enable minimal VCD trace outputs" OFF) option(TRACE_FULL "Enable FULL VCD trace outputs" OFF) #TODO: prevent this option from being cached, force user to always manually enable it +option(OLD_VICUNA "Old vicuna without vl abort" ON) +option(FORCE_ALIGNED_READS "Forces aligned reads for cv32 and vproc" ON) ######## ## Import RTL configuration from here instead of command line. @@ -37,9 +39,13 @@ message("Selected SCALAR_CORE = ${SCALAR_CORE}") set(ENV{VPROC_PIPELINES} ${VPROC_PIPELINES}) message("Selected VPROC_PIPELINES = ${VPROC_PIPELINES}") message("Selected RISCV_ARCH = ${RISCV_ARCH}") +set(ENV{VREG_W} ${VREG_W}) message("Selected VREG_W = ${VREG_W}") set(MEM_W ${VMEM_W}) +set(ENV{MEM_W} ${VMEM_W}) message("Selected MEM_W = ${MEM_W}") +set(MEM_PORTS ${VMEM_PORTS}) +message("Selected MEM_PORTS = ${MEM_PORTS}") set(MEM_SZ 4194304) @@ -401,7 +407,7 @@ if(TRACE) set(TRACE TRACE) if(TRACE_FULL) - set(TRACE_FLAG ) #no --trace-depth flag defaults to entire model + set(TRACE_FLAG --trace-structs) #no --trace-depth flag defaults to entire model else() set(TRACE_FLAG --trace-depth 2) endif() @@ -446,7 +452,7 @@ if ( ${SCALAR_CORE} STREQUAL "cv32e40x" ) #+define+COREV_ASSERT_OFF #Fixes UVM error with CV32E40X (Needed when not using -DVPROC_SVA) ${TRACE_FLAG} --assert -DVPROC_SVA - -GMEM_W=${MEM_W} -GVMEM_W=${VMEM_W} + -GMEM_W=${MEM_W} -GVMEM_W=${VMEM_W} -GMEM_PORTS=${MEM_PORTS} ${VICUNA_MODE} ${READ_MODE} ${XIF_FLAG} diff --git a/build_model/cv32e40x/verilator_main.cpp b/build_model/cv32e40x/verilator_main.cpp index 77d7d60..ebeb1c3 100644 --- a/build_model/cv32e40x/verilator_main.cpp +++ b/build_model/cv32e40x/verilator_main.cpp @@ -20,35 +20,40 @@ int main(int argc, char **argv) { ////////////////////////// //Check validity and parse input arguments ////////////////////////// - if (argc != 9 && argc != 10) { - fprintf(stderr, "ERROR: Correct Usage: %s PROG_PATHS_LIST MEM_W MEM_SZ MEM_LATENCY EXTRA_CYCLES TEST_NAME VREG_W NUM_TEST_CASES [WAVEFORM_FILE]\n", argv[0]); + if (argc != 10 && argc != 11) { + fprintf(stderr, "ERROR: Correct Usage: %s PROG_PATHS_LIST MEM_PORTS MEM_W MEM_SZ MEM_LATENCY EXTRA_CYCLES TEST_NAME VREG_W NUM_TEST_CASES [WAVEFORM_FILE]\n", argv[0]); return 1; } - int mem_w, mem_sz, mem_latency, extra_cycles, num_cases; + int mem_ports, mem_w, mem_sz, mem_latency, extra_cycles, num_cases; { char *endptr; - mem_w = strtol(argv[2], &endptr, 10); + mem_ports = strtol(argv[2], &endptr, 10); + if (mem_ports == 0 || *endptr != 0) { + fprintf(stderr, "ERROR: invalid MEM_PORTS argument\n"); + return 1; + } + mem_w = strtol(argv[3], &endptr, 10); if (mem_w == 0 || *endptr != 0) { fprintf(stderr, "ERROR: invalid MEM_W argument\n"); return 1; } - mem_sz = strtol(argv[3], &endptr, 10); + mem_sz = strtol(argv[4], &endptr, 10); if (mem_sz == 0 || *endptr != 0) { fprintf(stderr, "ERROR: invalid MEM_SZ argument\n"); return 1; } - mem_latency = strtol(argv[4], &endptr, 10); + mem_latency = strtol(argv[5], &endptr, 10); if (*endptr != 0) { fprintf(stderr, "ERROR: invalid MEM_LATENCY argument\n"); return 1; } - extra_cycles = strtol(argv[5], &endptr, 10); + extra_cycles = strtol(argv[6], &endptr, 10); if (*endptr != 0) { fprintf(stderr, "ERROR: invalid EXTRA_CYCLES argument\n"); return 1; } - num_cases = strtol(argv[8], &endptr, 10); + num_cases = strtol(argv[9], &endptr, 10); if (*endptr != 0) { fprintf(stderr, "ERROR: invalid NUM_TEST_CASES argument\n"); return 1; @@ -70,29 +75,35 @@ int main(int argc, char **argv) { ////////////////////////// /*Log File for Scalar Registers*/ - std::string filename=(std::string(argv[6])+std::string("_xreg_commits_verilator.txt")); + std::string filename=(std::string(argv[7])+std::string("_xreg_commits_verilator.txt")); FILE *fxreglog = fopen(filename.c_str(), "w"); /*Log File for Vector Registers. Separate log because actual writes to VREGs might be out of order relative to the Xregs. Should NOT be out of order relative to themselves.*/ - filename=(std::string(argv[6])+std::string("_vreg_commits_verilator.txt")); + filename=(std::string(argv[7])+std::string("_vreg_commits_verilator.txt")); FILE *fvreglog = fopen(filename.c_str(), "w"); /*Log File for Scalar Floating Point Registers*/ - filename=(std::string(argv[6])+std::string("_freg_commits_verilator.txt")); + filename=(std::string(argv[7])+std::string("_freg_commits_verilator.txt")); FILE *ffreglog = fopen(filename.c_str(), "w"); ////////////////////////// //Allocate memory latency buffers ////////////////////////// - - bool *mem_rvalid_queue = (bool *)malloc(sizeof(bool) * mem_latency); - unsigned char **mem_rdata_queue = (unsigned char **)malloc(sizeof(unsigned char *) * mem_latency); //memory data port - bool *mem_err_queue = (bool *)malloc(sizeof(bool) * mem_latency); - - for(int queue_pos = 0; queue_pos < mem_latency; queue_pos++) - { - mem_rdata_queue[queue_pos] = (unsigned char *)malloc(sizeof(unsigned char) * mem_w/8); + bool *mem_rvalid_queue[mem_ports]; + unsigned char **mem_rdata_queue[mem_ports]; + bool *mem_err_queue[mem_ports]; + + for(int i = 0; i < mem_ports; i++){ + mem_rvalid_queue[i] = (bool *)malloc(sizeof(bool) * mem_latency); + mem_rdata_queue[i] = (unsigned char **)malloc(sizeof(unsigned char *) * mem_latency); + mem_err_queue[i] = (bool *)malloc(sizeof(bool) * mem_latency); + + for(int queue_pos = 0; queue_pos < mem_latency; queue_pos++) + { + mem_rdata_queue[i][queue_pos] = (unsigned char *)malloc(sizeof(unsigned char) * mem_w/8); + } } + bool *mem_ivalid_queue = (bool *)malloc(sizeof(bool) * mem_latency); unsigned char **mem_idata_queue = (unsigned char **)malloc(sizeof(unsigned char *) * mem_latency); //memory instruction port @@ -100,7 +111,7 @@ int main(int argc, char **argv) { //even though known instruction interface width of 32 bits, malloc like this for compatability with memory management helper functions for(int queue_pos = 0; queue_pos < mem_latency; queue_pos++) { - mem_idata_queue[queue_pos] = (unsigned char *)malloc(sizeof(unsigned char) * 32/8); + mem_idata_queue[queue_pos] = (unsigned char *)malloc(sizeof(unsigned char) * mem_w/8); } Vvproc_top *top = new Vvproc_top; @@ -110,11 +121,11 @@ int main(int argc, char **argv) { //Setup vcd trace file ////////////////////////// VerilatedTrace_t *tfp = NULL; - if (argc == 10) { + if (argc == 11) { #ifdef TRACE_VCD tfp = new VerilatedTrace_t; top->trace(tfp, 99); // Trace 99 levels of hierarchy - tfp->open(argv[9]); + tfp->open(argv[10]); #endif } @@ -161,10 +172,12 @@ int main(int argc, char **argv) { ////////////////////////// int i; - for (i = 0; i < mem_latency; i++) { - mem_rvalid_queue[i] = 0; + for(int j = 0; j < mem_ports; j++){ + for (i = 0; i < mem_latency; i++) { + mem_rvalid_queue[j][i] = 0; + } + top->mem_rvalid_i[j] = 0; } - top->mem_rvalid_i = 0; top->mem_irvalid_i = 0; top->clk_i = 0; top->rst_ni = 0; @@ -187,7 +200,7 @@ int main(int argc, char **argv) { char *endptr; - int vreg_w = strtol(argv[7], &endptr, 10); + int vreg_w = strtol(argv[8], &endptr, 10); int cycles_begin_trace = 0; //Traces begin at this cycle count. TODO: expose to the command line int cycles_end_trace = 0; //Traces end at thsi cycle count. TODO: expose to the command line @@ -215,14 +228,15 @@ int main(int argc, char **argv) { ////////////////////////// //Update Memory interfaces ////////////////////////// - - //Update write interface - + for(int i = 0; i < mem_ports; i++){ + //Update write interface //Update read interface TODO - STALL IF (top->mem_req_o && !top->mem_we_o). Original Vicuna also did not contain this condition TODO: MEM_REQ_VALID NEEDS TO BE SIGNALLED for writes - update_mem_load(top->mem_addr_o, (top->mem_req_o && !top->mem_we_o), mem_w, mem_latency, mem_sz, (unsigned char*)&(top->mem_rdata_i), (bool*)&(top->mem_rvalid_i), (bool*)&(top->mem_err_i), mem_rdata_queue, mem_rvalid_queue, mem_err_queue, mem); - update_mem_write(top->mem_addr_o, (top->mem_req_o && top->mem_we_o), mem_w, mem_latency, mem_sz, (unsigned char*)&(top->mem_wdata_o), (unsigned char*)&(top->mem_be_o), mem_rvalid_queue, mem_err_queue, mem); + update_mem_load(top->mem_addr_o[i], (top->mem_req_o[i] && !top->mem_we_o[i]), mem_w, mem_latency, mem_sz, (unsigned char*)&(top->mem_rdata_i[i]), (bool*)&(top->mem_rvalid_i[i]), (bool*)&(top->mem_err_i[i]), mem_rdata_queue[i], mem_rvalid_queue[i], mem_err_queue[i], mem); + update_mem_write(top->mem_addr_o[i], (top->mem_req_o[i] && top->mem_we_o[i]), mem_w, mem_latency, mem_sz, (unsigned char*)&(top->mem_wdata_o[i]), (unsigned char*)&(top->mem_be_o[i]), mem_rvalid_queue[i], mem_err_queue[i], mem); + } + //Update instruction memory interface - update_mem_load(top->mem_iaddr_o, top->mem_ireq_o, 32, mem_latency, mem_sz, (unsigned char*)&(top->mem_irdata_i), (bool*)&(top->mem_irvalid_i), (bool*)&(top->mem_ierr_i), mem_idata_queue, mem_ivalid_queue, mem_ierr_queue, mem); + update_mem_load(top->mem_iaddr_o, top->mem_ireq_o, mem_w, mem_latency, mem_sz, (unsigned char*)&(top->mem_irdata_i), (bool*)&(top->mem_irvalid_i), (bool*)&(top->mem_ierr_i), mem_idata_queue, mem_ivalid_queue, mem_ierr_queue, mem); top->eval(); @@ -236,7 +250,7 @@ int main(int argc, char **argv) { //Use memory mapped IO at address 0x400 to signal success or failure char w_port; - if (check_memmapio(top->mem_addr_o, (top->mem_req_o && top->mem_we_o), 8, (unsigned char*)&(top->mem_wdata_o), 0x00000400u, &w_port)){ + if (check_memmapio(top->mem_addr_o[0], (top->mem_req_o[0] && top->mem_we_o[0]), 8, (unsigned char*)&(top->mem_wdata_o[0]), 0x00000400u, &w_port)){ if (w_port == 0) { fprintf(stderr, "SUCCESS: TEST PASS - TEST %d - Output Match\n", v_test_failure+v_test_success+2); @@ -323,15 +337,21 @@ int main(int argc, char **argv) { free(dump_path); free(line); free(mem); - free(mem_rvalid_queue); + for(int i = 0; i < mem_ports; i++){ + free(mem_rvalid_queue[i]); + for(int queue_pos = 0; queue_pos < mem_latency; queue_pos++) + { + free(mem_rdata_queue[i][queue_pos]); + } + free(mem_rdata_queue[i]); + free(mem_err_queue[i]); + } + for(int queue_pos = 0; queue_pos < mem_latency; queue_pos++) { - free(mem_rdata_queue[queue_pos]); - free(mem_idata_queue[queue_pos]); + free(mem_idata_queue[queue_pos]); } - free(mem_rdata_queue); free(mem_idata_queue); - free(mem_err_queue); fclose(fprogs); fclose(fxreglog); diff --git a/build_model/cv32e40x/vproc_top.sv b/build_model/cv32e40x/vproc_top.sv index 7a519dc..7ae357a 100644 --- a/build_model/cv32e40x/vproc_top.sv +++ b/build_model/cv32e40x/vproc_top.sv @@ -3,23 +3,29 @@ // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 -module vproc_top import vproc_pkg::*; #( +module vproc_top import vproc_pkg::*, obi_pkg::*; #( + parameter int unsigned ADDR_W = 32, // memory bus width in bits parameter int unsigned MEM_W = 32, // memory bus width in bits parameter int unsigned VMEM_W = 32, // vector memory interface width in bits + parameter int unsigned OBI_ID_WIDTH = 8, // vector memory interface width in bits + parameter int unsigned MEM_PORTS = 1, + parameter int unsigned PORT_QUEUE_DEPTH = 2, parameter vreg_type VREG_TYPE = VREG_GENERIC, parameter mul_type MUL_TYPE = MUL_GENERIC )( input logic clk_i, input logic rst_ni, - output logic mem_req_o, - output logic [31:0] mem_addr_o, - output logic mem_we_o, - output logic [MEM_W/8-1:0] mem_be_o, - output logic [MEM_W -1:0] mem_wdata_o, - input logic mem_rvalid_i, - input logic mem_err_i, - input logic [MEM_W -1:0] mem_rdata_i, + output logic mem_req_o [MEM_PORTS-1:0], + output logic [31:0] mem_addr_o [MEM_PORTS-1:0], + output logic mem_we_o [MEM_PORTS-1:0], + output logic [MEM_W/8-1:0] mem_be_o [MEM_PORTS-1:0], + output logic [MEM_W -1:0] mem_wdata_o [MEM_PORTS-1:0], + output logic mem_aid_o [MEM_PORTS-1:0], + input logic mem_rvalid_i [MEM_PORTS-1:0], + input logic mem_err_i [MEM_PORTS-1:0], + input logic [MEM_W -1:0] mem_rdata_i [MEM_PORTS-1:0], + input logic mem_rid_i [MEM_PORTS-1:0], output logic [31:0] pend_vreg_wr_map_o, @@ -27,10 +33,9 @@ module vproc_top import vproc_pkg::*; #( output logic [31:0] mem_iaddr_o, input logic mem_irvalid_i, input logic mem_ierr_i, - input logic [32 -1:0] mem_irdata_i + input logic [MEM_W-1:0] mem_irdata_i ); - if ((MEM_W & (MEM_W - 1)) != 0 || MEM_W < 32) begin $fatal(1, "The memory bus width MEM_W must be at least 32 and a power of two. ", "The current value of %d is invalid.", MEM_W); @@ -87,6 +92,12 @@ module vproc_top import vproc_pkg::*; #( .X_RFW_WIDTH ( X_RFW_WIDTH ), .X_MISA ( X_MISA ) ) vcore_xif (); + + localparam OBI_CFG = obi_default_cfg(ADDR_W, VMEM_W, OBI_ID_WIDTH, ObiMinimalOptionalConfig); + OBI_BUS #( + .OBI_CFG ( OBI_CFG ) + ) vcore_obi_bus [MEM_PORTS-1:0] (); + logic vect_pending_load; logic vect_pending_store; @@ -290,21 +301,21 @@ module vproc_top import vproc_pkg::*; #( // Data read/write for Vector Unit - logic vdata_gnt; - logic vdata_rvalid; - logic vdata_err; - logic [VMEM_W-1:0] vdata_rdata; - logic vdata_req; - logic [31:0] vdata_addr; - logic vdata_we; - logic [VMEM_W/8-1:0] vdata_be; - logic [VMEM_W-1:0] vdata_wdata; - logic [X_ID_WIDTH-1:0] vdata_req_id; - logic [X_ID_WIDTH-1:0] vdata_res_id; + logic vdata_gnt [MEM_PORTS-1:0]; + logic vdata_rvalid [MEM_PORTS-1:0]; + logic vdata_err [MEM_PORTS-1:0]; + logic [VMEM_W-1:0] vdata_rdata [MEM_PORTS-1:0]; + logic vdata_req [MEM_PORTS-1:0]; + logic [31:0] vdata_addr [MEM_PORTS-1:0]; + logic vdata_we [MEM_PORTS-1:0]; + logic [VMEM_W/8-1:0] vdata_be [MEM_PORTS-1:0]; + logic [VMEM_W-1:0] vdata_wdata [MEM_PORTS-1:0]; + logic [OBI_ID_WIDTH-1:0] vdata_req_id [MEM_PORTS-1:0]; + logic [OBI_ID_WIDTH-1:0] vdata_res_id [MEM_PORTS-1:0]; // Allow for vector loads/stores to be misaligned with respect to VMEM_W - `ifdef FORCE_ALIGNED_READS - localparam bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = (VLSU_FLAGS_W'(1) << VLSU_ALIGNED_UNITSTRIDE); + `ifdef FORCE_ALIGNED_READS // not needed anymore since scratch is aligning already + localparam bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = (VLSU_FLAGS_W'(0) << VLSU_ALIGNED_UNITSTRIDE); `else localparam bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = (VLSU_FLAGS_W'(0) << VLSU_ALIGNED_UNITSTRIDE); `endif @@ -319,6 +330,9 @@ module vproc_top import vproc_pkg::*; #( .MUL_TYPE ( MUL_TYPE ), .VLSU_FLAGS ( VLSU_FLAGS ), .BUF_FLAGS ( BUF_FLAGS ), + .OBI_CFG ( OBI_CFG ), + .PORT_QUEUE_DEPTH ( PORT_QUEUE_DEPTH ), + .MEM_PORTS ( MEM_PORTS ), .DONT_CARE_ZERO ( 1'b0 ), .ASYNC_RESET ( 1'b0 ) ) v_core ( @@ -327,9 +341,8 @@ module vproc_top import vproc_pkg::*; #( .xif_issue_if ( vcore_xif ), .xif_commit_if ( vcore_xif ), - .xif_mem_if ( vcore_xif ), - .xif_memres_if ( vcore_xif ), .xif_result_if ( vcore_xif ), + .obi_bus ( vcore_obi_bus ), .pending_load_o ( vect_pending_load ), .pending_store_o ( vect_pending_store ), @@ -360,6 +373,26 @@ module vproc_top import vproc_pkg::*; #( .pend_vreg_wr_map_o ( pend_vreg_wr_map_o ) ); + // TODO: wire id signal from/to aoptional/roptional field from lsu + if (USE_XIF_MEM) begin + assign vcore_xif.mem_valid = vcore_obi_bus[0].req; + assign vcore_obi_bus[0].gnt = vcore_xif.mem_ready; + //assign vcore_xif.mem_req.id = vcore_obi_bus[0].aid; + assign vcore_xif.mem_req.addr = vcore_obi_bus[0].addr; + assign vcore_xif.mem_req.mode = '0; + assign vcore_xif.mem_req.we = vcore_obi_bus[0].we; + //assign vcore_xif.mem_req.size; //TODO: get size + assign vcore_xif.mem_req.be = vcore_obi_bus[0].be; + assign vcore_xif.mem_req.attr = '0; + assign vcore_xif.mem_req.wdata = vcore_obi_bus[0].wdata; + //assign vcore_xif.mem_req.last; //TODO: get last + assign vcore_xif.mem_req.spec = '0; + assign vcore_obi_bus[0].rvalid = vcore_xif.mem_result_valid; + //assign vcore_obi_bus[0].rid = vcore_xif.mem_result.id; + assign vcore_obi_bus[0].rdata = vcore_xif.mem_result.rdata; + assign vcore_obi_bus[0].err = vcore_xif.mem_result.err; + end + `endif @@ -762,98 +795,149 @@ module vproc_top import vproc_pkg::*; #( assign vdata_wdata = '0; assign vdata_req_id = '0; end else begin - assign vdata_req = vcore_xif.mem_valid; - assign vcore_xif.mem_ready = 1'b1; //mem always ready in this configuration - assign vdata_addr = vcore_xif.mem_req.addr; - assign vdata_we = vcore_xif.mem_req.we; - assign vdata_be = vcore_xif.mem_req.be; - assign vdata_wdata = vcore_xif.mem_req.wdata; - assign vdata_req_id = vcore_xif.mem_req.id; - assign vcore_xif.mem_resp.exc = '0; - assign vcore_xif.mem_resp.exccode = '0; - assign vcore_xif.mem_resp.dbg = '0; - assign vcore_xif.mem_result_valid = vdata_rvalid; - assign vcore_xif.mem_result.id = vdata_res_id; - assign vcore_xif.mem_result.rdata = vdata_rdata; - assign vcore_xif.mem_result.err = vdata_err; - assign vcore_xif.mem_result.dbg = '0; + for(genvar i = 0; i < MEM_PORTS; i++) begin + assign vdata_req[i] = vcore_obi_bus[i].req; + assign vcore_obi_bus[i].gnt = vdata_gnt[i]; + assign vdata_addr[i] = vcore_obi_bus[i].addr; + assign vdata_we[i] = vcore_obi_bus[i].we; + assign vdata_be[i] = vcore_obi_bus[i].be; + assign vdata_wdata[i] = vcore_obi_bus[i].wdata; + assign vdata_req_id[i] = vcore_obi_bus[i].aid; + assign vcore_obi_bus[i].rvalid = vdata_rvalid[i]; + assign vcore_obi_bus[i].rid = vdata_res_id[i]; + assign vcore_obi_bus[i].rdata = vdata_rdata[i]; + assign vcore_obi_bus[i].err = vdata_err[i]; + end end // Data arbiter for main core and vector unit logic sdata_hold; - logic data_req; - logic [31:0] data_addr; - logic data_we; - logic [VMEM_W/8-1:0] data_be; - logic [VMEM_W -1:0] data_wdata; - logic data_gnt; - logic data_rvalid; - logic data_err; - logic [VMEM_W -1:0] data_rdata; - logic sdata_waiting, vdata_waiting; + logic data_req [MEM_PORTS-1:0]; + logic [31:0] data_addr [MEM_PORTS-1:0]; + logic data_we [MEM_PORTS-1:0]; + logic [VMEM_W/8-1:0] data_be [MEM_PORTS-1:0]; + logic [VMEM_W -1:0] data_wdata [MEM_PORTS-1:0]; + logic data_gnt [MEM_PORTS-1:0]; + logic data_rvalid [MEM_PORTS-1:0]; + logic data_err [MEM_PORTS-1:0]; + logic [VMEM_W -1:0] data_rdata [MEM_PORTS-1:0]; + logic [OBI_ID_WIDTH-1:0] data_req_id [MEM_PORTS-1:0]; + logic [OBI_ID_WIDTH-1:0] data_res_id [MEM_PORTS-1:0]; + logic sdata_waiting; + logic vdata_waiting; logic [31:0] sdata_wait_addr; - logic [X_ID_WIDTH-1:0] vdata_wait_id; - assign sdata_hold = ~USE_XIF_MEM & (vdata_req | vect_pending_store | (vect_pending_load & sdata_we)); + assign sdata_hold = ~USE_XIF_MEM & (vdata_req[0] | vect_pending_store | (vect_pending_load & sdata_we)); always_comb begin - data_req = vdata_req | (sdata_req & ~sdata_hold); - data_addr = sdata_addr; - data_we = sdata_we; + data_req[0] = vdata_req[0] | (sdata_req & ~sdata_hold); + data_addr[0] = sdata_addr; + data_we[0] = sdata_we; + // TODO: data_req_id[0] = ; for cva core `ifdef FORCE_ALIGNED_READS - data_be = {{(VMEM_W-32){1'b0}}, sdata_be} << (sdata_addr[$clog2(VMEM_W/8)-1:0] & {{$clog2(VMEM_W/32){1'b1}}, 2'b00}); - data_wdata = '0; + data_addr[0] = {sdata_addr[31:$clog2(VMEM_W/8)], {$clog2(VMEM_W/8){1'b0}}}; + data_be[0] = {{(VMEM_W-32){1'b0}}, sdata_be} << (sdata_addr[$clog2(VMEM_W/8)-1:0] & {{$clog2(VMEM_W/32){1'b1}}, 2'b00}); + data_wdata[0] = '0; for (int i = 0; i < VMEM_W / 32; i++) begin - data_wdata[32*i +: 32] = sdata_wdata; + data_wdata[0][32*i +: 32] = sdata_wdata; end `else - data_be = {{(VMEM_W-32){1'b0}}, sdata_be}; - data_wdata = {{(VMEM_W-32){1'b0}}, sdata_wdata}; + data_be[0] = {{(VMEM_W-32){1'b0}}, sdata_be}; + data_wdata[0] = {{(VMEM_W-32){1'b0}}, sdata_wdata}; `endif - if (vdata_req) begin - data_addr = vdata_addr; - data_we = vdata_we; - data_be = vdata_be; - data_wdata = vdata_wdata; + if (vdata_req[0]) begin + data_addr[0] = vdata_addr[0]; + data_we[0] = vdata_we[0]; + data_be[0] = vdata_be[0]; + data_wdata[0] = vdata_wdata[0]; + data_req_id[0] = vdata_req_id[0]; end - end - assign sdata_gnt = data_gnt & sdata_req & ~sdata_hold; - assign vdata_gnt = data_gnt & vdata_req; - always_ff @(posedge clk_i or negedge rst_ni) begin - if (~rst_ni) begin - sdata_waiting <= 1'b0; - vdata_waiting <= 1'b0; - sdata_wait_addr <= '0; - vdata_wait_id <= '0; - end else begin - if (sdata_gnt) begin - sdata_waiting <= 1'b1; - sdata_wait_addr <= sdata_addr; - end - else if (sdata_rvalid) begin - sdata_waiting <= 1'b0; - end - if (vdata_gnt) begin - vdata_waiting <= 1'b1; - vdata_wait_id <= vdata_req_id; - end - else if (vdata_rvalid) begin - vdata_waiting <= 1'b0; - end + for(int i = 1; i < MEM_PORTS; i++) begin + data_req[i] = vdata_req[i]; + data_addr[i] = vdata_addr[i]; + data_we[i] = vdata_we[i]; + data_be[i] = vdata_be[i]; + data_wdata[i] = vdata_wdata[i]; + data_req_id[i] = vdata_req_id[i]; end end - assign sdata_rvalid = sdata_waiting & data_rvalid; - assign vdata_rvalid = vdata_waiting & data_rvalid; - assign sdata_err = data_err; - assign vdata_err = data_err; + assign sdata_gnt = data_gnt[0] & sdata_req & ~sdata_hold; + for(genvar i = 0; i < MEM_PORTS; i++) begin + assign vdata_gnt[i] = data_gnt[i] & vdata_req[i]; + end + + vproc_queue #( + .WIDTH ( $bits(instr_wait_addr) ), + .DEPTH ( 2 ), // cv32 is configured to send out max 2 requests as default + .FLOW ( 1'b1 ) + ) i_wait_id_queue ( + .clk_i ( clk_i ), + .async_rst_ni ( rst_ni ), + .sync_rst_ni ( 1'b1 ), // sync_rst_n + .enq_ready_o ( ), + .enq_valid_i ( imem_gnt ), + .enq_data_i ( instr_addr ), + .deq_ready_i ( imem_rvalid ), + .deq_valid_o ( ), + .deq_data_o ( instr_wait_addr ), + .flags_any_o ( ), + .flags_all_o ( ) + ); + + vproc_queue #( + .WIDTH ( $bits(sdata_wait_addr) ), + .DEPTH ( 2 ), // cv32 is configured to send out max 2 requests as default + .FLOW ( 1'b1 ) + ) s_wait_id_queue ( + .clk_i ( clk_i ), + .async_rst_ni ( rst_ni ), + .sync_rst_ni ( sync_rst_n ), + .enq_ready_o ( ), + .enq_valid_i ( sdata_gnt ), + .enq_data_i ( sdata_addr ), + .deq_ready_i ( sdata_rvalid ), + .deq_valid_o ( sdata_waiting ), + .deq_data_o ( sdata_wait_addr ), + .flags_any_o ( ), + .flags_all_o ( ) + ); + + vproc_queue #( + .WIDTH ( 1 ), + .DEPTH ( PORT_QUEUE_DEPTH ), + .FLOW ( 1'b1 ) + ) v_wait_id_queue ( + .clk_i ( clk_i ), + .async_rst_ni ( 1 ), + .sync_rst_ni ( sync_rst_n ), + .enq_ready_o ( ), + .enq_valid_i ( vdata_gnt[0] ), + .enq_data_i ( ), + .deq_ready_i ( vdata_rvalid[0] ), + .deq_valid_o ( vdata_waiting ), + .deq_data_o ( ), + .flags_any_o ( ), + .flags_all_o ( ) + ); + + assign sdata_rvalid = sdata_waiting & data_rvalid[0]; + assign sdata_err = data_err[0]; + + + assign vdata_rvalid[0] = vdata_waiting & data_rvalid[0]; + assign vdata_err[0] = data_err[0]; + for(genvar i = 1; i < MEM_PORTS; i++) begin + assign vdata_rvalid[i] = data_rvalid[i]; + assign vdata_err[i] = data_err[i]; + end `ifdef FORCE_ALIGNED_READS - assign sdata_rdata = data_rdata[(sdata_wait_addr[$clog2(VMEM_W)-1:0] & {3'b000, {($clog2(VMEM_W/8)-2){1'b1}}, 2'b00})*8 +: 32]; + assign sdata_rdata = data_rdata[0][(sdata_wait_addr[$clog2(VMEM_W)-1:0] & {3'b000, {($clog2(VMEM_W/8)-2){1'b1}}, 2'b00})*8 +: 32]; `else - assign sdata_rdata = data_rdata[31:0]; + assign sdata_rdata = data_rdata[0][31:0]; `endif assign vdata_rdata = data_rdata; - assign vdata_res_id = vdata_wait_id; + assign vdata_res_id = data_res_id; // Memory Interface signals I-DATA logic imem_req; @@ -864,38 +948,53 @@ module vproc_top import vproc_pkg::*; #( logic imem_err; logic i_miss /* verilator public */; logic i_hit /* verilator public */; - - assign imem_req = instr_req; - assign imem_addr = instr_addr; - assign instr_gnt = imem_gnt; - assign instr_rvalid = imem_rvalid; - assign instr_rdata = imem_rdata[31:0]; - assign instr_err = imem_err; + logic [31:0] instr_wait_addr; + + always_comb begin + imem_req = instr_req; + instr_gnt = imem_gnt; + instr_rvalid = imem_rvalid; + instr_err = imem_err; + + `ifdef FORCE_ALIGNED_READS + imem_addr = {instr_addr[31:$clog2(VMEM_W/8)], {$clog2(VMEM_W/8){1'b0}}}; + instr_rdata = imem_rdata[(instr_wait_addr[$clog2(VMEM_W)-1:0] & {3'b000, {($clog2(VMEM_W/8)-2){1'b1}}, 2'b00})*8 +: 32]; + `else + imem_addr = instr_addr; + instr_rdata = imem_rdata[31:0]; + `endif + end // Memory Interface signals D-DATA - logic dmem_req; - logic dmem_gnt; - logic [31:0] dmem_addr; - logic dmem_we; - logic [MEM_W/8-1:0] dmem_be; - logic [MEM_W -1:0] dmem_wdata; - logic dmem_rvalid; - logic dmem_wvalid; - logic [MEM_W -1:0] dmem_rdata; - logic dmem_err; + logic dmem_req [MEM_PORTS-1:0]; + logic dmem_gnt [MEM_PORTS-1:0]; + logic [31:0] dmem_addr [MEM_PORTS-1:0]; + logic dmem_we [MEM_PORTS-1:0]; + logic [MEM_W/8-1:0] dmem_be [MEM_PORTS-1:0]; + logic [MEM_W -1:0] dmem_wdata [MEM_PORTS-1:0]; + logic dmem_rvalid [MEM_PORTS-1:0]; + logic dmem_wvalid [MEM_PORTS-1:0]; + logic [MEM_W -1:0] dmem_rdata [MEM_PORTS-1:0]; + logic dmem_err [MEM_PORTS-1:0]; + logic dmem_aid [MEM_PORTS-1:0]; + logic dmem_rid [MEM_PORTS-1:0]; logic d_miss /* verilator public */; logic d_hit /* verilator public */; - assign dmem_req = data_req; - assign dmem_addr = data_addr; - assign dmem_we = data_we && mem_req_o; - assign dmem_be = data_be; - assign dmem_wdata = data_wdata; - assign data_gnt = dmem_gnt; - assign data_rvalid = dmem_rvalid | dmem_wvalid; - assign data_rdata = dmem_rdata; - assign data_err = dmem_err; + for(genvar i = 0; i < MEM_PORTS; i++) begin + assign dmem_req[i] = data_req[i]; + assign dmem_addr[i] = data_addr[i]; + assign dmem_we[i] = data_we[i] && mem_req_o[i]; + assign dmem_be[i] = data_be[i]; + assign dmem_wdata[i] = data_wdata[i]; + assign data_gnt[i] = dmem_gnt[i]; + assign data_rvalid[i] = dmem_rvalid[i] | dmem_wvalid[i]; + assign data_rdata[i] = dmem_rdata[i]; + assign data_err[i] = dmem_err[i]; + assign dmem_aid[i] = data_req_id[i]; + assign data_res_id[i] = dmem_rid[i]; + end @@ -927,43 +1026,52 @@ module vproc_top import vproc_pkg::*; #( // shift register keeping track of the source of mem requests for up to 32 cycles (needed to keep track of reads/writes) - logic req_sources [32]; - logic req_write [32]; // keeping track of whether the request was a write - logic [4:0] req_count; + logic [MEM_PORTS-1:0][31:0] req_sources; + logic [MEM_PORTS-1:0][31:0] req_write; // keeping track of whether the request was a write + logic [MEM_PORTS-1:0][4:0] req_count; always_ff @(posedge clk_i or negedge rst_ni) begin if (~rst_ni) begin - req_count <= '0; + req_count <= '{default: '0}; end else begin - if (mem_rvalid_i) begin - for (int i = 0; i < 31; i++) begin - req_sources [i] <= req_sources [i+1]; - req_write [i] <= req_write [i+1]; + for(int i = 0; i < MEM_PORTS; i++) begin + if (mem_rvalid_i[i]) begin + for (int j = 0; j < 31; j++) begin + req_sources [i][j] <= req_sources [i][j+1]; + req_write [i][j] <= req_write [i][j+1]; + end + if (~dmem_gnt[i]) begin + req_count[i] <= req_count[i] - 1; + end else begin + req_sources [i][req_count[i]-1] <= dmem_gnt[i]; + req_write [i][req_count[i]-1] <= dmem_we[i]; + end end - if (~dmem_gnt) begin - req_count <= req_count - 1; - end else begin - req_sources [req_count-1] <= dmem_gnt; - req_write [req_count-1] <= dmem_we; + else if (dmem_gnt[i]) begin + req_sources [i][req_count] <= dmem_gnt[i]; + req_write [i][req_count] <= dmem_we[i]; + req_count[i] <= req_count[i] + 1; end end - else if (dmem_gnt) begin - req_sources [req_count] <= dmem_gnt; - req_write [req_count] <= dmem_we; - req_count <= req_count + 1; - end end end assign imem_rvalid = mem_irvalid_i; - assign dmem_rvalid = mem_rvalid_i & ~req_write[0]; - assign dmem_wvalid = mem_rvalid_i & req_write[0]; //this could be an issue? + generate + for(genvar i = 0; i < MEM_PORTS; i++) begin + assign dmem_rvalid[i] = mem_rvalid_i[i] & ~req_write[i][0]; + assign dmem_wvalid[i] = mem_rvalid_i[i] & req_write[i][0]; //this could be an issue? + end + endgenerate assign imem_err = mem_ierr_i; assign dmem_err = mem_err_i; assign imem_rdata = mem_irdata_i; assign dmem_rdata = mem_rdata_i; + + assign mem_aid_o = dmem_aid; + assign dmem_rid = mem_rid_i; diff --git a/build_model/vector_config.cmake b/build_model/vector_config.cmake index 2045fef..cab2507 100644 --- a/build_model/vector_config.cmake +++ b/build_model/vector_config.cmake @@ -8,7 +8,11 @@ set(RISCV_ARCH "rv32im_zve32x") #Currently Supported: cv32e40x, cv32a60x set(SCALAR_CORE "cv32e40x") - +set(VMEM_PORTS 1) set(VMEM_W 32) set(VREG_W 128) -set(VPROC_PIPELINES "${VMEM_W}:VLSU 32:VELEM,VSLD,VDIV,VALU,VMUL") + +math(EXPR VMEM_TOTAL_W "${VMEM_PORTS} * ${VMEM_W}") + +set(VPROC_PIPELINES "${VMEM_TOTAL_W}:VLSU 32:VELEM,VSLD,VDIV,VALU,VMUL") + diff --git a/build_tests/CMakeLists.txt b/build_tests/CMakeLists.txt index 5adb305..b16ba39 100644 --- a/build_tests/CMakeLists.txt +++ b/build_tests/CMakeLists.txt @@ -51,7 +51,10 @@ message("Selected RISCV_ARCH = ${RISCV_ARCH}") message("Selected VREG_W = ${VREG_W}") message("Selected VMEM_W = ${VMEM_W}") set(MEM_W ${VMEM_W}) +set(ENV{MEM_W} ${VMEM_W}) message("Selected MEM_W = ${MEM_W}") +set(MEM_PORTS ${VMEM_PORTS}) +message("Selected MEM_PORTS = ${MEM_PORTS}") #####