In reply to Farhad:
I struggled with that question when testing small models for my assertions.
I came up with a solution that integrates the concepts of UVM, but without the interface, vif, and UVM classes, the environment, and tests. I use UVM for displays.
**** NOTE: ****
**** I show 2 variations for testing this counter, one simple one, the other, a bit more details and more a la UVM with tasks for the drivers once I detect the “kind” of transaction needed. Anyway, that should give a flavor of my approach.
Using classes will allow you to more easily transition to a full UVM.
Below are the models to verify a counter with strange requirements.
The counter model is at the end of the code. On the testbench I use the following:
- counter_pkg: for the enumeration type
- class data_item: Items to be randomized
- class transaction extends data_item; Other items to be randomized.
Constraints are defined here.
The extension is used as a demo, but is nice to have if needed - class simple_random_sequence; task to randomize the items, It executes nothing, just randomizes per the constraints.
- module counter_max_tb_using_class; the testbench
The testbench includes:
- variables, DUT instantiation
- simple_random_sequence class instantiation
- test, includes reset, loop to randomize the variable, NBA assign the randomized data
// test using simple_random_sequence
always @ (posedge clk) begin : random1
rst_n <= 1'b1;
repeat(3) @ (negedge clk) rst_n <= 1'b0;
repeat(3) @ (negedge clk)rst_n <= 1'b1;
// dada and load
for (int i=0; i<40; i++) begin : for1
simple_rand_sequence_ld_mostly_hi.run();
data_in <= simple_rand_sequence_ld_mostly_hi.tx.data;
ld <= simple_rand_sequence_ld_mostly_hi.tx.ld;
@ (posedge clk);
end : for1
$display("End of test");
$finish;
end : random1
// **************** Counter pACKAGE
package counter_pkg;
timeunit 1ns; timeprecision 100ps;
`define TOP counter_tb
typedef enum {CT_LOAD, CT_RESET, CT_WAIT, CT_DONE} ct_scen_e;
endpackage : counter_pkg
//************** Testbench *****************************
import uvm_pkg::*;
`include "uvm_macros.svh"
class data_item;
rand logic[3:0] data;
endclass : data_item
class transaction extends data_item;
rand logic ld;
// 1'b0 80% of time, 1'b1 20% of the time
constraint values { ld dist {1'b0 := 80, 1'b1 := 20}; }
endclass : transaction
class simple_random_sequence;
transaction tx=new();
// randomize
virtual task run();
if (!randomize(tx)) `uvm_error("MYERR", "This is a randomize error");
// if(!randomize(tx)) $error("randomization failure");
endtask : run
endclass : simple_random_sequence
module counter_max_tb_using_class;
parameter MAX_COUNT=9, MIN_COUNT=2;
logic[3:0] data_in=0, data=0;
logic ld=0;
logic[3:0] counter, counter2;
logic clk=1'b1, rst_n=1'b1;
simple_random_sequence simple_rand_sequence_ld_mostly_hi=new();
counter_max counter_max1(.*);
// counter_max counter_max2(.counter(counter2), .*);
initial forever #10 clk=!clk;
// test using simple_random_sequence
always @ (posedge clk) begin : random1
rst_n <= 1'b1;
repeat(3) @ (negedge clk) rst_n <= 1'b0;
repeat(3) @ (negedge clk)rst_n <= 1'b1;
// dada and load
for (int i=0; i<40; i++) begin : for1
simple_rand_sequence_ld_mostly_hi.run();
data_in <= simple_rand_sequence_ld_mostly_hi.tx.data;
ld <= simple_rand_sequence_ld_mostly_hi.tx.ld;
@ (posedge clk);
end : for1
$display("End of test");
$finish;
end : random1
endmodule : counter_max_tb_using_class
You can go a bit more fancy on the drivers by doing something like more a la UVM
import counter_pkg::*;
class data_item;
rand logic[3:0] data;
endclass : data_item
class transaction extends data_item;
rand logic ld=0;
int reset_cycles, idle_cycles;
rand ct_scen_e kind;
// constraint values { ld dist {1'b0 := 80, 1'b1 := 20}; } // 0 80% of time
constraint data_range { data > 2 && data <=9; }
constraint cst_xact_kind {
kind dist {
CT_LOAD := 5,
CT_RESET := 2,
CT_WAIT := 97,
CT_DONE := 1
};
} // cst_xact_kind
endclass : transaction
class simple_random_sequence;
transaction tx=new();
// randomize
virtual task run();
ap_rand_seq: assert(randomize(tx));
endtask : run
endclass : simple_random_sequence
module counter_max_tb_simple;
parameter MAX_COUNT_TB=6, MIN_COUNT_TB=3;
// defparam counter_max1.MIN_COUNT=3;
// illegal because have parameter port list
logic[3:0] data_in=0, data=0;
logic ld=0;
logic[3:0] counter, counter2;
logic clk=1'b1, rst_n=1'b1;
simple_random_sequence seq=new();
counter_max #(.MAX_COUNT(MAX_COUNT_TB),
.MIN_COUNT(MIN_COUNT_TB)) counter_max1(.*);
// counter_max counter_max2(.counter(counter2), .*);
initial forever #10 clk=!clk;
// test using simple_random_sequence
always @ (negedge clk) begin : random1
rst_n <= 1'b1; ld <=1'b0;
repeat(3) @ (negedge clk) rst_n <= 1'b0;
repeat(3) @ (negedge clk)rst_n <= 1'b1;
// dada and load
for (int i=0; i<100; i++) begin : for1
@ (negedge clk);
seq.run();
case (seq.tx.kind)
CT_LOAD : begin
// $display("PUSH");
//`ovm_info({get_type_name(),":drive_dut"},{"rsp_txn - pre",rsp_txn.convert2string()},OVM_LOW)
load_task(seq.tx.data);
end
CT_RESET : begin
// $display("POP");
//`ovm_info({get_type_name(),":drive_dut"},{"rsp_txn - pre",rsp_txn.convert2string()},OVM_LOW)
reset_task();
end
CT_WAIT : begin
//$display("PUSH_POP");
//`ovm_info({get_type_name(),":drive_dut"},{"rsp_txn -pre",rsp_txn.convert2string()},OVM_LOW)
idle_task(seq.tx.data);
end
CT_DONE : begin
// $display("IDLE");
//`ovm_info({get_type_name(),":drive_dut"},{"rsp_txn -pre",rsp_txn.convert2string()},OVM_LOW)
done_task();
end // seq.tx.idle_cycles);
endcase
// @ (negedge clk);
end : for1
$display("End of test");
$display("counter_max1.cover_count=%d, counter_max1.fail_count=%d",
counter_max1.cover_count, counter_max1.fail_count);
$finish;
end : random1
// load counter
task load_task(int data);
data_in <= data;
ld <= 1'b1;
@ (negedge clk)ld <= 1'b0;
endtask : load_task
// reset
task reset_task();
ld <= 1'b0;
repeat(1) rst_n <= 1'b0;
@ (negedge clk)rst_n <= 1'b1;
endtask : reset_task
// IDLE
task idle_task(int data);// for now, make idle for 4 cycles
automatic logic[3:0] v=data;
for (int i=0; i<4; i++) begin
ld <= 1'b0;
assert(randomize(v));
data_in <= v;
@ (negedge clk);
end
endtask : idle_task
// DONE, for now, a do nothing
task done_task();
@ (negedge clk);
endtask : done_task
endmodule : counter_max_tb_simple
Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448
…
- SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats | Verification Academy
- Free books: Component Design by Example FREE BOOK: Component Design by Example … A Step-by-Step Process Using VHDL with UART as Vehicle | Verification Academy
Real Chip Design and Verification Using Verilog and VHDL($3) Amazon.com - Papers:
- Understanding the SVA Engine,
Verification Horizons - July 2020 | Verification Academy - SVA Alternative for Complex Assertions
Verification Horizons - March 2018 Issue | Verification Academy - SVA in a UVM Class-based Environment
SVA in a UVM Class-based Environment | Verification Horizons | Verification Academy
Udemy courses by Srinivasan Venkataramanan (http://cvcblr.com/home.html)
https://www.udemy.com/course/sva-basic/
https://www.udemy.com/course/sv-pre-uvm/