Initial commit
This commit is contained in:
commit
e4e8457f95
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
logs
|
||||
obj_dir
|
42
Makefile
Normal file
42
Makefile
Normal file
@ -0,0 +1,42 @@
|
||||
# Make and run project
|
||||
UVM_HOME=/home/mahesh/git/uvm-verilator
|
||||
|
||||
PROJ=uvm_tb
|
||||
|
||||
SV_FILES=$(shell ls *.sv)
|
||||
SV_SRC=$(UVM_HOME)/src/uvm_pkg.sv tb_pkg.sv
|
||||
SV_DEPS=$(SV_FILES)
|
||||
|
||||
CPP_SRC=sim_$(PROJ).cpp
|
||||
|
||||
TIMESCALE= --timescale '1ns/1ns'
|
||||
|
||||
UVM_DEFINES=+define+UVM_NO_DPI \
|
||||
+define+UVM_REPORT_DISABLE_FILE_LINE
|
||||
DISABLED_WARNINGS=-Wno-WIDTHTRUNC -Wno-WIDTHEXPAND \
|
||||
-Wno-CASTCONST -Wno-CONSTRAINTIGN \
|
||||
-Wno-MISINDENT -Wno-REALCVT \
|
||||
-Wno-SYMRSVDWORD -Wno-CASEINCOMPLETE
|
||||
|
||||
ifndef TEST_NAME
|
||||
TEST_NAME=test_base
|
||||
endif
|
||||
|
||||
build: $(SV_DEPS)
|
||||
verilator -I$(UVM_HOME)/src -I. \
|
||||
-o $(PROJ).sim \
|
||||
--binary \
|
||||
-j 4 \
|
||||
--error-limit 10 \
|
||||
--timing $(TIMESCALE) \
|
||||
+define+SVA_ON \
|
||||
$(UVM_DEFINES) \
|
||||
$(DISABLED_WARNINGS) \
|
||||
$(SV_SRC)
|
||||
|
||||
run:
|
||||
if [ ! -d logs/$(TEST_NAME) ]; then mkdir -p logs/$(TEST_NAME); fi
|
||||
cd logs/$(TEST_NAME) && ../../obj_dir/$(PROJ).sim +UVM_TESTNAME=$(TEST_NAME) |& tee sim.log
|
||||
|
||||
clean:
|
||||
rm -rf obj_dir
|
123
agent_reset.sv
Normal file
123
agent_reset.sv
Normal file
@ -0,0 +1,123 @@
|
||||
class sequencer_reset extends uvm_sequencer;
|
||||
`uvm_component_utils(sequencer_reset)
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class driver_reset extends uvm_driver;
|
||||
virtual testbench_if tb_if;
|
||||
|
||||
`uvm_component_utils(driver_reset)
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
if (!uvm_config_db#(virtual testbench_if)::get(this, "", "tb_vif", tb_if)) begin
|
||||
`uvm_fatal("CFG_DB_FAIL", $sformatf("Failed to fetch interface for %0s", get_full_name()))
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
forever begin
|
||||
@(posedge tb_if.rst_n);
|
||||
while (tb_if.rst_n != 0) begin
|
||||
seq_item_port.get_next_item(req);
|
||||
drive_item(req);
|
||||
seq_item_port.item_done();
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task drive_item(uvm_sequence_item req);
|
||||
`uvm_info("drive_item", $sformatf("Initiating reset..."), UVM_LOW)
|
||||
tb_if.rst_n = 0;
|
||||
repeat(10) @(posedge tb_if.clk);
|
||||
tb_if.rst_n = 1;
|
||||
`uvm_info("drive_item", $sformatf("Reset done."), UVM_LOW)
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class monitor_reset extends uvm_monitor;
|
||||
virtual testbench_if tb_if;
|
||||
|
||||
`uvm_component_utils(monitor_reset)
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
if (!uvm_config_db#(virtual testbench_if)::get(this, "", "tb_vif", tb_if)) begin
|
||||
`uvm_fatal("CFG_DB_FAIL", $sformatf("Failed to fetch interface for %0s", get_full_name()))
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
fork
|
||||
do_monitor();
|
||||
join
|
||||
endtask
|
||||
|
||||
task do_monitor();
|
||||
bit prev_val;
|
||||
|
||||
if (tb_if.rst_n === 1'b0) begin
|
||||
`uvm_info("do_monitor", $sformatf("Starting with reset asserted"), UVM_LOW)
|
||||
end else if (tb_if.rst_n === 1'b1) begin
|
||||
`uvm_info("do_monitor", $sformatf("Starting with reset de-asserted"), UVM_LOW)
|
||||
end else begin
|
||||
`uvm_info("do_monitor", $sformatf("Starting with reset unknown"), UVM_LOW)
|
||||
end
|
||||
|
||||
forever begin
|
||||
prev_val = tb_if.rst_n;
|
||||
|
||||
@(tb_if.rst_n);
|
||||
if ((prev_val !== 1'b1) && (tb_if.rst_n !== 1'b1)) begin
|
||||
`uvm_info("drive_item", $sformatf("Reset de-asserted"), UVM_LOW)
|
||||
end
|
||||
if ((prev_val !== 1'b0) && (tb_if.rst_n !== 1'b0)) begin
|
||||
`uvm_info("drive_item", $sformatf("Reset asserted"), UVM_LOW)
|
||||
end
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class agent_reset extends uvm_agent;
|
||||
sequencer_reset sequencer;
|
||||
driver_reset driver;
|
||||
monitor_reset monitor;
|
||||
|
||||
`uvm_component_utils(agent_reset)
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
sequencer = sequencer_reset::type_id::create("sequencer", this);
|
||||
driver = driver_reset::type_id::create("driver", this);
|
||||
monitor = monitor_reset::type_id::create("monitor", this);
|
||||
|
||||
`uvm_info("build_phase", $sformatf("Building done"), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
|
||||
driver.seq_item_port.connect(sequencer.seq_item_export);
|
||||
|
||||
`uvm_info("connect_phase", $sformatf("Connecting done"), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
endclass
|
7
agent_tb.sv
Normal file
7
agent_tb.sv
Normal file
@ -0,0 +1,7 @@
|
||||
class sequencer_tb extends uvm_sequencer;
|
||||
`uvm_component_utils(sequencer_tb)
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
endclass
|
40
design.sv
Normal file
40
design.sv
Normal file
@ -0,0 +1,40 @@
|
||||
// Some simple design
|
||||
|
||||
module rtl_design(design_if intf);
|
||||
|
||||
logic [31:0] data_out_drv = 0;
|
||||
assign intf.data_out = data_out_drv;
|
||||
|
||||
string trk_name;
|
||||
integer trk_h;
|
||||
|
||||
initial begin
|
||||
data_out_drv = 32'h0;
|
||||
end
|
||||
|
||||
always @(posedge intf.clk) begin
|
||||
if (intf.rst_n) begin
|
||||
data_out_drv = intf.data_in;
|
||||
end
|
||||
end
|
||||
|
||||
always_latch @(intf.rst_n) begin
|
||||
if (!intf.rst_n) begin
|
||||
data_out_drv = 32'h0;
|
||||
end
|
||||
end
|
||||
|
||||
initial begin
|
||||
trk_name = $sformatf("%m.out");
|
||||
trk_h = $fopen(trk_name, "w");
|
||||
$fdisplay(trk_h, "Tracker: %s", trk_name);
|
||||
$display("Starting tracker: %s", trk_name);
|
||||
$fmonitor(trk_h, "@%6t: %b %b %h %h", $time,
|
||||
intf.rst_n, intf.clk, intf.data_in, intf.data_out);
|
||||
end
|
||||
|
||||
function void be_done();
|
||||
$display("Closing tracker %s", trk_name);
|
||||
$fclose(trk_h);
|
||||
endfunction
|
||||
endmodule
|
23
interfaces.sv
Normal file
23
interfaces.sv
Normal file
@ -0,0 +1,23 @@
|
||||
// Design and Testbench interfaces
|
||||
interface design_if (
|
||||
input clk);
|
||||
|
||||
logic rst_n;
|
||||
logic [31:0] data_in;
|
||||
logic [31:0] data_out;
|
||||
|
||||
modport DN (output data_out, input rst_n, clk, data_in);
|
||||
modport TB (input clk, data_out, output rst_n, data_in);
|
||||
endinterface
|
||||
|
||||
interface testbench_if (
|
||||
input clk,
|
||||
virtual design_if d1_if,
|
||||
virtual design_if d2_if);
|
||||
|
||||
logic rst_n;
|
||||
|
||||
modport DN (input rst_n, clk);
|
||||
modport TB (input clk, output rst_n);
|
||||
endinterface
|
||||
|
70
seq_basic.sv
Normal file
70
seq_basic.sv
Normal file
@ -0,0 +1,70 @@
|
||||
class seq_base extends uvm_sequence;
|
||||
testbench_env tb_env;
|
||||
|
||||
`uvm_object_utils(seq_base)
|
||||
|
||||
function new(string name = "seq_base");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
function void set_handles(testbench_env env);
|
||||
tb_env = env;
|
||||
endfunction
|
||||
|
||||
virtual task body();
|
||||
bit ok = uvm_config_db#(testbench_env)::get(m_sequencer, "", "tb_env", tb_env);
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class seq_basic extends seq_base;
|
||||
`uvm_object_utils(seq_basic)
|
||||
|
||||
function new(string name = "seq_basic");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
virtual task body();
|
||||
super.body();
|
||||
|
||||
`uvm_info("body", $sformatf("Initiating stimulus ..."), UVM_LOW)
|
||||
fork
|
||||
begin
|
||||
d_stimulus(tb_env.tb_if.d1_if, 1);
|
||||
end
|
||||
begin
|
||||
d_stimulus(tb_env.tb_if.d2_if, 2);
|
||||
end
|
||||
join
|
||||
`uvm_info("body", $sformatf("Stimulus done."), UVM_LOW)
|
||||
endtask
|
||||
|
||||
task d_stimulus(virtual design_if d_if, int inst_n);
|
||||
`uvm_info("d_stimulus", $sformatf("Inst-%0d: Initiating stimulus...", inst_n), UVM_LOW);
|
||||
repeat(20) @(negedge tb_env.tb_if.clk);
|
||||
d_if.data_in = {inst_n[15:0], 16'hd1};
|
||||
`uvm_info("d_stimulus", $sformatf("Inst-%0d: Driving data_in=0x%h", inst_n, d_if.data_in), UVM_LOW);
|
||||
repeat(50) @(negedge tb_env.tb_if.clk);
|
||||
d_if.data_in = {inst_n[15:0], 16'hd2};
|
||||
`uvm_info("d_stimulus", $sformatf("Inst-%0d: Driving data_in=0x%h", inst_n, d_if.data_in), UVM_LOW);
|
||||
repeat(20) @(negedge tb_env.tb_if.clk);
|
||||
`uvm_info("d_stimulus", $sformatf("Inst-%0d: ... stimulus done", inst_n), UVM_LOW);
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class seq_reset extends seq_base;
|
||||
`uvm_object_utils(seq_reset)
|
||||
|
||||
function new(string name = "seq_reset");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
virtual task body();
|
||||
super.body();
|
||||
|
||||
`uvm_info("body", $sformatf("Initiating reset..."), UVM_LOW)
|
||||
tb_env.tb_if.rst_n = 0;
|
||||
repeat(10) @(posedge tb_env.tb_if.clk);
|
||||
tb_env.tb_if.rst_n = 1;
|
||||
`uvm_info("body", $sformatf("Reset done."), UVM_LOW)
|
||||
endtask
|
||||
endclass
|
17
tb_pkg.sv
Normal file
17
tb_pkg.sv
Normal file
@ -0,0 +1,17 @@
|
||||
`include "interfaces.sv"
|
||||
`include "design.sv"
|
||||
package tb_pkg;
|
||||
import uvm_pkg::*;
|
||||
|
||||
// Environment
|
||||
`include "agent_reset.sv"
|
||||
`include "agent_tb.sv"
|
||||
`include "testbench_env.sv"
|
||||
|
||||
// Sequences
|
||||
`include "seq_basic.sv"
|
||||
|
||||
// Tests
|
||||
`include "test_base.sv"
|
||||
endpackage
|
||||
`include "uvm_tb.sv"
|
76
test_base.sv
Normal file
76
test_base.sv
Normal file
@ -0,0 +1,76 @@
|
||||
class test_base extends uvm_test;
|
||||
`uvm_component_utils(test_base)
|
||||
|
||||
testbench_env tb_env;
|
||||
uvm_table_printer tb_printer;
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
tb_env = testbench_env::type_id::create("tb_env", this);
|
||||
tb_printer = new("tb_printer");
|
||||
|
||||
uvm_config_db#(testbench_env)::set(uvm_root::get(), "*", "tb_env", tb_env);
|
||||
endfunction
|
||||
|
||||
virtual function void end_of_elaboration_phase(uvm_phase phase);
|
||||
`uvm_info("end_of_elaboration_phase", $sformatf("Topology:\n%s", this.sprint(tb_printer)), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
uvm_objection objection;
|
||||
|
||||
objection = phase.get_objection();
|
||||
|
||||
`uvm_info("run_phase", $sformatf("Raising objection"), UVM_LOW)
|
||||
phase.raise_objection(this);
|
||||
|
||||
run_reset_phase(phase);
|
||||
|
||||
run_test_phase(phase);
|
||||
|
||||
run_flush_phase(phase);
|
||||
|
||||
objection.set_drain_time(this, 20);
|
||||
`uvm_info("run_phase", $sformatf("Dropping objection"), UVM_LOW)
|
||||
phase.drop_objection(this);
|
||||
endtask
|
||||
|
||||
virtual task run_reset_phase(uvm_phase phase);
|
||||
seq_reset rst_seq;
|
||||
|
||||
`uvm_info("run_reset_phase", $sformatf("Starting reset"), UVM_LOW)
|
||||
rst_seq = seq_reset::type_id::create("reset_seq", this);
|
||||
rst_seq.start(tb_env.tb_sequencer);
|
||||
`uvm_info("run_reset_phase", $sformatf("Finishing reset"), UVM_LOW)
|
||||
endtask
|
||||
|
||||
virtual task run_test_phase(uvm_phase phase);
|
||||
`uvm_warning("run_test_phase", $sformatf("This content is expected to be implemented in specific tests"))
|
||||
endtask
|
||||
|
||||
virtual task run_flush_phase(uvm_phase phase);
|
||||
`uvm_info("run_flush_phase", $sformatf("Finishing test"), UVM_LOW)
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class test_basic extends test_base;
|
||||
`uvm_component_utils(test_basic)
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
virtual task run_test_phase(uvm_phase phase);
|
||||
seq_basic tst_seq;
|
||||
|
||||
tst_seq = seq_basic::type_id::create("test_seq_basic");
|
||||
`uvm_info("run_test_phase", $sformatf("Starting stimulus"), UVM_LOW)
|
||||
tst_seq.start(tb_env.tb_sequencer);
|
||||
`uvm_info("run_test_phase", $sformatf("Finishing stimulus"), UVM_LOW)
|
||||
endtask
|
||||
endclass
|
40
testbench_env.sv
Normal file
40
testbench_env.sv
Normal file
@ -0,0 +1,40 @@
|
||||
// Top class
|
||||
class testbench_env extends uvm_component;
|
||||
string name;
|
||||
virtual testbench_if tb_if;
|
||||
|
||||
agent_reset rst_agt;
|
||||
sequencer_tb tb_sequencer;
|
||||
|
||||
`uvm_component_utils(testbench_env)
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
`uvm_info("new", $sformatf("Initialized testbench %s", name), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
rst_agt = agent_reset::type_id::create("reset_agent", this);
|
||||
tb_sequencer = sequencer_tb::type_id::create("tb_sequencer", this);
|
||||
endfunction
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
|
||||
if (!uvm_config_db#(virtual testbench_if)::get(this, "", "tb_vif", tb_if)) begin
|
||||
`uvm_fatal("CFG_DB_FAIL", $sformatf("Failed to fetch interface for %0s", get_full_name()))
|
||||
end
|
||||
|
||||
`uvm_info("connect_phase", $sformatf("Build phase complete"), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
function uvm_sequencer get_tb_sequencer();
|
||||
return tb_sequencer;
|
||||
endfunction
|
||||
|
||||
function uvm_sequencer get_rst_sequencer();
|
||||
return rst_agt.sequencer;
|
||||
endfunction
|
||||
endclass
|
55
uvm_tb.sv
Normal file
55
uvm_tb.sv
Normal file
@ -0,0 +1,55 @@
|
||||
// uvm_tb in SystemVerilog
|
||||
import uvm_pkg::*;
|
||||
|
||||
module uvm_tb (input logic sys_clk);
|
||||
logic clk;
|
||||
logic rst_n;
|
||||
logic [31:0] d1_data_i;
|
||||
logic [31:0] d1_data_o;
|
||||
logic [31:0] d2_data_i;
|
||||
logic [31:0] d2_data_o;
|
||||
|
||||
design_if d1_if(.clk(clk));
|
||||
assign d1_if.rst_n = rst_n;
|
||||
assign d1_if.data_in = d1_data_i;
|
||||
assign d1_data_o = d1_if.data_out;
|
||||
|
||||
design_if d2_if(.clk(clk));
|
||||
assign d2_if.rst_n = rst_n;
|
||||
assign d2_if.data_in = d2_data_i;
|
||||
assign d2_data_o = d2_if.data_out;
|
||||
|
||||
testbench_if uvm_tb_if(
|
||||
.clk(clk),
|
||||
.d1_if(d1_if),
|
||||
.d2_if(d2_if)
|
||||
);
|
||||
assign rst_n = uvm_tb_if.rst_n;
|
||||
|
||||
rtl_design d1(d1_if.DN);
|
||||
|
||||
rtl_design d2(d2_if.DN);
|
||||
|
||||
initial begin
|
||||
// TbEnv t = new(.name("uvm_tbTbEnv"), .parent(null));
|
||||
// // .intf(uvm_tb_if.TB));
|
||||
|
||||
// t.set_handles(uvm_tb_if);
|
||||
// // t.run_phase();
|
||||
|
||||
// $display("Simulation with UVM done at %t", $time);
|
||||
// $finish;
|
||||
|
||||
uvm_config_db#(virtual testbench_if)::set(uvm_root::get(), "*", "tb_vif", uvm_tb_if);
|
||||
|
||||
run_test();
|
||||
end
|
||||
|
||||
// initial begin
|
||||
// $dumpfile("wave.vcd");
|
||||
// $dumpvars();
|
||||
// end
|
||||
|
||||
// TODO: Move to interface. Parameterize frequency
|
||||
always #5 clk = ~clk;
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user