-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add example UVM testbench for Verilator
Signed-off-by: Krzysztof Bieganski <[email protected]> Signed-off-by: Karol Gugala <[email protected]>
- Loading branch information
Showing
13 changed files
with
541 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
*-sim | ||
snapshots | ||
*.vcd | ||
*.fst | ||
uvm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.