From f5a4606f755c07fa9c834f0d539863a6b6900443 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Wed, 8 Nov 2023 17:42:45 +0100 Subject: [PATCH 1/2] Add example UVM testbench for Verilator Signed-off-by: Krzysztof Bieganski Signed-off-by: Karol Gugala --- testbench/uvm/mem/.gitignore | 5 + testbench/uvm/mem/Makefile | 110 ++++++++++++++++++ testbench/uvm/mem/hdl/dccm_agent.sv | 36 ++++++ testbench/uvm/mem/hdl/dccm_base_test.sv | 40 +++++++ testbench/uvm/mem/hdl/dccm_driver.sv | 46 ++++++++ testbench/uvm/mem/hdl/dccm_interface.sv | 15 +++ testbench/uvm/mem/hdl/dccm_memtest.sv | 27 +++++ testbench/uvm/mem/hdl/dccm_monitor.sv | 45 +++++++ testbench/uvm/mem/hdl/dccm_scoreboard.sv | 57 +++++++++ testbench/uvm/mem/hdl/dccm_sequence.sv | 48 ++++++++ testbench/uvm/mem/hdl/dccm_sequencer.sv | 19 +++ .../mem/hdl/dccm_transaction_sequence_item.sv | 24 ++++ testbench/uvm/mem/hdl/tbench_top.sv | 69 +++++++++++ 13 files changed, 541 insertions(+) create mode 100644 testbench/uvm/mem/.gitignore create mode 100644 testbench/uvm/mem/Makefile create mode 100644 testbench/uvm/mem/hdl/dccm_agent.sv create mode 100644 testbench/uvm/mem/hdl/dccm_base_test.sv create mode 100644 testbench/uvm/mem/hdl/dccm_driver.sv create mode 100644 testbench/uvm/mem/hdl/dccm_interface.sv create mode 100644 testbench/uvm/mem/hdl/dccm_memtest.sv create mode 100644 testbench/uvm/mem/hdl/dccm_monitor.sv create mode 100644 testbench/uvm/mem/hdl/dccm_scoreboard.sv create mode 100644 testbench/uvm/mem/hdl/dccm_sequence.sv create mode 100644 testbench/uvm/mem/hdl/dccm_sequencer.sv create mode 100644 testbench/uvm/mem/hdl/dccm_transaction_sequence_item.sv create mode 100644 testbench/uvm/mem/hdl/tbench_top.sv diff --git a/testbench/uvm/mem/.gitignore b/testbench/uvm/mem/.gitignore new file mode 100644 index 00000000000..f2bb14d0747 --- /dev/null +++ b/testbench/uvm/mem/.gitignore @@ -0,0 +1,5 @@ +*-sim +snapshots +*.vcd +*.fst +uvm diff --git a/testbench/uvm/mem/Makefile b/testbench/uvm/mem/Makefile new file mode 100644 index 00000000000..e95b94d1960 --- /dev/null +++ b/testbench/uvm/mem/Makefile @@ -0,0 +1,110 @@ +all: simulate + +# ------------------------------------- +# Testbench setup +# ------------------------------------- +# Check for RV_ROOT +ifeq (,$(wildcard ${RV_ROOT}/configs/veer.config)) +$(error env var RV_ROOT does not point to a valid dir! Exiting!) +endif + +VERILATOR ?= verilator +ifdef VERILATOR_ROOT +VERILATOR := $(VERILATOR_ROOT)/bin/verilator +endif + +# Check for Verilator +ifeq ($(shell which $(VERILATOR)),) +$(error Verilator not found! Exiting!) +endif + +# Check Verilator version +VERILATOR_VERSION := $(shell $(VERILATOR) --version) +VERILATOR_RECOMMENDED_COMMIT := df36e9ca2 +ifeq ($(findstring $(VERILATOR_RECOMMENDED_COMMIT),$(VERILATOR_VERSION)),) +$(warning Using $(VERILATOR_VERSION)) +$(warning It is recommended to use Verilator revision: https://github.com/antmicro/verilator-1/commit/$(VERILATOR_RECOMMENDED_COMMIT)) +endif + +UVM_ROOT ?= uvm +UVM_TEST ?= mem_wr_rd_test +SNAPSHOT = verilator-uvm + +VERILOG_DEFINE_FILES = \ + ${UVM_ROOT}/src/uvm.sv \ + ${RV_ROOT}/snapshots/$(SNAPSHOT)/common_defines.vh \ + ${RV_ROOT}/design/include/el2_def.sv \ + ${RV_ROOT}/snapshots/$(SNAPSHOT)/el2_pdef.vh + +VERILOG_INCLUDE_DIRS = \ + hdl \ + ${UVM_ROOT}/src \ + ${RV_ROOT}/design/include \ + ${RV_ROOT}/snapshots/$(SNAPSHOT) + +VERILOG_SOURCES = \ + ${RV_ROOT}/design/lib/beh_lib.sv \ + ${RV_ROOT}/design/lib/mem_lib.sv \ + $(SIM_DIR)/el2_lsu_dccm_mem.sv \ + hdl/tbench_top.sv + +# ------------------------------------- +# Compilation/simulation configuration +# ------------------------------------- +SIM_NAME ?= mem_tb +SIM_DIR := $(SIM_NAME)-sim +COMPILE_ARGS += --top-module tbench_top +COMPILE_ARGS += -DUVM_NO_DPI +COMPILE_ARGS += --prefix $(SIM_NAME) -o $(SIM_NAME) +COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) +EXTRA_ARGS += --timescale 1ns/1ps --error-limit 100 --trace --trace-structs +WARNING_ARGS += -Wno-lint \ + -Wno-style \ + -Wno-SYMRSVDWORD \ + -Wno-IGNOREDRETURN \ + -Wno-CONSTRAINTIGN \ + -Wno-ZERODLY + +# ------------------------------------- +# Fetch UVM +# ------------------------------------- +$(UVM_ROOT): + git clone https://github.com/antmicro/uvm-verilator -b current-patches $(UVM_ROOT) + +# ------------------------------------- +# Configure VeeR EL-2 +# ------------------------------------- +$(RV_ROOT)/snapshots/$(SNAPSHOT)/el2_param.vh: + $(RV_ROOT)/configs/veer.config -snapshot=$(SNAPSHOT) -fpga_optimize=0 + +# FIXME: Patch source to disable "ifdef VERILATOR". Can't undef it as it has to be set for UVM sources. +$(SIM_DIR)/el2_lsu_dccm_mem.sv: + mkdir -p $(SIM_DIR) + sed 's/ifdef VERILATOR/ifdef XXXX/g' $(RV_ROOT)/design/lsu/el2_lsu_dccm_mem.sv > $(SIM_DIR)/el2_lsu_dccm_mem.sv + +# ------------------------------------- +# Make UVM test with Verilator +# ------------------------------------- +$(SIM_DIR)/$(SIM_NAME).mk: ${UVM_ROOT} $(RV_ROOT)/snapshots/$(SNAPSHOT)/el2_param.vh $(VERILOG_SOURCES) $(wildcard hdl/*.sv) + $(VERILATOR) --cc --exe --main --timing -Mdir $(SIM_DIR) \ + ${COMPILE_ARGS} ${EXTRA_ARGS} \ + ${VERILOG_DEFINE_FILES} \ + ${VERILOG_SOURCES} \ + ${WARNING_ARGS} + +$(SIM_DIR)/$(SIM_NAME): $(SIM_DIR)/$(SIM_NAME).mk + $(MAKE) -C $(SIM_DIR) $(BUILD_ARGS) -f $(SIM_NAME).mk + +simulate: build + $(SIM_DIR)/$(SIM_NAME) +UVM_TESTNAME=$(UVM_TEST) + +clean: + rm -rf snapshots + rm -rf simv*.daidir csrc + rm -rf csrc* simv* + rm -rf *.vcd *.fst + rm -rf $(SIM_DIR) + rm -rf $(UVM_DIR) + + +.PHONY: simulate clean diff --git a/testbench/uvm/mem/hdl/dccm_agent.sv b/testbench/uvm/mem/hdl/dccm_agent.sv new file mode 100644 index 00000000000..7ebabad6a20 --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_agent.sv @@ -0,0 +1,36 @@ +`include "dccm_transaction_sequence_item.sv" +`include "dccm_sequencer.sv" +`include "dccm_sequence.sv" +`include "dccm_driver.sv" +`include "dccm_monitor.sv" + +class dccm_agent extends uvm_agent; + + dccm_driver driver; + dccm_sequencer sequencer; + dccm_monitor monitor; + + `uvm_component_utils(dccm_agent) + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction : new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + + monitor = dccm_monitor::type_id::create("monitor", this); + + if (get_is_active() == UVM_ACTIVE) begin + driver = dccm_driver::type_id::create("driver", this); + sequencer = dccm_sequencer::type_id::create("sequencer", this); + end + endfunction : build_phase + + function void connect_phase(uvm_phase phase); + if (get_is_active() == UVM_ACTIVE) begin + driver.seq_item_port.connect(sequencer.seq_item_export); + end + endfunction : connect_phase + +endclass : dccm_agent diff --git a/testbench/uvm/mem/hdl/dccm_base_test.sv b/testbench/uvm/mem/hdl/dccm_base_test.sv new file mode 100644 index 00000000000..53795810281 --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_base_test.sv @@ -0,0 +1,40 @@ +`include "dccm_agent.sv" +`include "dccm_scoreboard.sv" +class mem_model_base_test extends uvm_test; + + `uvm_component_utils(mem_model_base_test) + + dccm_agent agent; + dccm_scoreboard scoreboard; + + function new(string name = "mem_model_base_test", uvm_component parent = null); + super.new(name, parent); + endfunction : new + + virtual function void build_phase(uvm_phase phase); + super.build_phase(phase); + + agent = dccm_agent::type_id::create("agent", this); + scoreboard = dccm_scoreboard::type_id::create("scoreboard", this); + endfunction : build_phase + + function void connect_phase(uvm_phase phase); + agent.monitor.transaction_analisys_port.connect(scoreboard.item_collected_export); + endfunction : connect_phase + + function void report_phase(uvm_phase phase); + uvm_report_server svr; + int errors; + super.report_phase(phase); + + svr = uvm_report_server::get_server(); + errors = svr.get_severity_count(UVM_FATAL) + svr.get_severity_count(UVM_ERROR); + if (errors > 0) begin + `uvm_info(get_type_name(), "DCCM TEST FAILED!!", UVM_NONE) + `uvm_info(get_type_name(), $sformatf("Found %d errors", errors), UVM_NONE) + end else begin + `uvm_info(get_type_name(), "DCCM TEST PASSED!!", UVM_NONE) + end + endfunction + +endclass : mem_model_base_test diff --git a/testbench/uvm/mem/hdl/dccm_driver.sv b/testbench/uvm/mem/hdl/dccm_driver.sv new file mode 100644 index 00000000000..20e9a5bef51 --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_driver.sv @@ -0,0 +1,46 @@ +class dccm_driver extends uvm_driver #(dccm_transaction_sequence_item); + + virtual dccm_interface memory_vif; + `uvm_component_utils(dccm_driver) + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction : new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + if (!uvm_config_db#(virtual dccm_interface)::get(this, "", "memory_vif", memory_vif)) + `uvm_fatal("NO_VIF", {"virtual interface must be set for: ", get_full_name(), ".memory_vif"}); + endfunction : build_phase + + virtual task run_phase(uvm_phase phase); + forever begin + seq_item_port.get_next_item(req); + drive(); + seq_item_port.item_done(); + end + endtask : run_phase + + virtual task drive(); + memory_vif.wr_en <= 0; + memory_vif.rd_en <= 0; + @(posedge memory_vif.clk); + + memory_vif.addr <= req.addr; + + if (req.wr_en) begin // write operation + `uvm_info(get_type_name(), $sformatf("WR: 0x%08X <= 0x%08X", req.addr, req.wdata), UVM_LOW) + memory_vif.wr_en <= 1'b1; //req.wr_en; + memory_vif.wdata <= req.wdata; + @(posedge memory_vif.clk); + end else if (req.rd_en) begin //read operation + memory_vif.rd_en <= 1'b1; //req.rd_en; + @(posedge memory_vif.clk); + memory_vif.rd_en <= 0; + @(posedge memory_vif.clk); + req.rdata = memory_vif.rdata; + `uvm_info(get_type_name(), $sformatf("RD: 0x%08X => 0x%08X", req.addr, req.rdata), UVM_LOW) + end + + endtask : drive +endclass : dccm_driver diff --git a/testbench/uvm/mem/hdl/dccm_interface.sv b/testbench/uvm/mem/hdl/dccm_interface.sv new file mode 100644 index 00000000000..59b36b45d36 --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_interface.sv @@ -0,0 +1,15 @@ +interface dccm_interface ( + input logic clk, + reset +); + + `include "el2_param.vh" + ; + + logic [pt.DCCM_BITS-1:0] addr; + logic wr_en; + logic rd_en; + logic [pt.DCCM_FDATA_WIDTH-1:0] wdata; + logic [pt.DCCM_FDATA_WIDTH-1:0] rdata; + +endinterface diff --git a/testbench/uvm/mem/hdl/dccm_memtest.sv b/testbench/uvm/mem/hdl/dccm_memtest.sv new file mode 100644 index 00000000000..a735159679e --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_memtest.sv @@ -0,0 +1,27 @@ +class mem_wr_rd_test extends mem_model_base_test; + + `uvm_component_utils(mem_wr_rd_test) + + dccm_memtest_sequence memtest; + + function new(string name = "mem_wr_rd_test", uvm_component parent = null); + super.new(name, parent); + endfunction : new + + virtual function void build_phase(uvm_phase phase); + super.build_phase(phase); + + memtest = dccm_memtest_sequence::type_id::create(); + // Run the memtest 10 times + memtest.loops = 10; + endfunction : build_phase + + task run_phase(uvm_phase phase); + + phase.raise_objection(this); + memtest.start(agent.sequencer); + phase.drop_objection(this); + + endtask : run_phase + +endclass : mem_wr_rd_test diff --git a/testbench/uvm/mem/hdl/dccm_monitor.sv b/testbench/uvm/mem/hdl/dccm_monitor.sv new file mode 100644 index 00000000000..e7d2f9ebfc0 --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_monitor.sv @@ -0,0 +1,45 @@ +class dccm_monitor extends uvm_monitor; + + virtual dccm_interface memory_vif; + uvm_analysis_port #(dccm_transaction_sequence_item) transaction_analisys_port; + dccm_transaction_sequence_item transaction; + + `uvm_component_utils(dccm_monitor) + + function new(string name, uvm_component parent); + super.new(name, parent); + transaction = new(); + transaction_analisys_port = new("trensaction_analisys_port", this); + endfunction : new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + if (!uvm_config_db#(virtual dccm_interface)::get(this, "", "memory_vif", memory_vif)) + `uvm_fatal("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".memory_vif"}); + endfunction : build_phase + + virtual task run_phase(uvm_phase phase); + forever begin + @(posedge memory_vif.clk); + wait (memory_vif.wr_en || memory_vif.rd_en); + // store control signals and address + transaction.addr = memory_vif.addr; + transaction.wdata = memory_vif.wdata; + transaction.rd_en = memory_vif.rd_en; + if (memory_vif.wr_en) begin + // store write data + transaction.wr_en = memory_vif.wr_en; + @(posedge memory_vif.clk); + end + if (memory_vif.rd_en) begin + // it takes 2 clocks to get the data on the output port + @(posedge memory_vif.clk); + @(posedge memory_vif.clk); + // store read data + transaction.rdata = memory_vif.rdata; + end + transaction_analisys_port.write(transaction); + end + endtask : run_phase + +endclass : dccm_monitor diff --git a/testbench/uvm/mem/hdl/dccm_scoreboard.sv b/testbench/uvm/mem/hdl/dccm_scoreboard.sv new file mode 100644 index 00000000000..4a368fd54eb --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_scoreboard.sv @@ -0,0 +1,57 @@ +class dccm_scoreboard extends uvm_scoreboard; + + `include "el2_param.vh" + ; + + dccm_transaction_sequence_item data_queue[$]; + bit [pt.DCCM_FDATA_WIDTH-1:0] sc_mem; + + uvm_analysis_imp #(dccm_transaction_sequence_item, dccm_scoreboard) item_collected_export; + `uvm_component_utils(dccm_scoreboard) + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction : new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + item_collected_export = new("item_collected_export", this); + sc_mem = {(pt.DCCM_FDATA_WIDTH) {1'b1}}; + endfunction : build_phase + + virtual function void write(dccm_transaction_sequence_item pkt); + pkt.print(); + data_queue.push_back(pkt); + endfunction : write + + virtual task run_phase(uvm_phase phase); + dccm_transaction_sequence_item mem_pkt; + + forever begin + wait (data_queue.size() > 0); + mem_pkt = data_queue.pop_front(); + + if (mem_pkt.wr_en) begin + sc_mem = mem_pkt.wdata; + `uvm_info(get_type_name(), $sformatf("------ :: WRITE DATA :: ------"), UVM_LOW) + `uvm_info(get_type_name(), $sformatf("Addr: %0h", mem_pkt.addr), UVM_LOW) + `uvm_info(get_type_name(), $sformatf("Data: %0h", mem_pkt.wdata), UVM_LOW) + `uvm_info(get_type_name(), "------------------------------------", UVM_LOW) + end else if (mem_pkt.rd_en) begin + if (sc_mem == mem_pkt.rdata) begin + `uvm_info(get_type_name(), $sformatf("------ :: READ DATA Match :: ------"), UVM_LOW) + `uvm_info(get_type_name(), $sformatf("Addr: %0h", mem_pkt.addr), UVM_LOW) + `uvm_info(get_type_name(), $sformatf("Expected Data: %0h Actual Data: %0h", sc_mem, + mem_pkt.rdata), UVM_LOW) + `uvm_info(get_type_name(), "------------------------------------", UVM_LOW) + end else begin + `uvm_error(get_type_name(), "------ :: READ DATA Mismatch :: ------") + `uvm_error(get_type_name(), $sformatf("Addr: %0h", mem_pkt.addr)) + `uvm_error(get_type_name(), $sformatf( + "Expected Data: %0h Actual Data: %0h", sc_mem, mem_pkt.rdata)) + `uvm_error(get_type_name(), "------------------------------------") + end + end + end + endtask : run_phase +endclass : dccm_scoreboard diff --git a/testbench/uvm/mem/hdl/dccm_sequence.sv b/testbench/uvm/mem/hdl/dccm_sequence.sv new file mode 100644 index 00000000000..edd6c8283fc --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_sequence.sv @@ -0,0 +1,48 @@ +// this sequence wites random random data to random address, then reads it back +class dccm_write_read_sequence extends uvm_sequence #(dccm_transaction_sequence_item); + + `uvm_object_utils(dccm_write_read_sequence) + + function new(string name = "write_read_sequence"); + super.new(name); + endfunction + + virtual task body(); + + // Do randomized write + req = dccm_transaction_sequence_item::type_id::create("req"); + wait_for_grant(); + req.randomize(); + req.wr_en = 1'b1; + req.rd_en = 1'b0; + send_request(req); + wait_for_item_done(); + + // Do read from the same address + wait_for_grant(); + req.wr_en = 1'b0; + req.rd_en = 1'b1; + send_request(req); + wait_for_item_done(); + + endtask +endclass + +class dccm_memtest_sequence extends uvm_sequence #(dccm_transaction_sequence_item); + + dccm_write_read_sequence seq; + int loops; + + `uvm_object_utils(dccm_memtest_sequence) + + function new(string name = "dccm_memtest_sequence"); + super.new(name); + endfunction + + virtual task body(); + repeat (loops) begin + `uvm_do(seq) + end + endtask +endclass +//========================================================================= diff --git a/testbench/uvm/mem/hdl/dccm_sequencer.sv b/testbench/uvm/mem/hdl/dccm_sequencer.sv new file mode 100644 index 00000000000..0410768152f --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_sequencer.sv @@ -0,0 +1,19 @@ +// FIXME: +// In Verilator, user should always use: +// uvm_sequencer#(item, item); +// instead standard (other simulators): +// uvm_sequencer#(item); + +`ifdef VERILATOR +class dccm_sequencer extends uvm_sequencer #(dccm_transaction_sequence_item, dccm_transaction_sequence_item); +`else +class dccm_sequencer extends uvm_sequencer #(dccm_transaction_sequence_item); +`endif + + `uvm_component_utils(dccm_sequencer) + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + +endclass diff --git a/testbench/uvm/mem/hdl/dccm_transaction_sequence_item.sv b/testbench/uvm/mem/hdl/dccm_transaction_sequence_item.sv new file mode 100644 index 00000000000..be2a4d52c00 --- /dev/null +++ b/testbench/uvm/mem/hdl/dccm_transaction_sequence_item.sv @@ -0,0 +1,24 @@ +class dccm_transaction_sequence_item extends uvm_sequence_item; + + `include "el2_param.vh" + ; + + rand bit [ pt.DCCM_BITS-1:0] addr; + rand bit [pt.DCCM_FDATA_WIDTH-1:0] wdata; + bit [pt.DCCM_FDATA_WIDTH-1:0] rdata; + // we want to manually control wr_en anf rd_en in the test + bit wr_en; + bit rd_en; + + `uvm_object_utils_begin(dccm_transaction_sequence_item) + `uvm_field_int(addr, UVM_ALL_ON) + `uvm_field_int(wr_en, UVM_ALL_ON) + `uvm_field_int(rd_en, UVM_ALL_ON) + `uvm_field_int(wdata, UVM_ALL_ON) + `uvm_object_utils_end + + function new(string name = "dccm_transation_sequence_item"); + super.new(name); + endfunction + +endclass diff --git a/testbench/uvm/mem/hdl/tbench_top.sv b/testbench/uvm/mem/hdl/tbench_top.sv new file mode 100644 index 00000000000..53dfdd92e0a --- /dev/null +++ b/testbench/uvm/mem/hdl/tbench_top.sv @@ -0,0 +1,69 @@ +`include "uvm_pkg.sv" + +import uvm_pkg::*; + +`include "dccm_interface.sv" +`include "dccm_base_test.sv" +`include "dccm_memtest.sv" + +module tbench_top; + + bit clk; + bit reset; + + always #5 clk = ~clk; + + initial begin + reset = 1; + #5 reset = 0; + end + + initial begin + $dumpfile("dump.vcd"); + $dumpvars(0, tbench_top); + end + + dccm_interface intf ( + clk, + reset + ); + + el2_lsu_dccm_mem DUT ( + .clk (intf.clk), + .active_clk (intf.clk), + .rst_l (~intf.reset), + .clk_override(1'b0), + .scan_mode (1'b0), + + .dccm_wren (intf.wr_en), + .dccm_rden (intf.rd_en), + .dccm_wr_addr_hi(intf.addr), + .dccm_wr_addr_lo(intf.addr), + .dccm_rd_addr_hi(intf.addr), + .dccm_rd_addr_lo(intf.addr), + .dccm_wr_data_hi(intf.wdata), + .dccm_wr_data_lo(intf.wdata), + .dccm_rd_data_hi(), // For aligned read/write this should match the lo part + .dccm_rd_data_lo(intf.rdata) + ); + + // Debug, dump memory signals on each clock cycle + always @(posedge intf.clk) + $display( + "a:%08X w:%d wd:%08X r:%d rd:%08X", + intf.addr, + intf.wr_en, + intf.wdata, + intf.rd_en, + intf.rdata + ); + + initial begin + uvm_config_db#(virtual dccm_interface)::set(uvm_root::get(), "*", "memory_vif", intf); + end + + initial begin + run_test(); + end + +endmodule From 4a8e19d592d284e51174a6fd5b5c14085c61b415 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Wed, 8 Nov 2023 18:53:11 +0100 Subject: [PATCH 2/2] Add CI workflow for UVM testbench Signed-off-by: Krzysztof Bieganski --- .github/workflows/build-verilator.yml | 17 +++++- .github/workflows/ci.yml | 5 ++ .github/workflows/test-uvm.yml | 84 +++++++++++++++++++++++++++ testbench/uvm/mem/Makefile | 6 +- 4 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/test-uvm.yml diff --git a/.github/workflows/build-verilator.yml b/.github/workflows/build-verilator.yml index 9a34e6f3c89..bd2b960f8cb 100644 --- a/.github/workflows/build-verilator.yml +++ b/.github/workflows/build-verilator.yml @@ -7,9 +7,20 @@ jobs: verilator: name: Build Verilator runs-on: ubuntu-latest + strategy: + matrix: + include: + - version: v5.010 + repo: verilator/verilator + commit: v5.010 + - version: uvm + repo: antmicro/verilator-1 + commit: df36e9ca2597aebe4b92c72461d945745b36c3e0 env: TOOL_NAME: verilator - TOOL_VERSION: v5.010 + TOOL_VERSION: ${{ matrix.version }} + TOOL_REPO: ${{ matrix.repo }} + TOOL_COMMIT: ${{ matrix.commit }} DEBIAN_FRONTEND: "noninteractive" steps: @@ -56,9 +67,9 @@ jobs: run: | export CCACHE_DIR=/opt/verilator/.cache ccache --show-config | grep cache_dir - git clone https://github.com/verilator/verilator + git clone https://github.com/${{ env.TOOL_REPO }} verilator pushd verilator - git checkout ${{ env.TOOL_VERSION }} + git checkout ${{ env.TOOL_COMMIT }} autoconf ./configure --prefix=/opt/verilator make -j `nproc` diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1d8b7c40a7..db3001341dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,11 @@ jobs: needs: [Build-Verilator, Build-Spike] uses: ./.github/workflows/test-riscof.yml + Test-UVM: + name: Test-UVM + needs: [Build-Verilator] + uses: ./.github/workflows/test-uvm.yml + Report-Coverage: name: Report-Coverage needs: [Test-Regression, Test-Verification, Test-RISCV-DV, Test-RISCOF] diff --git a/.github/workflows/test-uvm.yml b/.github/workflows/test-uvm.yml new file mode 100644 index 00000000000..a972ae1ec71 --- /dev/null +++ b/.github/workflows/test-uvm.yml @@ -0,0 +1,84 @@ +name: VeeR-EL2 verification + +on: + workflow_call: + +jobs: + tests: + name: UVM tests + runs-on: ubuntu-latest + env: + CCACHE_DIR: "/opt/uvm/.cache/" + VERILATOR_VERSION: uvm + DEBIAN_FRONTEND: "noninteractive" + steps: + - name: Setup repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup Cache Metadata + id: cache_metadata + run: | + date=$(date +"%Y_%m_%d") + time=$(date +"%Y%m%d_%H%M%S_%N") + cache_verilator_restore_key=cache_verilator_ + cache_verilator_key=${cache_verilator_restore_key}${{ env.VERILATOR_VERSION }} + cache_test_restore_key=${{ matrix.test }}_${{ matrix.coverage }}_ + cache_test_key=${cache_test_restore_key}${time} + + echo "date=$date" | tee -a "$GITHUB_ENV" + echo "time=$time" | tee -a "$GITHUB_ENV" + echo "cache_verilator_restore_key=$cache_verilator_restore_key" | tee -a "$GITHUB_ENV" + echo "cache_verilator_key=$cache_verilator_key" | tee -a "$GITHUB_ENV" + echo "cache_test_restore_key=$cache_test_restore_key" | tee -a "$GITHUB_ENV" + echo "cache_test_key=$cache_test_key" | tee -a "$GITHUB_ENV" + + + - name: Restore verilator cache + id: cache-verilator-restore + uses: actions/cache/restore@v3 + with: + path: | + /opt/verilator + /opt/verilator/.cache + key: ${{ env.cache_verilator_key }} + restore-keys: ${{ env.cache_verilator_restore_key }} + + - name: Setup tests cache + uses: actions/cache@v3 + id: cache-test-setup + with: + path: | + ${{ env.CCACHE_DIR }} + key: ${{ env.cache_test_key }} + restore-keys: ${{ env.cache_test_restore_key }} + + - name: Install prerequisities + run: | + sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ + git build-essential cpanminus ccache + sudo cpanm Bit::Vector + + - name: Setup environment + run: | + echo "/opt/verilator/bin" >> $GITHUB_PATH + RV_ROOT=`pwd` + echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV + PYTHONUNBUFFERED=1 + echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV + + - name: Build UVM testbench + run: | + make -C testbench/uvm/mem build -j$(nproc) + + - name: Run UVM testbench + run: | + make -C testbench/uvm/mem simulate | tee test.out + + - name: Upload test output + if: always() + uses: actions/upload-artifact@v3 + with: + name: uvm_test_output + path: test.out diff --git a/testbench/uvm/mem/Makefile b/testbench/uvm/mem/Makefile index e95b94d1960..6a142123d8e 100644 --- a/testbench/uvm/mem/Makefile +++ b/testbench/uvm/mem/Makefile @@ -85,14 +85,14 @@ $(SIM_DIR)/el2_lsu_dccm_mem.sv: # ------------------------------------- # Make UVM test with Verilator # ------------------------------------- -$(SIM_DIR)/$(SIM_NAME).mk: ${UVM_ROOT} $(RV_ROOT)/snapshots/$(SNAPSHOT)/el2_param.vh $(VERILOG_SOURCES) $(wildcard hdl/*.sv) +verilate: ${UVM_ROOT} $(RV_ROOT)/snapshots/$(SNAPSHOT)/el2_param.vh $(VERILOG_SOURCES) $(wildcard hdl/*.sv) $(VERILATOR) --cc --exe --main --timing -Mdir $(SIM_DIR) \ ${COMPILE_ARGS} ${EXTRA_ARGS} \ ${VERILOG_DEFINE_FILES} \ ${VERILOG_SOURCES} \ ${WARNING_ARGS} -$(SIM_DIR)/$(SIM_NAME): $(SIM_DIR)/$(SIM_NAME).mk +build: verilate $(MAKE) -C $(SIM_DIR) $(BUILD_ARGS) -f $(SIM_NAME).mk simulate: build @@ -107,4 +107,4 @@ clean: rm -rf $(UVM_DIR) -.PHONY: simulate clean +.PHONY: verilate build simulate clean