Professional Documents
Culture Documents
Agenda
Day 1
Introduction Data Types Procedural Statements and Routines
Day2
Basic OOP Connecting the Testbench and Design Randomization
Day3
Threads and Interprocess Communication Advanced OOP concepts Advanced Interfaces
Day4
Functional Coverage Assertions
What is the goal of verification? To make sure that the design is an accurate representation of the specification. Bugs are what you get when there is a discrepancy. Each bug found before tape-out is one fewer that ends up in the customers hand. Once you verified that the DUT performs its designated functions correctly, you need to see how it operates when there are errors.
The purpose of a testbench is to determine the correctness of the design under test (DUT). This is accomplished by the following steps. Generate stimulus Apply stimulus to the DUT Capture the response Check for correctness Measure progress against the overall verification goals
Time
Coverage convergence
Add constraints
Directed testcase
Device Configuration Environment Configuration Input Data Protocol exceptions Delays Errors and violations
Functional
Agent
Scoreboard
Checker
Command
Driver
Assertions
Monitor
Signal
DUT
Data Types
Data Types
Two-state : better performance, reduced memory usage Queues, dynamic and associative arrays and automatic storage: reduced memory usage, built-in support for searching and sorting Unions and packed structures: allows multiple views of same data Classes and structures: support for abstract data structures Strings: built-in string support Enumerated types: code is easier to write and understand
Verilog provides reg, wire, integer, time, real logic type Can be driven by continuous assignments, gates and modules in addition to being a variable Two-state types bit Unsigned byte, shortint, int, longint Signed
// // // // // //
single bit 32-bit unsigned integer 32-bit signed integer 8-bit signed integer 16-bit signed integer 64-bit signed integer
// To get unsigned from signed types byte unsigned u_byte; // 2-state, 8-bit unsigned integer
Fixed-Size Arrays
SystemVerilog lets you use the shortcut of just giving the array size (C-Style)
int sv_mem[16]; // equivalent to int sv_mem[0:15];
Multidimensional arrays
int array2 [0:7] [0:3]; // verbose declaration int array3 [8] [4]; // compact declaration
Initializing an array
int ascend [4] = {0,1,2,3}; // initialize 4 elements
Multi-dimensional Array
Unpacked Array
bit [7:0] b_array [0:2] ;
Unused Space
Stored in one long word
b_array
b_array[1][6]
Dynamic Arrays
Arrays which can grow and shrink Array size will be decided at run-time Declared using a empty word subscript [] Array is initially empty and space is allocated when new[] is called If a name of an array is passed to new[] operator, then the values in the array are copied
Queues
Queues can also grow and shrink similar to dynamic arrays But with a queue you can add and remove elements anywhere Search and sort can be done easily Declared using a $ word subscript i.e., [$]
Queue - Example
int j = 1, b[$] = {3,4}, q[$] = {0,2,5} ; // {0,2,5} Initial Queue initial begin q.insert(1,j); // {0,1,2,5} Insert 1 at 1 // {0,1,2,3,4,5} q.insert(3,b); // Insert whole b at 3 q.delete(1); // {0,2,3,4,5} // Delete #1 element q.push_front(6) // {6,0,2,3,4,5} j = q.pop_back; // {6,0,2,3,4} j = 5 end
Associative Arrays
Memory gets allocated only when an element is written
4521
200,000
The memory used to store the above is far less than would be needed to store a fixed or dynamic array with 200,000 entrires You can use the function exists to check if an element exists. Ex : if (data.exists(4521))
Array Methods
Array reduction methods sum, product, and, or, xor Array locator methods min, max, unique find, find_index, find_first, find_first_index, find_last, find_last_index
sum-with
User-Defined Types
Enumerated Types
Creates a strong variable type that is limited to a set of specified names. Ex : instruction opcode, state machine value
enum {RED, BLUE, GREEN} color; // Defining enumerated values typedef enum {INIT, DECODE=2,IDLE} fsm_type_e; color = color.first; do begin $display(Color = %0d/%0s,color,color.name); color = color.next; end while (color != color.first); // Done at wrap-around
Const modifier allows you to make a variable that can be initialized in the declaration.
initial begin const byte colon = :; . end
SystemVerilog string type holds variable length strings. Unlike C, there is no null character at the end of the string. Strings use dynamic memory allocation.
String Methods
string s; initial begin s = SystemVerilog; $display(s.getc(0)); // Display : 83 // Display : SYSTEMVERILOG $display(s.toupper()); s = {s,3.1b}; // SystemVerilog3.1b s.putc(s.len()-1,a); // change b -> a $display(s.substr(2,5)); // Display : stem my_log( $psprintf(%s %5d,s,42)); end task my_log (string message); $display(@%0d: %s,$time,message); endtask
Expression Width
bit [7:0] b8; bit one = 1b1; // Single bit $displayb(one + one); // A: 1+1 = 0 b8 = one + one; // B: 1+1 = 2 $displayb(b8); $displayb(one + one + 2b0); // C: 1+1 = 2 with constant $displayb(2(one) + one); // D: 1+1 = 2 with cast
Procedural Statements
Can declare a variable inside a for loop Increment ++ and decrement -- operators are available The above operators in both pre and post forms Can put the same label on matching end and join Can put a label on statements like endmodule, endtask, endfunction etc break and continue statements to control the flow in loop structures
Any debug routine should be a void function rather than a task so that it can be called from any function or task
function void print_state (); $display(@%0d : state = %0s,$time,cur_state.name); endfunction
Tasks, Functions
Task and function can be defined inside following : modules, packages, interfaces, program blocks, class Task/function can be called inside following : program blocks, modules, procedural blocks
Routine Arguments
Argument direction
task T3 (a,b,output bit [15:0] u, v);
The arguments a and b are input logic, 1 bit wide. The arguments u and v are 16-bit output bit types.
In SystemVerilog you can specify a default value that is used if you leave out an argument in the call
function void print_sum (ref int a[], input int start = 0, input int last = -1); int sum = 0; if (last == -1 || last > a.size) last = a.size ; for (int i = start; i <last; i++) sum += a[i]; $display(The sum of the array is %d,sum); endfunction
program automatic test ; task wait_for_mem (input [31:0] addr, expect_data, output success); while(bus.addr !== addr) @(bus.addr); success = (bus.data == expect_data); endtask endprogram
You can call this task multiple times concurrently as the addr and expect_data arguments are stored separately for each call
Time Values
`timescale compiler directive You must compile the files in proper order to be sure all the delays use the proper scale and precision. The timeunit and timeprecision declarations eliminate this ambiguity. Put these in every module that has delay.
module timing; timeunit 1ns; timeprecision 1ps; endmodule
Day 1 Summary
logic, bit, byte, shortint, int, longint
Fixed size arrays, dynamic arrays, queues, associative arrays Packed arrays and unpacked arrays User defined types, structures, enumerated types, constants and strings Improvements in procedural statements and operators Arguments : C-style declarations, sticky direction, default values, pass by reference Automatic for calling multiple times Time values
ThankYou
Day 2 - Agenda
Basic OOP
Introduction
OOP Object Oriented Programming Lets you create complex data types and tie them together with routines that work with them When you work with transactions instead of signal transitions, you are more productive
OOP Terminology
Class Basic building block containing routines and variables Object An instance of a class Handle A pointer to an object Property A variable that holds a data inside class declaration Method The procedural code that manipulates variables Prototype The header of a routine that shows the name, type and argument list
Object Deallocation
BusTran b; b = new ; b = new ; b = null ; // // // // create a handle Allocate a new BusTran Allocate a second one, free the first Deallocate the second
SystemVerilog performs automatic garbage collection when no more handles refer to an object
Class Routines
class BusTran; bit [31:0] addr, crc, data[8]; extern function void display(); endclass : BusTran function void BusTran::display(); $display(@%0d: BusTran addr=%h, crc=%h, addr,crc); $write(\tdata[0-7]=); foreach (data[i]) $write(%d ,data[i]); $display(); endfunction : display
Scoping Rules
A scope is a block of code such as a module, program, task, function, class, or begin-end block. The for and foreach loops automatically create a block so that an index variable can be declared or created local to the scope of the loop. If you forget to declare a variable, SystemVerilog looks up the higher scopes until it finds a match. Suggestion : Declare all your variables in the smallest scope that encloses all uses of the variable.
Name scope
int limit; // $root.limit program p; int limit, i; // $root.p.limit class Foo; int limit, array[]; // $root.p.Foo.limit task print (int limit); // $root.p.Foo.print.limit for (int i=0; i<limit;i++) $display(); endtask : print endclass : Foo initial begin int limit = $root.limit; // $root.p.$unnamed.limit end endprogram : p
Copying Objects
The above is a shallow copy, similar to photocopy of the original. If the class contains handle to another class, only the top level object is copied by new, not the lower level one.
Copying Objects
Copying Objects
// Create first object // Copy src to dst // Changes stats for dst &
startT=42
dst
id=3 stats
src
id=3 stats
startT=84
dst
id=3 stats
Copying Objects
src
id=3 stats
startT=42
dst
id=4 stats
startT=84
grant[1:0] clk
Testbench
Interface clk
Arbiter
Using modports
The modport construct in an interface lets you group signals and specify directions.
interface arb_if (input bit clk); logic [1:0] grant, request; logic reset; modport TEST (output request, reset, input grant, clk); modport DUT (input request, reset, clk, output grant); modport MONITOR (input request, grant, reset, clk); endinterface : arb_if
Clocking block
Synchronous signals can be bundled using clocking block.
interface mii_if; clocking mtx @(posedge tx_clk); output txd, tx_en, tx_err; endclocking : mtx clocking mrx @(posedge rx_clk); input rxd, rx_dv, rx_err; endclocking : mrx Clocking block name can be just used for waiting to its edge as follows
@ (this.sigs.mtx); this.sigs.mtx.txd <= nibble; The synchronous edge can be changed easily later.
The program block can read and write all signals in modules. But a module has no visibility into a program. A program can call a routine in a module to perform various actions. The routine can set values on internal signals, also known as backdoor load. For forcing a signal from a program block, you need to write a task in the module to do the force and then call from the program
Randomization
Randomization in SV
class Packet; // The random variables rand bit [31:0] src, dst, data[8]; randc bit [7:0] kind; // Limit the values for src constraint c {src >10; src <15;} endclass : Packet Packet p; initial begin p = new; assert(p.randomize()); transmit(p); end
Constraint Details
// Set membership and inside operator rand int c; int lo, hi; constraint c_range { c inside {[lo:hi]}; // lo <= c and c <= hi } // Inverted random set constraint constraint c_range { !(c inside {[lo:hi]}); }
Weighted Distributions
// Weighted random distribution with dist rand int src, dst; constraint c_dist { src dist {0:=40, [1:3]:=60}; // src = 0, weight = 40/220 // src = 1, weight = 60/220 // src = 2, weight = 60/220 // src = 3, weight = 60/220 }
Conditional constraints
// Constraint block with implication operator constraint c_io { (io_space_mode) -> addr[31] == 1b1; } // Constraint block with if-else operator constraint c_len_rw { if (op == READ) len inside {[BYTE:LWRD]}; else len == LWRD; }
// 0 to 65536
In-line Constraints
class Transaction; rand bit [31:0] addr, data; constraint c1 { addr inside {[0:100],[1000:2000]};} endclass Transaction t ; initial begin t = new; // addr is 50-100, 1000-1500, data < 10 assert(t.randomize() with {addr >= 50;addr <=1500; data <10;}); driveBus(t); end
Sum of elements
parameter MAX_TRANSFER_LEN=10; class StrobePat; rand bit strobe[MAX_TRANSFER_LEN]; constraint c_set_four {strobe.sum == 3h4;} endclass
Random Control
Use randcase to make weighted choice between several actions, without having to create a class and instance.
initial begin int len; randcase 1: len = 8: len = 1: len = endcase $display(len end
// // // // //
Construct environment Create random configuration Build the testbench environment Run the test Clean up after test & report
Day 2 - Summary
: syntax, terminology, creation, deallocation Class Routines : Scoping rules, one inside another, understanding of dynamic objects, copying objects interface : syntax, modport program block : Timing, interaction with module rand, randc for randomization Constraints, weighted distribution, conditional constraints, randomize with, solve before,
class constraint_mode, rand_mode pre_randomize, post_randomize, randsequence, randcase
ThankYou
Day 3 - Agenda
Verilog has initial, always, beginend, forkjoin and forever constructs for thread creation. SystemVerilog adds two new ways to create threads with the fork join_none and fork join_any statements. In testbench to communicate, synchronize and control the threads, verilog has constructs like event, @ event control, the wait and disable statements. SystemVerilog adds mailbox and semaphore for the above need.
fork
fork
fork
join
join_any
join_none
Events
SystemVerilog enhances the verilog event in several ways. An event is now a handle to a synchronization object that can be passed around to routines. In verilog, if the triggering thread executes before the blocking thread, the trigger is missed. SystemVerilog introduces triggered function that lets you check whether an event has been triggered.
1: after trigger,$time);
2: before trigger,$time);
2: after trigger,$time);
Passing events
class Generator; event done; function new (event done); // Pass event from TB this.done = done; endfunction task run; fork begin -> done; // Tell that test is done end join_none endtask endclass : Generator
Semaphores
A Semaphore allows you to control access to a resource Ex : A library book, A common car for family members Semaphore can be used in a testbench when you have a resource, such as bus, that may have multiple requestors from inside the testbench but as part of physical design, can only have one driver. In SystemVerilog, a thread that requests a key when one is not available always blocks. Multiple blocking threads are queued in FIFO order.
Semaphore operations
Create a semaphore with one or more keys using new method Get one or more keys with get method Return one or more keys with put method If you want to try to get a semaphore, but not block, use try_get function. It returns 1 if there are enough keys, and 0 if there are insufficient keys.
Semaphore operations
program automatic test; semaphore sem; // create semaphore initial begin sem = new(1); // Allocate with 1 key fork sequencer; // Spawn two threads that both sequencer; // do bus transactions join end task automatic sequencer; repeat($urandom%10) @bus.cb; // Random wait, 0-9 cycles sendTrans; // Execute the transaction endtask
Semaphore operations
task automatic sendTrans; sem.get(1); @bus.cb; bus.cb.addr <= t.addr; sem.put(1); endtask endprogram // Get the key to the bus // Drive signals onto bus // Release the key back
Mailboxes
How do you pass information between two threads? Generator needs to create many transactions and pass them to a driver. A mailbox is just like a FIFO with a source and sink. Mailboxes can have a maximum size or can be unlimited. When source puts a value into a sized mailbox that is full, it blocks until data is removed. If sink tries to remove data from a mailbox that is empty, it blocks until data is available.
Mailboxes (cntd.)
A mailbox is an object and thus has to be instantiated by calling the new function. Put data into a mailbox using put method. put blocks if mailbox is full. Remove data from a mailbox using get. get blocks if mailbox is empty. peek task gets a copy of the data in the mailbox but does not remove it. If you dont want your code to block, use the try_get and try_peek functions.
Mailbox in a testbench
program mailbox_example; class Generator; Transaction tr; mailbox mbx; function new(mailbox mbx); this.mbx = mbx; endfunction task run; repeat(10) begin tr = new; assert(tr.randomize()); mbx.put(tr); // Send out transaction end endtask : run endclass : Generator
Advanced OOP
Inheritance
Inheritance allows a new class to be derived from an existing one in order to share its variables and routines. The original class is known as the base or super class. The new one, since it extends the capability of the base class, is called the extended class. Inheritance provides reusability by adding features, such as error injection, to an existing class, the base transaction, without modifying the base class.
Factory Patterns
Blueprint (from test)
Generator
copy
Generated stream
Factory Patterns
Blueprint (from test)
Generator
copy
Generated stream
Callbacks
To create a verification environment that you can use for all tests with no changes. The key requirement is that the testbench must provide a hook where the test program can inject new code without modifying the original classes. Driver may want to do: inject errors, drop the transaction, delay the transaction, synchronize this transaction with others, put the transaction in scoreboard, gather functional coverage data. Driver just needs to call back a routine defined in the top-level test. The beauty of this technique is that the callback routine can be defined differently in every test. The test can add new functionality to the driver using callbacks without editing Driver class.
Callback flow
task Driver::run; forever begin . <pre_callback> transmit(tr); <post_callback> . end endtask task pre_callback; . endtask
Advanced Interfaces
Virtual Interfaces
In a network switch, a single Driver class may connect to many interfaces, one for each input channel of the DUT. Write a generic Driver, instantiate it N times and have it connect each of the N physical interfaces. You can do the above in SystemVerilog by using a virtual interface that is merely a handle to a physical interface.
A mesh design example A simple replicated component, an 8-bit counter. This resembles a DUT that has a device such as network chip or processor that is instantiated repeatedly in a mesh configuration. The key idea is that the top-level bench creates an array of interfaces and counters. Now the testbench can connect its array of virtual interfaces to the physical ones.
Day 3 - Summary
fork join, fork_join_none, fork join_any Events, semaphores and mailboxes Inheritance, factory pattern generation and callbacks Interfaces to virtual interfaces
ThankYou
Day 4 - Agenda
Assertions
Assertions
An assertion specifies a behavior of the system. Assertions are primarily used to validate the behavior of a design. In addition, assertions can be used to provide functional coverage. Two types of Assertions: Immediate assertions and concurrent assertions. Immediate assertions : Follow simulation event semantics and executed like a statement in a procedural block. Concurrent assertions : Follow clock semantics and use sampled values of variables. (Also called as temporal assertions)
Immediate Assertions
Is a test of an expression performed when the statement is executed in a procedural block. (like an if statement) If expression evaluates to 0, X or Z then it is interpreted as false and assertion is said to fail. Else the expression is interpreted as true and assertion is said to pass.
assert_foo : assert(foo) $display(%m passed); else $display(%m failed);
Concurrent Assertions
Concurrent assertions describe behavior that spans over time. Concurrent assertion is only evaluated at clock tick. The values of the variable used in the expression are sampled values. It is important to ensure that the defined clock behavior is glitch-free. Otherwise wrong values can be sampled.
base_rule1 : assert property (cont_prop(rst,in1,in2)) pass_stat else fail_stat;
Sequences
Delay ##1 indicates that the beginning of the sequence that follows is one clock tick later than the current clock tick. The sequence: req ##1 gnt ##1 !req specifies that req be true on the current clock tick, gnt shall be true on the first subsequent tick, and req shall be false on the next clock tick after that. req ##2 gnt This specifies that req shall be true on the current clock tick, and gnt shall be true on the second subsequent clock tick.
Sequences (cntd.)
req ##[4:32] gnt In the above case, signal req must be true at the current clock tick, and signal gnt must be true at some clock tick between the 4th and the 32nd clock tick after the current clock tick. The time window can extend to a finite, but unbounded, range by using $ as in the example below. req ##[4:$] gnt
Declaration of Sequences
sequence s1; // Simple Sequence a ##1 b ##1 c; endsequence sequence s20_1(data,en); // Sequence with arguments (!frame && (data==data_bus)) ##1 (c_be[0:3] == en); endsequence sequence rule; // Nested sequence @(posedge sysclk) trans ##1 start_trans ##1 s1 ##1 end_trans; endsequence
Declaring Properties
A property defines a behavior of the design. A property can be used for verification as an assumption, a checker, or a coverage specification. In order to use the behavior for verification, an assert, assume or cover statement must be used. A property declaration by itself does not produce any result. A property can be declared in a module an interface a program a clocking block a package a compilation-unit scope
Implication Properties
property data_end; // Overlapped Implication @(posedge mclk) data_phase |-> ((irdy==0) && ($fell(trdy) || $fell(stop))) ; endproperty For Non-overlapped implication, use |=>. Means after one clock tick. property data_end; // Non-Overlapped Implication @(posedge mclk) data_phase |=> ((irdy==0) && ($fell(trdy) || $fell(stop))) ; endproperty
Assert statement
The assert statement is used to enforce a property as a checker. When the property for the assert statement is evaluated to be true, the pass statements of the action block are executed. Otherwise, the fail statements of the action_block are executed. For example, property abc(a,b,c); disable iff (a==2) not @clk (b ##1 c); endproperty env_prop: assert property (abc(rst,in1,in2)) pass_stat else fail_stat; When no action is needed, a null statement (i.e.;) is specified. If no statement is specified for else, then $error is used as the statement when the assertion fails.
Assertions Example 1
module test; bit clk, req, gnt; always #5 clk = ~clk; initial begin repeat (2) @ (posedge clk); req <= 1'b1 ; @ (posedge clk); gnt <= 1'b1 ; @ (posedge clk); 1'b0 ; repeat (2) @ (posedge clk); $finish; end sequence s1; req ##1 gnt ##1 !req; endsequence : s1 property rule_s1 ; @ (posedge clk) s1; endproperty assert property (rule_s1); endmodule
req <=
0 req
10
15
20
25
30
35
40
45
50
55
gnt $finish
"assertions_1.sv", 18: test.unnamed$$_1: started at 5s failed at 5s Offending 'req' "assertions_1.sv", 18: test.unnamed$$_1: started at 15s failed at 15s Offending 'req' "assertions_1.sv", 18: test.unnamed$$_1: started at 45s failed at 45s Offending 'req' $finish at simulation time 55
Assertions Example 2
module test; bit clk, req, gnt; always #5 clk = ~clk; initial begin repeat (2) @ (posedge clk); req <= 1'b1 ; @ (posedge clk); gnt <= 1'b1 ; @ (posedge clk); 1'b0 ; repeat (2) @ (posedge clk); $finish; Overlapping end sequence s1; req ##1 gnt ##1 !req; endsequence : s1 property rule_s1 ; @ (posedge clk) req |-> s1; endproperty assert property (rule_s1); endmodule
req <=
0 req
10
15
20
25
30
35
40
45
50
55
gnt $finish
Assertions Example 3
module test; bit clk, req, gnt; always #5 clk = ~clk; initial begin repeat (2) @ (posedge @ (posedge clk); gnt @ (posedge clk); req repeat (2) @ (posedge $finish; end
clk); req <= 1'b1 ; <= 1'b1 ; <= 1'b0 ; gnt <= 1b0; clk);
Non-overlapping
sequence s1; gnt ##1 !req; endsequence : s1 property rule_s1 ; @ (posedge clk) req |=> s1; endproperty assert property (rule_s1); endmodule
0 req
10
15
20
25
30
35
40
45
50
55
gnt $finish
Failed at
Repetition in Sequences
a ##1 b ##1 b ##1 b ##1 c
Using the consecutive repetition operator [*3], which indicates 3 iterations, this sequential behavior is specified more succinctly:
a ##1 b [*3] ##1 c
is equivalent to
(b ##2 c) or (b ##1 a ##2 c)
To specify a finite, but unbounded, number of iterations, the dollar sign ($) is used.
a ##1 b [*1:$] ##1 c
matches over an interval of three or more consecutive clock ticks if a is true on the first clock tick, c is true on the last clock tick, and b is true at every clock tick strictly in between the first and the last.
Goto Repetition
Goto repetition specifies finitely many iterative matches of the operand boolean expression, with a delay of one or more clock ticks from one match of the operand to the next successive match and no match of the operand strictly in between. The overall repetition sequence matches at the last iterative match of the operand. Example :
a ##1 b [->2:10] ##1 c
is equivalent to
a ##1 ((!b[*0:$] ##1 b) [*2:10]) ##1 c
Go to Repetition Example
a c
Non-consecutive repetition
Non-consecutive repetition specifies finitely many iterative matches of the operand boolean expression, with a delay of one or more clock ticks from one match of the operand to the next successive match and no match of the operand strictly in between. The overall repetition sequence matches at or after the last iterative match of the operand, but before any later match of the operand. Example: a ##1 b [=2:10] ##1 c is equivalent to a ##1 ((!b [*0:$] ##1 b) [*2:10]) ##1 !b[*0:$] ##1 c
a c
Example : $fell (ack, clk); $rose (req); The clocking event if not specified will be inferred from the code where it is used.
Past function
The past values can be accessed with the $past function. $past( expression1 [, number_of_ticks] [, expression2] [, clocking_event]) The following three optional arguments are provided: expression2 is used as a gating expression for the clocking event number_of_ticks specifies the number of clock ticks in the past clocking_event specifies the clocking event for sampling expression1 The clocking event if not specified will be inferred from the code where it is used.
and Operation
The two operands of and are sequences. The requirement for the match of the and operation is that both the operands must match. The operand sequences start at the same time. When one of the operand sequences matches, it waits for the other to match. The end time of the composite sequence is the end time of the operand sequence that completes last. Example : When te1 and te2 are sequences, then the composite sequence: te1 and te2
intersect, or Operations
Intersect : Same as and, but the lengths of two matches of the operand sequences must be the same. te1 intersect te2 The operator or is used when at least one of the two operand sequences is expected to match. The two operands of or are sequences. If the operands te1 and te2 are expressions, then te1 or te2 matches at any clock tick on which at least one of te1 and te2 evaluates to true.
first_match Operation
The first_match operator matches only the first of possibly multiple matches for an evaluation attempt of its operand sequence. This allows all subsequent matches to be discarded from consideration. sequence t1; te1 ## [2:5] te2; endsequence sequence ts1; first_match(te1 ## [2:5] te2); endsequence
property data_check_p; int x; a ##1 !a, x = data_in |=> !b[*0:$] ##1 b && (data_out == x); endproperty A disable iff clause can be attached to a property_expr to yield a property_spec disable iff (expression_or_dist) property_expr
Assume statement
The purpose of the assume statement is to allow properties to be considered as assumptions for formal analysis tools.
a1:assume property @(posedge clk) req dist {0:=40, 1:=60} ; property proto; @(posedge clk) req |-> req[*1:$] ##0 ack; endproperty
Cover statement
To monitor sequences and other behavioral aspects of the design for coverage, the same syntax is used with the cover statement.
cover property ( sequence_expr ) statement_or_null
Functional Coverage
Introduction
Code coverage : how many lines of code have been executed. Functional coverage is a measure of which design features have been exercised by the tests. Code coverage : measures the coverage with respect to what has been implemented Function coverage: measures the coverage with respect to what has to be implemented to meet the functionality.
Covergroup in a class
class Transactor; Transaction tr; mailbox mbx_in; covergroup CovPort; coverpoint tr.port; endgroup function new(mailbox mbx_in); CovPort = new; // Instantiate covergroup this.mbx_in = mbx_in; endfunction
Covergroups can be triggered by calling sample method from Callback functions. Covergroups can also be triggered on a SystemVerilog assertion.
// // // //
A 1 8 1
bin for kind==0 bin for values 1:3 separate bins bin for all the rest
Conditional coverage
// Disable during reset covergroup CovPort; // Dont gather coverage when reset == 1 coverpoint port iff (bus_if.reset); endgroup // Using start and stop functions initial begin CovPort ck = new; // Instantiate covergroup // Reset sequence stops collection of coverage data #1ns bus_if.reset = 1; ck.stop(); #100ns bus_if.reset = 0; ck.start(); end
Transition coverage
For example you can check if port ever went from 0 to 1,2 or 3.
covergroup CovPort; coverpoint port { bins t1 = (0 => 1), (0 => 2), (0 => 3); } endgroup
Ignoring bins
Use ignore_bins to tell which values to exclude from functional coverage calculation. bit [2:0] low_ports_0_5; // Only uses values 0-5 covergroup CovPort; coverpoint low_ports_0_5 { ignore_bins hi = {[6,7]}; //Ignore upper 2bins } endgroup
Cross Coverage
Example : hburst and hsize combinations Cross coverage measures what values were seen for two or more coverpoints at the same time.
covergroup CovPortKind; kind: coverpoint tr.kind; kind port: coverpoint tr.port; cross kind, port; endgroup // Create coverpoint // Create coverpoint port // Cross kind and port
Day 4 - Summary
Immediate assertions, concurrent assertions Sequences, declaration of sequences Repetition specification (consecutive, goto and non-consecutive) Sampled value functions ($sampled, $rose, $fell, $stable, $past) and, intersect, or, first_match, throughout, within and ended operations Assigning variables in sequence specification and checking Property declaration : syntax, Implication properties assert, assume and cover statements Functional coverage example coverpoint, covergroup, triggering the covergroup Controlling the number of bins, naming the bins Conditional coverage, transition coverage Ignore_bins and cross coverage
ThankYou