mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-20 03:47:15 -04:00
Add UVM testbench
This adds a UVM testbench and associated tooling for Ibex. The tooling requires Synopsys VCS to run.
This commit is contained in:
parent
effa61c684
commit
2782ae9677
31 changed files with 1421 additions and 0 deletions
67
dv/uvm/Makefile
Normal file
67
dv/uvm/Makefile
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
DV_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
GEN_DIR := $(realpath ${DV_DIR}/../../vendor/google_riscv-dv)
|
||||
TOOLCHAIN := ${RISCV_TOOLCHAIN}
|
||||
OUT := "${DV_DIR}/out"
|
||||
# Run time options for the instruction generator
|
||||
GEN_OPTS :=
|
||||
# Run time options for ibex RTL simulation
|
||||
SIM_OPTS :=
|
||||
# Enable waveform dumping
|
||||
WAVES := 1
|
||||
WAVE_CMP_OPTS := -debug_access+all -ucli -do vcs.tcl
|
||||
# Enable coverage dump
|
||||
COV := 0
|
||||
|
||||
ifeq (${WAVES}, 0)
|
||||
WAVE_CMP_OPTS=
|
||||
endif
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
export PRJ_DIR:= $(realpath ${DV_DIR}/../../..)
|
||||
|
||||
rand:=$(shell awk 'BEGIN{srand();printf("%d", 65536*rand())}')
|
||||
|
||||
.PHONY: rtl_sim clean iss_sim
|
||||
|
||||
all: clean gen iss_sim compile rtl_sim post_compare
|
||||
|
||||
clean:
|
||||
rm -rf ${OUT}
|
||||
|
||||
# Generate random instructions
|
||||
gen:
|
||||
mkdir -p ${OUT}
|
||||
cd ${GEN_DIR}; ./run -o ${OUT}/instr_gen ${GEN_OPTS};
|
||||
|
||||
# ISS simulation
|
||||
iss_sim:
|
||||
cd ${GEN_DIR}; \
|
||||
./iss_sim -dir ${OUT}/instr_gen -toolchain ${TOOLCHAIN} -isa rv32imc -abi ilp32;
|
||||
|
||||
# Compile ibex core TB
|
||||
compile:
|
||||
mkdir -p ${OUT}/rtl_sim
|
||||
vcs -f ibex_dv.f -full64 \
|
||||
-l ${OUT}/rtl_sim/compile.log \
|
||||
-sverilog -ntb_opts uvm-1.2 \
|
||||
+define+UVM_REGEX_NO_DPI -timescale=1ns/10ps -licqueue \
|
||||
-Mdir=${OUT}/rtl_sim/vcs_simv.csrc \
|
||||
-o ${OUT}/rtl_sim/vcs_simv \
|
||||
+define+BOOT_ADDR=32\'h8000_0000 \
|
||||
+define+TRACE_EXECUTION \
|
||||
-debug_access+pp \
|
||||
${WAVE_CMP_OPTS} \
|
||||
-lca -kdb
|
||||
|
||||
# Run ibex RTL simulation with random instructions
|
||||
rtl_sim:
|
||||
./sim ${SIM_OPTS} -dir ${OUT} -waves ${WAVES}
|
||||
|
||||
# Compare the regression result between ISS and RTL sim
|
||||
post_compare:
|
||||
./compare ${OUT}
|
18
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf.sv
Normal file
18
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf.sv
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
interface ibex_mem_intf#(ADDR_WIDTH = 32, DATA_WIDTH = 32);
|
||||
|
||||
logic clock;
|
||||
logic reset;
|
||||
logic request;
|
||||
logic grant;
|
||||
logic [ADDR_WIDTH-1:0] addr;
|
||||
logic we;
|
||||
logic [DATA_WIDTH/8-1:0] be;
|
||||
logic rvalid;
|
||||
logic [DATA_WIDTH-1:0] wdata;
|
||||
logic [DATA_WIDTH-1:0] rdata;
|
||||
|
||||
endinterface : ibex_mem_intf
|
30
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
Normal file
30
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`include "ibex_mem_intf.sv"
|
||||
|
||||
package ibex_mem_intf_agent_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
import mem_model_pkg::*;
|
||||
|
||||
parameter DATA_WIDTH = 32;
|
||||
parameter ADDR_WIDTH = 32;
|
||||
|
||||
typedef enum { READ, WRITE } rw_e;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
`include "ibex_mem_intf_seq_item.sv"
|
||||
|
||||
typedef uvm_sequencer#(ibex_mem_intf_seq_item) ibex_mem_intf_master_sequencer;
|
||||
|
||||
`include "ibex_mem_intf_monitor.sv"
|
||||
`include "ibex_mem_intf_slave_driver.sv"
|
||||
`include "ibex_mem_intf_slave_sequencer.sv"
|
||||
`include "ibex_mem_intf_slave_seq_lib.sv"
|
||||
`include "ibex_mem_intf_slave_agent.sv"
|
||||
`include "ibex_mem_intf_master_driver.sv"
|
||||
`include "ibex_mem_intf_master_agent.sv"
|
||||
|
||||
endpackage
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_master_agent
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_master_agent extends uvm_agent;
|
||||
|
||||
ibex_mem_intf_master_driver driver;
|
||||
ibex_mem_intf_master_sequencer sequencer;
|
||||
ibex_mem_intf_monitor monitor;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_master_agent)
|
||||
`uvm_component_new
|
||||
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
monitor = ibex_mem_intf_monitor::type_id::create("monitor", this);
|
||||
if(get_is_active() == UVM_ACTIVE) begin
|
||||
driver = ibex_mem_intf_master_driver::type_id::create("driver", this);
|
||||
sequencer = ibex_mem_intf_master_sequencer::type_id::create("sequencer", this);
|
||||
end
|
||||
endfunction : build_phase
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
if(get_is_active() == UVM_ACTIVE) begin
|
||||
driver.seq_item_port.connect(sequencer.seq_item_export);
|
||||
end
|
||||
endfunction : connect_phase
|
||||
|
||||
endclass : ibex_mem_intf_master_agent
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_master_driver
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_master_driver extends uvm_driver #(ibex_mem_intf_seq_item);
|
||||
|
||||
protected virtual ibex_mem_intf vif;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_master_driver)
|
||||
`uvm_component_new
|
||||
|
||||
mailbox #(ibex_mem_intf_seq_item) rdata_queue;
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
rdata_queue = new();
|
||||
if(!uvm_config_db#(virtual ibex_mem_intf)::get(this, "", "vif", vif))
|
||||
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
|
||||
endfunction: build_phase
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
fork
|
||||
get_and_drive();
|
||||
reset_signals();
|
||||
collect_response();
|
||||
join
|
||||
endtask : run_phase
|
||||
|
||||
virtual protected task get_and_drive();
|
||||
@(negedge vif.reset);
|
||||
forever begin
|
||||
@(posedge vif.clock);
|
||||
seq_item_port.get_next_item(req);
|
||||
repeat(req.req_delay) @(posedge vif.clock);
|
||||
$cast(rsp, req.clone());
|
||||
rsp.set_id_info(req);
|
||||
drive_transfer(rsp);
|
||||
seq_item_port.item_done();
|
||||
end
|
||||
endtask : get_and_drive
|
||||
|
||||
virtual protected task reset_signals();
|
||||
forever begin
|
||||
@(posedge vif.reset);
|
||||
vif.request <= 'h0;
|
||||
vif.addr <= 'hz;
|
||||
vif.wdata <= 'hz;
|
||||
vif.be <= 'bz;
|
||||
vif.we <= 'bz;
|
||||
end
|
||||
endtask : reset_signals
|
||||
|
||||
virtual protected task drive_transfer (ibex_mem_intf_seq_item trans);
|
||||
if (trans.req_delay > 0) begin
|
||||
repeat(trans.req_delay) @(posedge vif.clock);
|
||||
end
|
||||
vif.request <= 1'b1;
|
||||
vif.addr <= trans.addr;
|
||||
vif.be <= trans.be;
|
||||
vif.we <= trans.read_write;
|
||||
vif.wdata <= trans.data;
|
||||
wait(vif.grant === 1'b1);
|
||||
@(posedge vif.clock);
|
||||
vif.request <= 'h0;
|
||||
vif.addr <= 'hz;
|
||||
vif.wdata <= 'hz;
|
||||
vif.be <= 'bz;
|
||||
vif.we <= 'bz;
|
||||
rdata_queue.put(trans);
|
||||
endtask : drive_transfer
|
||||
|
||||
virtual protected task collect_response();
|
||||
ibex_mem_intf_seq_item tr;
|
||||
forever begin
|
||||
rdata_queue.get(tr);
|
||||
@(posedge vif.clock);
|
||||
while(vif.rvalid !== 1'b1) @(posedge vif.clock);
|
||||
if(tr.read_write == READ)
|
||||
tr.data = vif.rdata;
|
||||
seq_item_port.put_response(tr);
|
||||
end
|
||||
endtask : collect_response
|
||||
|
||||
endclass : ibex_mem_intf_master_driver
|
75
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv
Normal file
75
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_monitor.sv
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_monitor
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_monitor extends uvm_monitor;
|
||||
|
||||
protected virtual ibex_mem_intf vif;
|
||||
|
||||
mailbox #(ibex_mem_intf_seq_item) collect_data_queue;
|
||||
uvm_analysis_port#(ibex_mem_intf_seq_item) item_collected_port;
|
||||
uvm_analysis_port#(ibex_mem_intf_seq_item) addr_ph_port;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_monitor)
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
item_collected_port = new("item_collected_port", this);
|
||||
addr_ph_port = new("addr_ph_port_monitor", this);
|
||||
collect_data_queue = new();
|
||||
if(!uvm_config_db#(virtual ibex_mem_intf)::get(this, "", "vif", vif)) begin
|
||||
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
|
||||
end
|
||||
endfunction: build_phase
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
wait(vif.reset === 1'b0);
|
||||
fork
|
||||
collect_address_phase();
|
||||
collect_data_phase();
|
||||
join
|
||||
endtask : run_phase
|
||||
|
||||
virtual protected task collect_address_phase();
|
||||
ibex_mem_intf_seq_item trans_collected;
|
||||
forever begin
|
||||
trans_collected = ibex_mem_intf_seq_item::type_id::create("trans_collected");
|
||||
while(!(vif.request && vif.grant)) @(posedge vif.clock);
|
||||
trans_collected.addr = vif.addr;
|
||||
trans_collected.be = vif.be;
|
||||
`uvm_info(get_full_name(), $sformatf("Detect request with address: %0x",
|
||||
trans_collected.addr), UVM_HIGH)
|
||||
if(vif.we) begin
|
||||
trans_collected.read_write = WRITE;
|
||||
trans_collected.data = vif.wdata;
|
||||
end else begin
|
||||
trans_collected.read_write = READ;
|
||||
end
|
||||
addr_ph_port.write(trans_collected);
|
||||
`uvm_info(get_full_name(),"Send through addr_ph_port", UVM_HIGH)
|
||||
if(trans_collected.read_write == WRITE)
|
||||
item_collected_port.write(trans_collected);
|
||||
else
|
||||
collect_data_queue.put(trans_collected);
|
||||
@(posedge vif.clock);
|
||||
end
|
||||
endtask : collect_address_phase
|
||||
|
||||
virtual protected task collect_data_phase();
|
||||
ibex_mem_intf_seq_item trans_collected;
|
||||
forever begin
|
||||
collect_data_queue.get(trans_collected);
|
||||
do
|
||||
@(posedge vif.clock);
|
||||
while(vif.rvalid === 0);
|
||||
trans_collected.data = vif.rdata;
|
||||
item_collected_port.write(trans_collected);
|
||||
end
|
||||
endtask : collect_data_phase
|
||||
|
||||
endclass : ibex_mem_intf_monitor
|
30
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_seq_item.sv
Normal file
30
dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_seq_item.sv
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_seq_item
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_seq_item extends uvm_sequence_item;
|
||||
|
||||
rand bit [ADDR_WIDTH-1:0] addr;
|
||||
rand rw_e read_write;
|
||||
rand bit [DATA_WIDTH-1:0] data;
|
||||
rand bit [DATA_WIDTH/8-1:0] be;
|
||||
rand bit [3:0] gnt_delay;
|
||||
rand bit [3:0] req_delay;
|
||||
rand bit [5:0] rvalid_delay;
|
||||
|
||||
`uvm_object_utils_begin(ibex_mem_intf_seq_item)
|
||||
`uvm_field_int (addr, UVM_DEFAULT)
|
||||
`uvm_field_enum (rw_e, read_write, UVM_DEFAULT)
|
||||
`uvm_field_int (be, UVM_DEFAULT)
|
||||
`uvm_field_int (data, UVM_DEFAULT)
|
||||
`uvm_field_int (gnt_delay, UVM_DEFAULT)
|
||||
`uvm_field_int (rvalid_delay, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
endclass : ibex_mem_intf_seq_item
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_slave_agent
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_slave_agent extends uvm_agent;
|
||||
|
||||
ibex_mem_intf_slave_driver driver;
|
||||
ibex_mem_intf_slave_sequencer sequencer;
|
||||
ibex_mem_intf_monitor monitor;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_slave_agent)
|
||||
`uvm_component_new
|
||||
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
monitor = ibex_mem_intf_monitor::type_id::create("monitor", this);
|
||||
if(get_is_active() == UVM_ACTIVE) begin
|
||||
driver = ibex_mem_intf_slave_driver::type_id::create("driver", this);
|
||||
sequencer = ibex_mem_intf_slave_sequencer::type_id::create("sequencer", this);
|
||||
end
|
||||
endfunction : build_phase
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
if(get_is_active() == UVM_ACTIVE) begin
|
||||
driver.seq_item_port.connect(sequencer.seq_item_export);
|
||||
monitor.addr_ph_port.connect(sequencer.addr_ph_port.analysis_export);
|
||||
end
|
||||
endfunction : connect_phase
|
||||
|
||||
endclass : ibex_mem_intf_slave_agent
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_slave_driver
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_slave_driver extends uvm_driver #(ibex_mem_intf_seq_item);
|
||||
|
||||
protected virtual ibex_mem_intf vif;
|
||||
|
||||
int unsigned min_grant_delay = 0;
|
||||
int unsigned max_grant_delay = 10;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_slave_driver)
|
||||
`uvm_component_new
|
||||
|
||||
mailbox #(ibex_mem_intf_seq_item) grant_queue;
|
||||
mailbox #(ibex_mem_intf_seq_item) rdata_queue;
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
grant_queue = new();
|
||||
rdata_queue = new();
|
||||
if(!uvm_config_db#(virtual ibex_mem_intf)::get(this, "", "vif", vif))
|
||||
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
|
||||
endfunction: build_phase
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
reset_signals();
|
||||
fork
|
||||
send_grant();
|
||||
join_none
|
||||
get_and_drive();
|
||||
endtask : run_phase
|
||||
|
||||
virtual protected task reset_signals();
|
||||
vif.rvalid <= 1'b0;
|
||||
vif.grant <= 1'b0;
|
||||
vif.rdata <= 'b0;
|
||||
endtask : reset_signals
|
||||
|
||||
virtual protected task get_and_drive();
|
||||
@(negedge vif.reset);
|
||||
fork
|
||||
forever begin
|
||||
ibex_mem_intf_seq_item req, req_c;
|
||||
@(posedge vif.clock);
|
||||
seq_item_port.get_next_item(req);
|
||||
$cast(req_c, req.clone());
|
||||
if(~vif.reset) begin
|
||||
rdata_queue.put(req_c);
|
||||
end
|
||||
seq_item_port.item_done();
|
||||
end
|
||||
send_read_data();
|
||||
join_none
|
||||
endtask : get_and_drive
|
||||
|
||||
virtual protected task send_grant();
|
||||
int gnt_delay;
|
||||
forever begin
|
||||
while(vif.request !== 1'b1) begin
|
||||
@(negedge vif.clock);
|
||||
end
|
||||
std::randomize(gnt_delay) with {
|
||||
gnt_delay dist {
|
||||
min_grant_delay :/ 1,
|
||||
[min_grant_delay+1 : max_grant_delay-1] :/ 1,
|
||||
max_grant_delay :/ 1
|
||||
};
|
||||
};
|
||||
repeat(gnt_delay) @(negedge vif.clock);
|
||||
if(~vif.reset) begin
|
||||
vif.grant = 1'b1;
|
||||
@(negedge vif.clock);
|
||||
vif.grant = 1'b0;
|
||||
end
|
||||
end
|
||||
endtask : send_grant
|
||||
|
||||
virtual protected task send_read_data();
|
||||
ibex_mem_intf_seq_item tr;
|
||||
forever begin
|
||||
@(posedge vif.clock);
|
||||
vif.rvalid <= 1'b0;
|
||||
vif.rdata <= 'x;
|
||||
rdata_queue.get(tr);
|
||||
if(vif.reset) continue;
|
||||
repeat(tr.rvalid_delay) @(posedge vif.clock);
|
||||
if(~vif.reset) begin
|
||||
vif.rvalid <= 1'b1;
|
||||
vif.rdata <= tr.data;
|
||||
end
|
||||
end
|
||||
endtask : send_read_data
|
||||
|
||||
endclass : ibex_mem_intf_slave_driver
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// SEQUENCE: ibex_mem_intf_slave_seq
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_slave_seq extends uvm_sequence #(ibex_mem_intf_seq_item);
|
||||
|
||||
int max_rvalid_delay = 20;
|
||||
int min_rvalid_delay = 0;
|
||||
ibex_mem_intf_seq_item item;
|
||||
mem_model m_mem;
|
||||
|
||||
`uvm_object_utils(ibex_mem_intf_slave_seq)
|
||||
`uvm_declare_p_sequencer(ibex_mem_intf_slave_sequencer)
|
||||
`uvm_object_new
|
||||
|
||||
virtual task body();
|
||||
if(m_mem == null)
|
||||
`uvm_fatal(get_full_name(), "Cannot get memory model")
|
||||
forever
|
||||
begin
|
||||
bit [ADDR_WIDTH-1:0] aligned_addr;
|
||||
p_sequencer.addr_ph_port.get(item);
|
||||
req = ibex_mem_intf_seq_item::type_id::create("req");
|
||||
req.randomize() with {
|
||||
addr == item.addr;
|
||||
read_write == item.read_write;
|
||||
data == item.data;
|
||||
be == item.be;
|
||||
rvalid_delay dist {
|
||||
min_rvalid_delay :/ 5,
|
||||
[min_rvalid_delay+1 : max_rvalid_delay/2-1] :/ 3,
|
||||
[max_rvalid_delay/2 : max_rvalid_delay-1] :/ 1,
|
||||
max_rvalid_delay :/ 1
|
||||
};
|
||||
};
|
||||
aligned_addr = {req.addr[DATA_WIDTH-1:2], 2'b0};
|
||||
if(req.read_write == READ) begin : READ_block
|
||||
req.data = m_mem.read(aligned_addr);
|
||||
end
|
||||
`uvm_info(get_full_name(), $sformatf("Response transfer:\n%0s", req.sprint()), UVM_HIGH)
|
||||
start_item(req);
|
||||
finish_item(req);
|
||||
if(item.read_write == WRITE) begin : WRITE_block
|
||||
bit [DATA_WIDTH-1:0] data;
|
||||
data = req.data;
|
||||
for(int i = 0; i < DATA_WIDTH/8; i++) begin
|
||||
if(req.be[i])
|
||||
m_mem.write_byte(aligned_addr + i, data[7:0]);
|
||||
data = data >> 8;
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask : body
|
||||
|
||||
endclass : ibex_mem_intf_slave_seq
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CLASS: ibex_mem_intf_slave_sequencer
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ibex_mem_intf_slave_sequencer extends uvm_sequencer #(ibex_mem_intf_seq_item);
|
||||
|
||||
// TLM port to peek the address phase from the slave monitor
|
||||
uvm_tlm_analysis_fifo #(ibex_mem_intf_seq_item) addr_ph_port;
|
||||
|
||||
`uvm_component_utils(ibex_mem_intf_slave_sequencer)
|
||||
|
||||
function new (string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
addr_ph_port = new("addr_ph_port_sequencer", this);
|
||||
endfunction : new
|
||||
|
||||
endclass : ibex_mem_intf_slave_sequencer
|
56
dv/uvm/common/mem_model/mem_model.sv
Normal file
56
dv/uvm/common/mem_model/mem_model.sv
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class mem_model#(Addr_width = 32, Data_width = 32) extends uvm_object;
|
||||
|
||||
typedef bit [Addr_width-1:0] mem_addr_t;
|
||||
typedef bit [Data_width-1:0] mem_data_t;
|
||||
|
||||
bit [7:0] system_memory[mem_addr_t];
|
||||
|
||||
`uvm_object_param_utils(mem_model#(Addr_width, Data_width))
|
||||
|
||||
function new(string name="");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
function bit [7:0] read_byte(mem_addr_t addr);
|
||||
bit [7:0] data;
|
||||
if(system_memory.exists(addr)) begin
|
||||
data = system_memory[addr];
|
||||
`uvm_info(get_full_name(),
|
||||
$sformatf("Read Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_HIGH)
|
||||
end
|
||||
else begin
|
||||
std::randomize(data);
|
||||
`uvm_error(get_full_name(), $sformatf("read to uninitialzed addr 0x%0h", addr))
|
||||
end
|
||||
return data;
|
||||
endfunction
|
||||
|
||||
function void write_byte(mem_addr_t addr, bit[7:0] data);
|
||||
`uvm_info(get_full_name(),
|
||||
$sformatf("Write Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_HIGH)
|
||||
system_memory[addr] = data;
|
||||
endfunction
|
||||
|
||||
function void write(input mem_addr_t addr, mem_data_t data);
|
||||
bit [7:0] byte_data;
|
||||
for(int i=0; i<Data_width/8; i++) begin
|
||||
byte_data = data[7:0];
|
||||
write_byte(addr+i, byte_data);
|
||||
data = data >> 8;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function mem_data_t read(mem_addr_t addr);
|
||||
mem_data_t data;
|
||||
for(int i=Data_width/8-1; i>=0; i--) begin
|
||||
data = data << 8;
|
||||
data[7:0] = read_byte(addr+i);
|
||||
end
|
||||
return data;
|
||||
endfunction
|
||||
|
||||
endclass
|
12
dv/uvm/common/mem_model/mem_model_pkg.sv
Normal file
12
dv/uvm/common/mem_model/mem_model_pkg.sv
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mem_model_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
`include "mem_model.sv"
|
||||
|
||||
endpackage
|
29
dv/uvm/common/utils/clk_if.sv
Normal file
29
dv/uvm/common/utils/clk_if.sv
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//----------------------------- DESCRIPTION ------------------------------------
|
||||
//
|
||||
// Generic clock interface for clock events in various utilities
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
interface clk_if(input logic clk);
|
||||
|
||||
clocking cb @(posedge clk);
|
||||
endclocking
|
||||
|
||||
clocking cbn @(negedge clk);
|
||||
endclocking
|
||||
|
||||
// Wait for 'n' clocks based of postive clock edge
|
||||
task wait_clks(int num_clks);
|
||||
repeat (num_clks) @cb;
|
||||
endtask
|
||||
|
||||
// Wait for 'n' clocks based of negative clock edge
|
||||
task wait_n_clks(int num_clks);
|
||||
repeat (num_clks) @cbn;
|
||||
endtask
|
||||
|
||||
endinterface
|
232
dv/uvm/common/utils/dv_macros.svh
Normal file
232
dv/uvm/common/utils/dv_macros.svh
Normal file
|
@ -0,0 +1,232 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// UVM speficic macros
|
||||
`ifndef gfn
|
||||
`define gfn get_full_name()
|
||||
`endif
|
||||
|
||||
`ifndef gtn
|
||||
`define gtn get_type_name()
|
||||
`endif
|
||||
|
||||
`ifndef gn
|
||||
`define gn get_name()
|
||||
`endif
|
||||
|
||||
`ifndef gmv
|
||||
`define gmv(csr) csr.get_mirrored_value()
|
||||
`endif
|
||||
|
||||
// cast base class obj holding extended class handle to extended class handle;
|
||||
// throw error if cast fails
|
||||
`ifndef downcast
|
||||
`define downcast(EXT_, BASE_, MSG_="", SEV_=fatal, ID_=`gfn) \
|
||||
if (!$cast(EXT_, BASE_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf({"Cast failed: base class variable %0s ", \
|
||||
"does not hold extended class %0s handle %s"}, \
|
||||
`"BASE_`", `"EXT_`", MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
// Note, UVM provides a macro `uvm_new_func -- which only applies to uvm_components
|
||||
`ifndef uvm_object_new
|
||||
`define uvm_object_new \
|
||||
function new (string name=""); \
|
||||
super.new(name); \
|
||||
endfunction : new
|
||||
`endif
|
||||
|
||||
`ifndef uvm_create_obj
|
||||
`define uvm_create_obj(_type_name_, _inst_name_) \
|
||||
_inst_name_ = _type_name_::type_id::create(`"_inst_name_`");
|
||||
`endif
|
||||
|
||||
`ifndef uvm_component_new
|
||||
`define uvm_component_new \
|
||||
function new (string name="", uvm_component parent=null); \
|
||||
super.new(name, parent); \
|
||||
endfunction : new
|
||||
`endif
|
||||
|
||||
`ifndef uvm_create_comp
|
||||
`define uvm_create_comp(_type_name_, _inst_name_) \
|
||||
_inst_name_ = _type_name_::type_id::create(`"_inst_name_`", this);
|
||||
`endif
|
||||
|
||||
// Common check macros used by DV_CHECK error and fatal macros.
|
||||
// Note: Should not be called by user code
|
||||
`ifndef DV_CHECK
|
||||
`define DV_CHECK(T_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!(T_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf("Check failed (%s) %s ", `"T_`", MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_EQ
|
||||
`define DV_CHECK_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!(ACT_ == EXP_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf("Check failed %s == %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_NE
|
||||
`define DV_CHECK_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!(ACT_ != EXP_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf("Check failed %s != %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_LT
|
||||
`define DV_CHECK_LT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!(ACT_ < EXP_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf("Check failed %s < %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_GT
|
||||
`define DV_CHECK_GT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!(ACT_ > EXP_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf("Check failed %s > %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_LE
|
||||
`define DV_CHECK_LE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!(ACT_ <= EXP_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf("Check failed %s <= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_GE
|
||||
`define DV_CHECK_GE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
|
||||
if (!(ACT_ >= EXP_)) begin \
|
||||
`uvm_``SEV_(ID_, $sformatf("Check failed %s >= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
|
||||
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \
|
||||
end
|
||||
`endif
|
||||
|
||||
// Fatal version of the checks
|
||||
`ifndef DV_CHECK_FATAL
|
||||
`define DV_CHECK_FATAL(T_, MSG_="", ID_=`gfn) \
|
||||
`DV_CHECK(T_, MSG_, fatal, ID_)
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_EQ_FATAL
|
||||
`define DV_CHECK_EQ_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
|
||||
`DV_CHECK_EQ(ACT_, EXP_, MSG_, fatal, ID_)
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_NE_FATAL
|
||||
`define DV_CHECK_NE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
|
||||
`DV_CHECK_NE(ACT_, EXP_, MSG_, fatal, ID_)
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_LT_FATAL
|
||||
`define DV_CHECK_LT_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
|
||||
`DV_CHECK_LT(ACT_, EXP_, MSG_, fatal, ID_)
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_GT_FATAL
|
||||
`define DV_CHECK_GT_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
|
||||
`DV_CHECK_GT(ACT_, EXP_, MSG_, fatal, ID_)
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_LE_FATAL
|
||||
`define DV_CHECK_LE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
|
||||
`DV_CHECK_LE(ACT_, EXP_, MSG_, fatal, ID_)
|
||||
`endif
|
||||
|
||||
`ifndef DV_CHECK_GE_FATAL
|
||||
`define DV_CHECK_GE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
|
||||
`DV_CHECK_GE(ACT_, EXP_, MSG_, fatal, ID_)
|
||||
`endif
|
||||
|
||||
// Shorthand for common foo.randomize() + fatal check
|
||||
`ifndef DV_CHECK_RANDOMIZE_FATAL
|
||||
`define DV_CHECK_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \
|
||||
`DV_CHECK_FATAL(VAR_.randomize(), MSG_, ID_)
|
||||
`endif
|
||||
|
||||
// Shorthand for common foo.randomize() with { } + fatal check
|
||||
`ifndef DV_CHECK_RANDOMIZE_WITH_FATAL
|
||||
`define DV_CHECK_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_, MSG_="Randomization failed!", ID_=`gfn) \
|
||||
`DV_CHECK_FATAL(VAR_.randomize() with {WITH_C_}, MSG_, ID_)
|
||||
`endif
|
||||
|
||||
// Shorthand for common std::randomize(foo) + fatal check
|
||||
`ifndef DV_CHECK_STD_RANDOMIZE_FATAL
|
||||
`define DV_CHECK_STD_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \
|
||||
`DV_CHECK_FATAL(std::randomize(VAR_), MSG_, ID_)
|
||||
`endif
|
||||
|
||||
// Shorthand for common std::randomize(foo) with { } + fatal check
|
||||
`ifndef DV_CHECK_STD_RANDOMIZE_WITH_FATAL
|
||||
`define DV_CHECK_STD_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_,MSG_="Randomization failed!",ID_=`gfn) \
|
||||
`DV_CHECK_FATAL(std::randomize(VAR_) with {WITH_C_}, MSG_, ID_)
|
||||
`endif
|
||||
|
||||
// Shorthand for common this.randomize(foo) + fatal check
|
||||
`ifndef DV_CHECK_MEMBER_RANDOMIZE_FATAL
|
||||
`define DV_CHECK_MEMBER_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \
|
||||
`DV_CHECK_FATAL(this.randomize(VAR_), MSG_, ID_)
|
||||
`endif
|
||||
|
||||
// Shorthand for common this.randomize(foo) with { } + fatal check
|
||||
`ifndef DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL
|
||||
`define DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(VAR_, C_, MSG_="Randomization failed!", ID_=`gfn) \
|
||||
`DV_CHECK_FATAL(this.randomize(VAR_) with {C_}, MSG_, ID_)
|
||||
`endif
|
||||
|
||||
// print non-empty tlm fifos that were uncompared at end of test
|
||||
`ifndef DV_EOT_PRINT_TLM_FIFO_CONTENTS
|
||||
`define DV_EOT_PRINT_TLM_FIFO_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \
|
||||
while (!FIFO_.is_empty()) begin \
|
||||
TYP_ item; \
|
||||
void'(FIFO_.try_get(item)); \
|
||||
`uvm_``SEV_(ID_, $sformatf("%s item uncompared:\n%s", `"FIFO_`", item.sprint())) \
|
||||
end
|
||||
`endif
|
||||
|
||||
// print non-empty tlm fifos that were uncompared at end of test
|
||||
`ifndef DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS
|
||||
`define DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \
|
||||
foreach (FIFO_[i]) begin \
|
||||
while (!FIFO_[i].is_empty()) begin \
|
||||
TYP_ item; \
|
||||
void'(FIFO_[i].try_get(item)); \
|
||||
`uvm_``SEV_(ID_, $sformatf("%s[%0d] item uncompared:\n%s", `"FIFO_`", i, item.sprint())) \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
// print non-empty tlm fifos that were uncompared at end of test
|
||||
`ifndef DV_EOT_PRINT_Q_CONTENTS
|
||||
`define DV_EOT_PRINT_Q_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \
|
||||
while (Q_.size() != 0) begin \
|
||||
TYP_ item = Q_.pop_front(); \
|
||||
`uvm_``SEV_(ID_, $sformatf("%s item uncompared:\n%s", `"Q_`", item.sprint())) \
|
||||
end
|
||||
`endif
|
||||
|
||||
// print non-empty tlm fifos that were uncompared at end of test
|
||||
`ifndef DV_EOT_PRINT_Q_ARR_CONTENTS
|
||||
`define DV_EOT_PRINT_Q_ARR_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \
|
||||
foreach (Q_[i]) begin \
|
||||
while (Q_[i].size() != 0) begin \
|
||||
TYP_ item = Q[i].pop_front(); \
|
||||
`uvm_``SEV_(ID_, $sformatf("%s[%0d] item uncompared:\n%s", `"Q_`", i, item.sprint())) \
|
||||
end \
|
||||
end
|
||||
`endif
|
||||
|
||||
// get parity - implemented as a macro so that it can be invoked in constraints as well
|
||||
`ifndef get_parity
|
||||
`define get_parity(val, odd=0) (^val ^ odd)
|
||||
`endif
|
17
dv/uvm/common/utils/dv_utils_pkg.sv
Normal file
17
dv/uvm/common/utils/dv_utils_pkg.sv
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package dv_utils_pkg;
|
||||
// dep packages
|
||||
import uvm_pkg::*;
|
||||
|
||||
// macro includes
|
||||
`include "dv_macros.svh"
|
||||
`include "uvm_macros.svh"
|
||||
|
||||
// types & variables
|
||||
typedef bit [31:0] uint;
|
||||
typedef bit [63:0] uint64;
|
||||
|
||||
endpackage
|
57
dv/uvm/compare
Executable file
57
dv/uvm/compare
Executable file
|
@ -0,0 +1,57 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
RUN_DIR="$1"
|
||||
report_file="$1/regr.log"
|
||||
rm -rf "$report_file"
|
||||
script_path="../../vendor/google_riscv-dv"
|
||||
|
||||
compare_log () {
|
||||
spike_log="$1"
|
||||
ibex_log="$2"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Convert spike log to standard instruction trace csv
|
||||
# -----------------------------------------------------------------------------
|
||||
# Remove all the init spike boot instructions
|
||||
# 0xffffffff80000080 is the first user instruction
|
||||
sed -i '/0xffffffff80000080/,$!d' "$spike_log"
|
||||
# Remove all instructions after ecall (end of program excecution)
|
||||
sed -i '/ecall/q' "$spike_log"
|
||||
# Convert the spike log to riscv_instr_trace.proto format
|
||||
spike_csv=$(echo "$spike_log" | sed 's/\.log/.csv/g')
|
||||
python $script_path/scripts/spike_log_to_trace_csv.py \
|
||||
--log $spike_log --csv $spike_csv >> $report_file
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Convert ibex log to standard instruction trace csv
|
||||
# -----------------------------------------------------------------------------
|
||||
# Remove all instructions after ecall (end of program excecution)
|
||||
sed -i '/ecall/q' "$ibex_log"
|
||||
# Convert the spike log to riscv_instr_trace.proto format
|
||||
ibex_csv=$(echo "$ibex_log" | sed 's/\.log/.csv/g')
|
||||
python $script_path/scripts/ibex_log_to_trace_csv.py \
|
||||
--log $ibex_log --csv $ibex_csv >> $report_file
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Compare the trace log
|
||||
# -----------------------------------------------------------------------------
|
||||
python $script_path/scripts/instr_trace_compare.py $spike_csv $ibex_csv \
|
||||
"spike" "ibex" >> $report_file
|
||||
}
|
||||
|
||||
echo "compare simulation result under $RUN_DIR"
|
||||
while read asm_test; do
|
||||
SRC=$(echo "$asm_test" | sed 's/^.*\///g' | sed 's/\.S>*$//g')
|
||||
echo "Test: $asm_test" >> $report_file
|
||||
compare_log $RUN_DIR/instr_gen/spike_sim/$SRC.S.o.log \
|
||||
$RUN_DIR/rtl_sim/$SRC/trace_core_00_0.log
|
||||
done <"$RUN_DIR/asm_test_list"
|
||||
|
||||
passed_cnt="$(grep -c PASS $report_file)"
|
||||
failed_cnt="$(grep -c FAIL $report_file)"
|
||||
echo "$passed_cnt tests PASSED, $failed_cnt tests FAILED" >> $report_file
|
||||
|
||||
cat $report_file
|
10
dv/uvm/env/core_ibex_dut_probe_if.sv
vendored
Normal file
10
dv/uvm/env/core_ibex_dut_probe_if.sv
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Interface to probe DUT internal signal
|
||||
interface core_ibex_dut_probe_if(input logic clk);
|
||||
logic illegal_instr;
|
||||
logic ecall;
|
||||
logic fetch_enable;
|
||||
endinterface
|
33
dv/uvm/env/core_ibex_env.sv
vendored
Normal file
33
dv/uvm/env/core_ibex_env.sv
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// ---------------------------------------------
|
||||
// ibex processor core environment class
|
||||
// ---------------------------------------------
|
||||
class core_ibex_env extends uvm_env;
|
||||
|
||||
ibex_mem_intf_slave_agent data_if_slave_agent;
|
||||
ibex_mem_intf_slave_agent instr_if_slave_agent;
|
||||
core_ibex_vseqr vseqr;
|
||||
|
||||
`uvm_component_utils(core_ibex_env)
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
data_if_slave_agent = ibex_mem_intf_slave_agent::type_id::
|
||||
create("data_if_slave_agent", this);
|
||||
instr_if_slave_agent = ibex_mem_intf_slave_agent::type_id::
|
||||
create("instr_if_slave_agent", this);
|
||||
// Create virtual sequencer
|
||||
vseqr = core_ibex_vseqr::type_id::create("vseqr", this);
|
||||
endfunction : build_phase
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
vseqr.data_if_seqr = data_if_slave_agent.sequencer;
|
||||
vseqr.instr_if_seqr = instr_if_slave_agent.sequencer;
|
||||
endfunction : connect_phase
|
||||
|
||||
endclass
|
19
dv/uvm/env/core_ibex_env_pkg.sv
vendored
Normal file
19
dv/uvm/env/core_ibex_env_pkg.sv
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2018 lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// ---------------------------------------------
|
||||
// Core ibex environment package
|
||||
// ---------------------------------------------
|
||||
|
||||
`include "core_ibex_dut_probe_if.sv"
|
||||
|
||||
package core_ibex_env_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
import ibex_mem_intf_agent_pkg::*;
|
||||
|
||||
`include "core_ibex_vseqr.sv"
|
||||
`include "core_ibex_env.sv"
|
||||
|
||||
endpackage
|
16
dv/uvm/env/core_ibex_vseqr.sv
vendored
Normal file
16
dv/uvm/env/core_ibex_vseqr.sv
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// ---------------------------------------------
|
||||
// Core ibex environment virtual sequencer
|
||||
// ---------------------------------------------
|
||||
class core_ibex_vseqr extends uvm_sequencer;
|
||||
|
||||
ibex_mem_intf_slave_sequencer data_if_seqr;
|
||||
ibex_mem_intf_slave_sequencer instr_if_seqr;
|
||||
|
||||
`uvm_component_utils(core_ibex_vseqr)
|
||||
`uvm_component_new
|
||||
|
||||
endclass
|
41
dv/uvm/ibex_dv.f
Normal file
41
dv/uvm/ibex_dv.f
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
${PRJ_DIR}/ibex/dv/uvm/tb/prim_clock_gating.sv
|
||||
|
||||
// ibex CORE RTL files
|
||||
+incdir+${PRJ_DIR}/ibex/rtl
|
||||
${PRJ_DIR}/ibex/rtl/ibex_defines.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_tracer_defines.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_tracer.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_alu.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_compressed_decoder.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_controller.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_cs_registers.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_decoder.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_int_controller.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_ex_block.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_id_stage.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_if_stage.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_load_store_unit.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_multdiv_slow.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_multdiv_fast.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_prefetch_buffer.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_fetch_fifo.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_register_file_ff.sv
|
||||
${PRJ_DIR}/ibex/rtl/ibex_core.sv
|
||||
|
||||
// Core DV files
|
||||
+incdir+${PRJ_DIR}/ibex/dv/uvm/env
|
||||
+incdir+${PRJ_DIR}/ibex/dv/uvm/tests
|
||||
+incdir+${PRJ_DIR}/ibex/dv/uvm/common/ibex_mem_intf_agent
|
||||
+incdir+${PRJ_DIR}/ibex/dv/uvm/common/mem_model
|
||||
+incdir+${PRJ_DIR}/ibex/dv/uvm/common/utils
|
||||
${PRJ_DIR}/ibex/dv/uvm/common/utils/clk_if.sv
|
||||
${PRJ_DIR}/ibex/dv/uvm/common/utils/dv_utils_pkg.sv
|
||||
${PRJ_DIR}/ibex/dv/uvm/common/mem_model/mem_model_pkg.sv
|
||||
${PRJ_DIR}/ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
|
||||
${PRJ_DIR}/ibex/dv/uvm/env/core_ibex_env_pkg.sv
|
||||
${PRJ_DIR}/ibex/dv/uvm/tests/core_ibex_test_pkg.sv
|
||||
${PRJ_DIR}/ibex/dv/uvm/tb/core_ibex_tb_top.sv
|
79
dv/uvm/sim
Executable file
79
dv/uvm/sim
Executable file
|
@ -0,0 +1,79 @@
|
|||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Script to run the assembly tests generated by the riscv-dv instruction generator.
|
||||
|
||||
# Test directory
|
||||
RUN_DIR="./"
|
||||
|
||||
# Assembly test file name
|
||||
TEST=""
|
||||
|
||||
# Seed
|
||||
RAND_SEED=1
|
||||
SEED=""
|
||||
|
||||
# Wavform dump options
|
||||
WAVES=0
|
||||
WAVES_OPTS=""
|
||||
|
||||
# Process command line options
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
case $key in
|
||||
-dir)
|
||||
RUN_DIR="$2"
|
||||
shift
|
||||
;;
|
||||
-test)
|
||||
TEST="$2"
|
||||
shift
|
||||
;;
|
||||
-waves)
|
||||
WAVES="$2"
|
||||
shift
|
||||
;;
|
||||
-seed)
|
||||
SEED="$2"
|
||||
RAND_SEED=0
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "unknown option $1"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
|
||||
# If the test is specified through "-test" option, run a single test rather
|
||||
# than all tests under RUN_DIR.
|
||||
if [[ $TEST == "" ]]; then
|
||||
find "$RUN_DIR" -name "*.S" > "$RUN_DIR/asm_test_list"
|
||||
else
|
||||
echo "$TEST" > "$RUN_DIR/asm_test_list"
|
||||
fi
|
||||
|
||||
OUT="$RUN_DIR/rtl_sim"
|
||||
|
||||
# Run each test
|
||||
while read asm_test; do
|
||||
SRC=$(echo "$asm_test" | sed 's/^.*\///g' | sed 's/\.S>*$//g')
|
||||
BINFILE="$asm_test.bin"
|
||||
mkdir -p $OUT/$SRC
|
||||
cd $OUT/$SRC
|
||||
if [[ $RAND_SEED == 1 ]]; then
|
||||
SEED=$RANDOM
|
||||
fi
|
||||
if [[ $WAVES == 1 ]]; then
|
||||
WAVES_OPTS="-ucli -do $RUN_DIR/../vcs.tcl"
|
||||
fi
|
||||
CMD="$OUT/vcs_simv +UVM_TESTNAME=core_ibex_base_test \
|
||||
${WAVES_OPTS} +ntb_random_seed=${SEED} \
|
||||
+bin=$BINFILE -l sim.log"
|
||||
echo "Running simulation for : $CMD"
|
||||
$CMD
|
||||
done <"$RUN_DIR/asm_test_list"
|
87
dv/uvm/tb/core_ibex_tb_top.sv
Normal file
87
dv/uvm/tb/core_ibex_tb_top.sv
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module core_ibex_tb_top;
|
||||
|
||||
import uvm_pkg::*;
|
||||
|
||||
logic clk;
|
||||
logic rst_n;
|
||||
logic fetch_enable;
|
||||
|
||||
clk_if ibex_clk_if(.clk(clk));
|
||||
|
||||
// TODO(taliu) Resolve the tied-off ports
|
||||
ibex_core dut(
|
||||
.clk_i(clk),
|
||||
.rst_ni(rst_n),
|
||||
.test_en_i(1'b1),
|
||||
.core_id_i('0),
|
||||
.cluster_id_i('0),
|
||||
.boot_addr_i(`BOOT_ADDR), // align with spike boot address
|
||||
.irq_i('0),
|
||||
.irq_id_i('0),
|
||||
.debug_req_i('0),
|
||||
.fetch_enable_i(fetch_enable),
|
||||
.ext_perf_counters_i('0)
|
||||
);
|
||||
|
||||
ibex_mem_intf data_mem_vif();
|
||||
ibex_mem_intf instr_mem_vif();
|
||||
|
||||
initial begin
|
||||
//data load/store vif connection
|
||||
force data_mem_vif.clock = clk;
|
||||
force data_mem_vif.reset = ~rst_n;
|
||||
force data_mem_vif.request = dut.data_req_o;
|
||||
force dut.data_gnt_i = data_mem_vif.grant;
|
||||
force dut.data_rvalid_i = data_mem_vif.rvalid;
|
||||
force data_mem_vif.we = dut.data_we_o;
|
||||
force data_mem_vif.be = dut.data_be_o;
|
||||
force data_mem_vif.addr = dut.data_addr_o;
|
||||
force data_mem_vif.wdata = dut.data_wdata_o;
|
||||
force dut.data_rdata_i = data_mem_vif.rdata;
|
||||
force dut.data_err_i = 0; // TODO(taliu) Support interface error
|
||||
//instruction fetch vif connnection
|
||||
force instr_mem_vif.clock = clk;
|
||||
force instr_mem_vif.reset = ~rst_n;
|
||||
force instr_mem_vif.request = dut.instr_req_o;
|
||||
force dut.instr_gnt_i = instr_mem_vif.grant;
|
||||
force instr_mem_vif.we = 0;
|
||||
force instr_mem_vif.be = 0;
|
||||
force instr_mem_vif.wdata = 0;
|
||||
force dut.instr_rvalid_i = instr_mem_vif.rvalid;
|
||||
force instr_mem_vif.addr = dut.instr_addr_o;
|
||||
force dut.instr_rdata_i = instr_mem_vif.rdata;
|
||||
end
|
||||
|
||||
// DUT probe interface
|
||||
core_ibex_dut_probe_if dut_if(.clk(clk));
|
||||
assign dut_if.ecall = dut.id_stage_i.ecall_insn_dec;
|
||||
assign fetch_enable = dut_if.fetch_enable;
|
||||
|
||||
initial begin
|
||||
uvm_config_db#(virtual clk_if)::set(null, "*", "clk_if", ibex_clk_if);
|
||||
uvm_config_db#(virtual core_ibex_dut_probe_if)::set(null, "*", "dut_if", dut_if);
|
||||
uvm_config_db#(virtual ibex_mem_intf)::set(null, "*data_if_slave*", "vif", data_mem_vif);
|
||||
uvm_config_db#(virtual ibex_mem_intf)::set(null, "*instr_if_slave*", "vif", instr_mem_vif);
|
||||
run_test();
|
||||
end
|
||||
|
||||
// Generate clk
|
||||
initial begin
|
||||
clk = 1'b0;
|
||||
forever begin
|
||||
#10 clk = ~clk;
|
||||
end
|
||||
end
|
||||
|
||||
// Generate reset
|
||||
initial begin
|
||||
rst_n = 1'b0;
|
||||
repeat(100) @(posedge clk);
|
||||
rst_n = 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
18
dv/uvm/tb/prim_clock_gating.sv
Normal file
18
dv/uvm/tb/prim_clock_gating.sv
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Dummy clock gating module
|
||||
|
||||
module prim_clock_gating #(
|
||||
parameter Impl = "default"
|
||||
) (
|
||||
input clk_i,
|
||||
input en_i,
|
||||
input test_en_i,
|
||||
output logic clk_o
|
||||
);
|
||||
|
||||
assign clk_o = en_i ? clk_i : 0;
|
||||
|
||||
endmodule
|
BIN
dv/uvm/tests/bin/ibex_sanity_test.bin
Executable file
BIN
dv/uvm/tests/bin/ibex_sanity_test.bin
Executable file
Binary file not shown.
BIN
dv/uvm/tests/bin/ibex_sanity_test.o
Executable file
BIN
dv/uvm/tests/bin/ibex_sanity_test.o
Executable file
Binary file not shown.
84
dv/uvm/tests/core_ibex_base_test.sv
Normal file
84
dv/uvm/tests/core_ibex_base_test.sv
Normal file
|
@ -0,0 +1,84 @@
|
|||
class core_ibex_base_test extends uvm_test;
|
||||
|
||||
core_ibex_env env;
|
||||
virtual clk_if clk_vif;
|
||||
virtual core_ibex_dut_probe_if dut_vif;
|
||||
mem_model_pkg::mem_model mem;
|
||||
core_ibex_vseq vseq;
|
||||
int unsigned timeout_in_cycles = 1000000;
|
||||
|
||||
`uvm_component_utils(core_ibex_base_test)
|
||||
|
||||
function new(string name="", uvm_component parent=null);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
$value$plusargs("timeout_in_cycles=%0d", timeout_in_cycles);
|
||||
if (!uvm_config_db#(virtual clk_if)::get(null, "", "clk_if", clk_vif)) begin
|
||||
`uvm_fatal(get_full_name(), "Cannot get clk_if")
|
||||
end
|
||||
if (!uvm_config_db#(virtual core_ibex_dut_probe_if)::get(null, "", "dut_if", dut_vif)) begin
|
||||
`uvm_fatal(get_full_name(), "Cannot get dut_if")
|
||||
end
|
||||
env = core_ibex_env::type_id::create("env", this);
|
||||
mem = mem_model_pkg::mem_model#()::type_id::create("mem");
|
||||
// Create virtual sequence and assign memory handle
|
||||
vseq = core_ibex_vseq::type_id::create("vseq");
|
||||
vseq.mem = mem;
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
phase.raise_objection(this);
|
||||
dut_vif.fetch_enable = 1'b0;
|
||||
clk_vif.wait_clks(100);
|
||||
load_binary_to_mem();
|
||||
dut_vif.fetch_enable = 1'b1;
|
||||
vseq.start(env.vseqr);
|
||||
wait_for_test_done();
|
||||
phase.drop_objection(this);
|
||||
endtask
|
||||
|
||||
function void load_binary_to_mem();
|
||||
string bin;
|
||||
bit [7:0] r8;
|
||||
bit [31:0] addr = `BOOT_ADDR;
|
||||
int f_bin;
|
||||
void'($value$plusargs("bin=%0s", bin));
|
||||
if (bin == "")
|
||||
`uvm_fatal(get_full_name(), "Please specify test binary by +bin=binary_name")
|
||||
`uvm_info(get_full_name(), $sformatf("Running test : %0s", bin), UVM_LOW)
|
||||
f_bin = $fopen(bin,"rb");
|
||||
if (!f_bin)
|
||||
`uvm_fatal(get_full_name(), $sformatf("Cannot open file %0s", bin))
|
||||
while ($fread(r8,f_bin)) begin
|
||||
`uvm_info(`gfn, $sformatf("Init mem [0x%h] = 0x%0h", addr, r8), UVM_FULL)
|
||||
mem.write(addr, r8);
|
||||
addr++;
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual task wait_for_test_done();
|
||||
// TODO(taliu): We need a consistent approach to determine the test is completed for both
|
||||
// random instruction test and firmware based test. For example, it could be done by writing to
|
||||
// a specific memory location of the test signature. Right now the random instruction generator
|
||||
// use ecall instruction to indicate the end of the program. It could be changed to align with
|
||||
// firmware test completion mechanism.
|
||||
fork
|
||||
begin
|
||||
wait (dut_vif.ecall === 1'b1);
|
||||
`uvm_info(`gfn, "ECALL instruction is detected, test done", UVM_LOW)
|
||||
// De-assert fetch enable to finish the test
|
||||
dut_vif.fetch_enable = 1'b0;
|
||||
// Wait some time for the remaining instruction to finish
|
||||
clk_vif.wait_clks(100);
|
||||
end
|
||||
begin
|
||||
clk_vif.wait_clks(timeout_in_cycles);
|
||||
`uvm_fatal(`gfn, "TEST TIMEOUT!!")
|
||||
end
|
||||
join_any
|
||||
endtask
|
||||
|
||||
endclass
|
17
dv/uvm/tests/core_ibex_test_pkg.sv
Normal file
17
dv/uvm/tests/core_ibex_test_pkg.sv
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2018 lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// ---------------------------------------------
|
||||
// Core ibex test package
|
||||
// ---------------------------------------------
|
||||
package core_ibex_test_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
import core_ibex_env_pkg::*;
|
||||
import ibex_mem_intf_agent_pkg::*;
|
||||
|
||||
`include "core_ibex_vseq.sv"
|
||||
`include "core_ibex_base_test.sv"
|
||||
|
||||
endpackage
|
30
dv/uvm/tests/core_ibex_vseq.sv
Normal file
30
dv/uvm/tests/core_ibex_vseq.sv
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// ---------------------------------------------
|
||||
// Ibex core virtual sequence
|
||||
// ---------------------------------------------
|
||||
|
||||
class core_ibex_vseq extends uvm_sequence;
|
||||
|
||||
ibex_mem_intf_slave_seq instr_intf_seq;
|
||||
ibex_mem_intf_slave_seq data_intf_seq;
|
||||
mem_model_pkg::mem_model mem;
|
||||
|
||||
`uvm_object_utils(core_ibex_vseq)
|
||||
`uvm_declare_p_sequencer(core_ibex_vseqr)
|
||||
`uvm_object_new
|
||||
|
||||
virtual task body();
|
||||
instr_intf_seq = ibex_mem_intf_slave_seq::type_id::create("instr_intf_seq");
|
||||
data_intf_seq = ibex_mem_intf_slave_seq::type_id::create("data_intf_seq");
|
||||
instr_intf_seq.m_mem = mem;
|
||||
data_intf_seq.m_mem = mem;
|
||||
fork
|
||||
instr_intf_seq.start(p_sequencer.instr_if_seqr);
|
||||
data_intf_seq.start(p_sequencer.data_if_seqr);
|
||||
join_none
|
||||
endtask
|
||||
|
||||
endclass
|
28
dv/uvm/vcs.tcl
Normal file
28
dv/uvm/vcs.tcl
Normal file
|
@ -0,0 +1,28 @@
|
|||
# TCL file invoked from VCS's simv at run-time using this: -ucli -do <this file>
|
||||
|
||||
# Syntax: fsdbDumpfile FSDB_Name [Limit_Size]
|
||||
fsdbDumpfile "waves.fsdb"
|
||||
|
||||
# Syntax: fsdbDumpvars [depth] [instance] [option]*
|
||||
##############################################################################
|
||||
# Option Description
|
||||
##############################################################################
|
||||
# +mda Dumps memory and MDA signals in all scopes.
|
||||
# +packedmda Dumps packed signals
|
||||
# +struct Dumps structs
|
||||
# +skip_cell_instance=mode Enables or disables cell dumping
|
||||
# +strength Enables strength dumping
|
||||
# +parameter Dumps parameters
|
||||
# +power Dumps power-related signals
|
||||
# +trace_process Dumps VHDL processes
|
||||
# +no_functions Disables dumping of functions
|
||||
# +sva Dumps assertions
|
||||
# +Reg_Only Dumps only reg type signals
|
||||
# +IO_Only Dumps only IO port signals
|
||||
# +by_file=<filename> File to specify objects to add
|
||||
# +all Dumps memories, MDA signals, structs, unions,power, and packed structs
|
||||
fsdbDumpvars 0 core_ibex_tb_top +all
|
||||
fsdbDumpSVA 0 core_ibex_tb_top.dut
|
||||
|
||||
run
|
||||
quit
|
Loading…
Add table
Add a link
Reference in a new issue