Wednesday, November 12, 2008

systemverilog/ovm training


OVM overview
Data items represent the input to the DUT. Examples include networking packets, bus transactions, andinstructions
Driver(BFM): A driver is an active entity that emulates logic that drives the DUT. A typical driver repeatedly receivesa data item and drives it to the DUT by sampling and driving the DUT signals.
A sequencer is an advanced stimulus generator that controls the items that are provided to the driverfor execution.
A monitor is a passive entity that samples DUT signals but does not drive them. Monitors collectcoverage information and perform checking.
Agent: Sequencers, drivers, and monitors can be reused independently. OVM recommends that environment developers create a more abstract container, agent to emulate and verify DUTdevices. They encapsulate a driver, sequencer, and monitor. Active agents emulate devices and drive transactions according totest directives. Passive agents only monitor DUT activity.
Environment: The environment (env) is the top-level component of the OVC. It contains one or more agents, as wellas other components such as a bus monitor.

to start a general verification process
create a base class for pattern generation
define the control signals
define utility functions
define default constraint for each control signal, e.g. checker, printer..
create a class that inherits the base class
define specific contraints for control signals (if necessary, disable base class's constraints)

ovm provides additional features:
printing
packing
transaction layer recording
...
0. basic functions and usage
** my_class_inst.print(); // print name, type, size, value of vars
** class_inst1.set_name("inst_tst"); // rename the class
** $cast(class_inst2, class_inst1.clone()); // clone
** void '(begin_tr(class_inst); //start of transaction recording
//body
end_tr(class_inst)); //end of recording

1. class definition keyword and usage
** `ovm_object_utils_begin(my_classname)
`ovm_field_int( my_int_var, OVM_ALL_ON)
`ovm_field_enum( my_enum_typename, my_enum_var, OVM_ALL_ON + OVM_NOCOMPARE)
...
`ovm_object_utils_end
== description
** `ovm_object_utils macro implements a set of utility functions for OVM objects: get_type_name() and create() methods implemented, print(), clone(), etc are configured.
** `ovm_field_* macros specify the automation requirements for each field of the data item
** OVM_ALL_ON Turns on the COPY, COMPARE, PRINT, RECORD, PACK , UNPACK and DEEP flags

OVM Message Control
`message( , ( ) )
is a formatted string with arguments similar to $display = OVM_NONE, OVM_LOW, OVM_MEDIUM, OVM_HIGH, OVM_FULL
OVM_LOW shows test scope
Three ways to change verbosity:
1.+MSG_DETAIL argument to irun% irun …. +MSG_DETAIL=NONE
The default verbosity is OVM_LOW
2.In the test:set_report_verbosity_level(int VERBOSITY);
3.TCL APIovm_message command
OVM Data Item
class uart_frame extends ovm_sequence_item;
OVM Sequences
Derived from ovm_sequence base class
Use the `ovm_sequence_utils macro to associate the sequence with the relevant sequencertype and to declare the various automation utilities.
e.g.: class rand_retry_seq extends ovm_sequence;
`over_do
An object is created using the factory settings and assigned to the specifiedvariable. Based on the processing, when the driver requests an item from thesequencer, the item is randomized and provided to the driver.
`over_do_with
Similiar to `over_do. This enables adding different inline constraints, while still using the same item or sequence variable.
The body() task is the actual logic of the sequence.
[0] ovm_random_sequence executes a random number of sequences(does not call itself)
[1] ovm_exhaustive_sequence randomly executes each defined sequence without repetition until all are executed(does not call random or itself)

[2] ovm_simple_sequence executes a single data transaction Default_sequence = ovm_random_sequence
sequence flow
`ovm_do(subsequence);
Call pre_do() task with is_item = 0
Call mid_do()
trigger subsequence.started
Call subsequence.body()
trigger subsequence.ended
Call post_do()
End of do subsequence

The Driver (BFM)
class uart_tx_driver extends ovm_driver;
`ovm_sequence_item item;
uart_frame this_tx_frame;
`ovm_component_utils(uart_tx_driver)

agent
Agents provide all the verification logic for a device in the system. Instantiation and connection logic is done by the developer in a standard manner
–Integrator does not need to worry about this.
Agents share a common configuration or common signals

A Standard agent has:
–Sequencer for generating traffic
–Driver to drive the DUT
–Monitor
e.g.
class master_agent extends ovm_agent;
master_driver driver;
master_sequencer sequencer;
master_monitor monitor;


virtual function void build();


virtual function void connect();


endclass



OVM Simulation Phases


OVM Built-in Phases – run in order


build Build Top-Level Testbench Topology

connect Connect environment topology
start_of_simulation Configure verification components
end_of_elaboration Post-elaboration activity (e.g. print topology)
run task - Run-time execution of the test
extract Gathers details on the final DUT state
check Processes and checks the simulation results.
report Simulation results analysis and reporting

to add a user defined phase, derive a subclass of ovm_phase that implements either the call_task() or call_funcmethod, depending on whether the new phase is to be time-consuming (a task) or not (a function). Register the phase with the OVM phase controller, ovm_top.

