Initial commit

This commit is contained in:
Mahesh Asolkar 2024-08-11 21:48:11 -07:00
commit e4e8457f95
11 changed files with 495 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
logs
obj_dir

42
Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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