Creating and Adding a New Sequence
To create a user-defined sequence:
1. Derive a sequence from the ovm_sequence base class.
2. Use the `ovm_sequence_utils macro to associate the sequence with the relevant sequencer type and to declare the various automation utilities.
This macro is similar to the`ovm_object_utils macro (and its variations) except that it takes another argument, whichis the sequencer type name this sequence is associated with. This macro also provides ap_sequencer variable that is of the type specified by the second argument of the macro. This allows access to derived type-specific sequencer properties.
3. Implement the sequence's body task with the specific scenario you want the sequence to execute.
In the body, you can execute data items and other sequences using “`ovm_do” and“`ovm_do_with”.

Executing Multiple Sequences Concurrently
There are two ways you can create concurrently-executing sequences:
• Using the ovm_do Macros with fork/join.
• Starting Several Sequences in Parallel using the start() method.
Using the ovm_do Macros with fork/join
e.g.:
a_seq a;
b_seq b;
virtual task body();
fork
`ovm_do(a)
`ovm_do(b)
join
endtask : body
Starting Several Sequences in Parallel
a_seq a;
b_seq b;
virtual task body();// Initialize the sequence variables with the factory.
`ovm_create(a)
`ovm_create(b)// Start each subsequence as a new thread.
fork
a.start(p_sequencer);
b.start(p_sequencer);
join
endtask : body

Randomizing the Kind of Generated Sequences
The use of `ovm_sequence_utils registers a sequence type with a particular sequencer’s sequence library. The seq_kind property is used to identify a specific type in the sequence library based on the sequence type. For example, get_seq_kind(“simple_seq_do”) returns an integer that can be used to identify the sequence type simple_seq_do.

A test name is provided to run_test() via a simulator command-line argument. If the top modulecalls run_test() without an argument, the +OVM_TESTNAME=test_name simulator command-line argument is always checked. otherwise a default test_name must be provided.


Virtual sequencer
with virtual sequencer, we can
1. provide sequence to multiple channels that need sequences
2. timing the sequences between channels
how to do:
1. define virtual sequencer class
1.1. define virtual sequencer class that derives from ovm_virtual_sequencer class
   note: use `ovm_update_sequencer_lib to register in new() function
1.2. define 1 or more sequence consumer interfaces (to connect to interface sequencers)
use add_seq_cons_if("my_name")  in build() function to generate interface
these consumer interfaces has built-in function named seq_cons_if(), which can be connected to seq_prod_if of normal sequencer
1.3 instantiate normal sequencer to be attached to
2. define virtual sequences class
each virtual sequence has all possible instance of interface sequences
the instances of interface sequence are activated in virtual task body()  using `ovm_do_seq(seq_name, p_sequencer.seq_cons_if["myname"])
in this way, virtual sequencer take the virtual sequence interface as output explicitly
3. define tb class (extends ovm_threaded_component or ovm_env?) to
connect  virtual sequencer to interface sequencer in the testbench(sve, tb, etc)
3.0 the tb class may extend directly from previous class with all env but without virtual sequencer to simply the process 
3.1. instantiate the virtual sequencer
e.g.: simple_vsequencer vsequencer0;
and build it in the function build()
3.2. connect virtual sequencer's sequence consumer interfaces to the interface sequencers in virtual function connect()
e.g.: agent0.sequencer.seq_prod_if.connect_if(vsequencer0.seq_cons_if["bar"]);
4. define a class extends ovm_test
instantiate the tb class
invoke a virtual sequence
use task set_config_string(), set_config_int() in function build() to configure the virtual sequencer
use following command in task run() to print info
  ovm_factory::print_all_overrides();
  ovm_print_topology();

TLM
TLM – Transaction Level Modeling
TLM is used for Architecture design and (performance) analysis
Interfaces = API’s
interface types
Put interfaces
tlm_blocking_put_if #(type T=int)
tlm_nonblocking_put_if
tlm_put_if
Get interfaces
tlm_blocking_get_if
tlm_nonblocking_get_if
tlm_get_if
Peek interfaces
tlm_blocking_peek_if
tlm_nonblocking_peek_if
tlm_peek_if
Transport interfaces
tlm_blocking_transport_if #(type REQ=int, type RSP=int)
Analysis interface
analysis_if #(type T=int)         non_blocking, broadcast
port vs export
initiator vs target
e.g.
initiator side:
class yapp_m_monitor extends ovm_monitor;
ovm_analysis_port #(yapp_packet) ingress_out= new(“ingress_out", this);
ingress_out.write(collected_packet);

target side:
class sys_monitor extends ovm_threaded_component;
`ovm_analysis_imp_decl(_ingress)
ovm_analysis_imp_ingress#(yapp_packet, sys_mon) ingress_in = new(“sys_mon”, this);
function write_ingress(input yapp_packet packet);

endfunction

testbench side:
class yapp_router_testbench extends ovm_threaded_component;
virtual function void connect();
  input_uvc.master.monitor.ingress_out.connect(router_mod_uvc.sys_mon.ingress_in);
endfunction

No comments: