Showing posts with label systemverilog. Show all posts
Showing posts with label systemverilog. Show all posts

Monday, November 15, 2010

short summary of package

Packages are explicitly named scopes appearing at the outermost level of the source text (at the same level as top-level modules and primitives). Types, variables, tasks, functions, sequences, and properties may be declared within a package.
Packages must not contain any processes. Therefore, wire declarations with implicit continuous assignments are not allowed.

Items within packages are generally type definitions, tasks, and functions. Items within packages cannot have hierarchical references. It is also possible to populate packages with parameters, variables, and nets.

One way to use declarations made in a package is to reference them using the class scope resolution operator ::.
ComplexPkg::Complex cout = ComplexPkg::mul(a, b);

Explicit import allows control over precisely which symbols are imported:
import ComplexPkg::Complex;


An alternate method for utilizing package declarations is via the import statement.

Thursday, June 10, 2010

virtual things

Virtual class
If a base class is not intended to be instantiated, it can be made abstract by specifying the class to be virtual.
An abstract class cannot be instantiated; it can only be derived.
Abstract classes can also have virtual methods.

Virtual method(function)
 Virtual methods are a basic polymorphic construct. A virtual method overrides a method in all the base classes, whereas a normal method only overrides a method in that class and its descendants.(only a virtual method can be overrided.) One way to view this is that there is only one implementation of a virtual method per class hierarchy, and it is always the one in the latest derived class. When subclasses override virtual methods, they must follow the prototype exactly.

example:
virtual class BasePacket;
virtual function integer send(bit[31:0] data);
endfunction
endclass
class EtherPacket extends BasePacket;
function integer send(bit[31:0] data);
// body of the function
...
endfunction
endclass


Virtual interface
Virtual interfaces provide a mechanism for separating abstract models and test programs from the actual signals that make up the design. A virtual interface allows the same subprogram to operate on different portions of a design and to dynamically control the set of signals associated with the subprogram. Instead of referring to the actual set of signals directly, users are able to manipulate a set of virtual signals. Changes to the underlying design do not require the code using virtual interfaces to be rewritten. By abstracting the connectivity and functionality of a set of blocks, virtual interfaces promote code reuse.
A virtual interface is a variable that represents an interface instance.

Virtual interface variables can be passed as arguments to tasks, functions, or methods. A single virtual interface variable can thus represent different interface instances at different times throughout the simulation. A virtual  interface  must  be  initialized  before  it  can  be  used;  it  has  the  value  null  before  it  is  initialized.

A virtual  interface  must  be  initialized  before  it  can  be  used;  it  has  the  value  null  before  it  is  initialized.

Once  a  virtual  interface  has  been  initialized,  all  the components  of  the  underlying  interface  instance  are directly  available  to  the  virtual  interface  via  the  dot  notation. 
Virtual interfaces can be declared as class properties, which can be initialized procedurally or by an argument to new().

example:
interface SBus; // A Simple bus interface
logic req, grant;
logic [7:0] addr, data;
endinterface

class SBusTransctor; // SBus transactor class
  virtual SBus bus; // virtual interface of type Sbus
  function new( virtual SBus s );
    bus = s;  // initialize the virtual interface
  endfunction
endclass

module devA( Sbus s ) ... endmodule   // devices that use SBus

module top;
  SBus s[1:4] (); // instantiate 4 interfaces
  devA a1( s[1] ); // instantiate 4 devices
  ...
  initial begin
    SbusTransactor t[1:4];          // create 4 bus-transactors and bind
    t[1] = new( s[1] );
    ...
  end
endmodule

In the preceding example, the transaction class SbusTransctor is a simple reusable component. It is written without any global or hierarchical references and is unaware of the particular device with which it will interact. Nevertheless, the class can interact with any number of devices (four in the example) that adhere to the interface’s protocol.

(设想一下,在SBusTransctor中如果没有virtual修饰 SBus s, s就成为一个实在的interface, 所有对s的操作都在局限在SBusTransctor中,"到此为止"。有了virtual修饰,在SBusTransctor梨花的时候,通过把virtual interface和外部实际interface连接,相应的操作就能传递到理想的real DUT上。 所以virtual interface 常用于 ovm driver 设计中。

semaphore, mailbox and event


semaphore

a semaphore is a bucket to store 1 or more keys. Any process using semaphore must procure a key before it can continue to execute.
To declare a semaphore:
semaphore smTx
Semaphore is a built-in class that provides the following methods:
Create a semaphore with a specified number of keys:
function new(int keyCount = 0 );
Obtain one or more keys from the bucket. If the specified number of keys is not available, the process blocks until the keys become available.
task get(int keyCount = 1);
Return one or more keys into the bucket. If the specified number of keys is available, the method returns a positive integer and execution continues.
task put(int keyCount = 1);
Try to obtain one or more keys without blocking. The semaphore try_get() method is used to procure a specified number of keys from a semaphore, but without blocking.
function int try_get(int keyCount = 1);

mailbox
A mailbox is a communication mechanism that allows messages to be exchanged between processes. Data can be sent to a mailbox by one process and retrieved by another.
Conceptually, mailboxes behave like real mailboxes.
  When a letter is delivered and put into the mailbox, one can retrieve the letter (and any data stored within). However, if the letter has not been delivered when one checks the mailbox, one must choose whether to wait for the letter or to retrieve the letter on a subsequent trip to the mailbox. Similarly, SystemVerilog's mailboxes provide processes to transfer and retrieve data in a controlled manner.
size: Mailboxes are created as having either a bounded or unbounded queue size.
      A bounded mailbox becomes full when it contains the bounded number of messages. A process that attempts to place a message into a full mailbox shall be suspended until enough room becomes available in the mailbox queue.
      Unbounded mailboxes never suspend a thread in a send operation.

An example of creating a mailbox is as follows:
mailbox mbxRcv;

Mailbox is a built-in class that provides the following methods:
Create a new mailbox
  function new(int bound = 0);
If the bound argument  is  0,  then  the  mailbox  is  unbounded

The number of messages in a mailbox can be obtained via the num() method.
  function int num();

The put() method places a message in a mailbox.
  task put( singular message);
The message  is any singular expression, including object handles.
If the mailbox was created with a bounded queue, the process shall be suspended until there is enough room in the queue.

The try_put() method attempts to place a message in a mailbox.
  function int try_put( singular message);
The try_put()  method stores a message in the mailbox in strict FIFO order. Meaningful only for bounded mailboxes. If the mailbox is full, the method returns 0.

The get() method retrieves a message from a mailbox.
task get( ref singular message );
  The get()  method retrieves one message from the mailbox, that is, removes one message from the mailbox queue. If the mailbox is empty, then the current process blocks until a message is placed in the mailbox.

try_get() method attempts to retrieves a message from a mailbox without blocking.
  function int try_get( ref singular message );

The peek() method copies a message from a mailbox without removing the message from the queue.
  task peek( ref singular message );
The peek()  method copies one message from the mailbox without removing the message from the mailbox queue.

The try_peek() method attempts to copy a message from a mailbox without blocking.
  function int try_peek( ref singular message );



Event
 Nonblocking event trigger are supported in systemverilog  using the ->> operator.
 The basic mechanism to wait for an event to be triggered is via the event control operator, @.
@ hierarchical_event_identifier;

SystemVerilog can distinguish the event trigger itself, which is instantaneous. The triggered property is invoked using a method-like syntax:
hierarchical_event_identifier.triggered.
The triggered event property is most useful when used in the context of a wait construct:
wait ( hierarchical_event_identifier.triggered )

Tuesday, December 30, 2008

systemverilog wordfile

copied from http://avm-users.googlegroups.com/web/systemverilog.txt?hl=en&gsc=Lb4u6AsAAADWzOiV2TvclJOPyNlia6Gs
/L20"Verilog 1364-2001" Line Comment = // Block Comment On = /* Block Comment Off = */ String Chars = " File Extensions = SV SVL/Delimiters = ~!@%^&*()-+=|\/{}[]:;"<> , .?#/Function String = "%[a-z0-9]+[ ^t]+[a-z_0-9]+[ ^t]+("
/Indent Strings = "begin" "fork" "specify" "config"
/Unindent Strings = "end" "join" "join_any" "join_none" "endspecify" "endconfig"
/C1"Keywords"
alias always always_comb always_ff always_latch and assert assign assume automatic 
before begin bind bins binsof bit break buf bufif0 bufif1 byte
case casex casez cell chandle class clocking cmos config const constraint context continue cover covergroup coverpoint cross
deassign default defparam design disable dist do
edge else end endcase endclass endclocking endconfig endfunction endgenerate endgroup endinterface endmodule endpackage endprimitive endprogram endproperty endspecify endsequence endtable endtask enum event expect export extends extern
final first_match for force foreach forever fork forkjoin function
generate genvar
highz0 highz1
if iff ifnone ignore_bins illegal_bins import incdir include initial inout input inside instance int integer interface intersect join
join_any join_none
large liblist library local localparam logic longint
macromodule matches medium modport module
nand negedge new nmos nor noshowcancelled not notif0 notif1 null
or output
package packed parameter pmos posedge primitive priority program property protected pull0 pull1 pulldown pullup pulsestyle_onevent pulsestyle_ondetect pure
rand randc randcase randsequence rcmos real realtime ref reg release repeat return rnmos rpmos rtran rtranif0 rtranif1
scalared sequence shortint shortreal showcancelled signed small solve specify specparam static string strong0 strong1 struct super supply0 supply1
table tagged task this throughout time timeprecision timeunit tran tranif0 tranif1 tri tri0 tri1 triand trior trireg type typedef
union unique unsigned use
var vectored virtual void
wait wait_order wand weak0 weak1 while wildcard wire with within wor
xnor xor
/C2"System"
** 'b 'B 'o 'O 'd 'D 'h 'H 'sb 'sB 'so 'sO 'sd 'sD 'sh 'sH 'Sb 'SB 'So 'SO 'Sd 'SD 'Sh 'SH
** _
$assertkill $assertoff $asserton $async$and$array $async$nand$array $async$or$array $async$nor$array $async$and$plane $async$nand$plane $async$or$plane $async$nor$plane
$bits $bitstoreal $bitstoshortreal 
$cast $comment $countdrivers $countones
$date $dimensions $display $displayb $displayh $displayo $dist_chi_square $dist_erlang $dist_exponential $dist_normal $dist_poisson $dist_t $dist_uniform $dumpall $dumpflush $dumpfile $dumplimit $dumpoff $dumpon $dumpports $dumpportsall $dumpportsflush $dumpportslimit $dumpportsoff $dumpportson $dumpvars
$enddefinitions $error $exit
$fatal $fdisplay $fdisplayf $fdisplayb $fdisplayh $fdisplayo $fell $feof $ferror $fflush $fgetc $fgets $finish $fopen $fmonitor $fmonitorb $fmonitorf $fmonitorh $fmonitoro $fclose $fread $fscanf $fseek $fsscanf $fstrobe $fstrobeb $fstrobef $fstrobeh $fstrobeo $ftell $fullskew $fwrite $fwriteb $fwritef $fwriteh $fwriteo 
$get_coverage $getpattern
$high $hold $history
$increment $incsave $info $input $isunbounded $isunknown $itor
$key 
$left $list $load_coverage_db $log $low 
$monitor $monitorb $monitorh $monitoro $monitoron $monitoroff 
$nochange $nokey $nolog $onehot $onehot0
$past $period $printtimescale
$q_add $q_exam $q_full $q_initialize $q_remove $q_random
$random $readmemb $readmemh $realtime $realtobits $recovery $recrem $removal $reset $reset_count $reset_value $restart $rewind $right $root $rose $rtoi
$sampled $save $scale $scope $sdf_annotate $set_coverage_db_name $setup $setuphold $sformat $shortrealtobits $showvariables $showscopes $showvars $signed $size $skew $sreadmemb $sreadmemh $sscanf $stable $stime $stop $strobe $strobeb $strobeh $strobeo $swrite $swriteb $swriteh $swriteo $sync$and$array $sync$nand$array $sync$or$array $sync$nor$array $sync$and$plane $sync$nand$plane $sync$or$plane $sync$nor$plane
$test$plusargs $time $timeformat $timescale $timeskew $typename $typeof
$ungetc $unit $unpacked_dimensions $unsigned $upscope $urandom $urandom_range
$value$plusargs $var $vcdclose $version
$warning $width $write $writeb $writeh $writeo $writememb $writememh

/C3"Operators"
->
+:
-:
@
@*
*>
,
;
.*
{
}
+
-
// /
*
**
%
>
>=
>>
>>>
<
<=
<<
<<<
!
!=
!==
&
&&
|
||
=
==
===
^
^~
~
~^
~&
~|
?
:
|->
|=>
/C4"Directives"
** `
`begin_keywords
`accelerate `autoexepand_vectornets
`celldefine
`default_nettype `define `default_decay_time `default_trieg_distributed `default_trireg_strength `delay_mode_distributed `delay_mode_path `delay_mode_unit `delay_mode_zero
`else `elsif `endcelldefine `endif `end_keywords `endprotect `endprotected `expand_vectornets
`file
`ifdef `ifndef `include
`line
`noaccelerate `noexpand_vectornets `noremove_gatenames `noremove_netnames `nounconnected_drive
`pragma `protect `protected
`remove_gatenames `remove_netnames `resetall
`timescale
`unconnected_drive `undef `uselib


/C5"DelaysAndParameters"
#
##

System Verilog by example by example

System Verilog by example(constraint, random, covergroup)
module top;
typedef enum bit { BAD_PARITY, GOOD_PARITY } parity_e;
class packet_c;
rand bit [5:0] pkt_length;
bit[63:0][7:0] pkt_payload;
bit[7:0] parity;
rand parity_e parity_type;
function bit [7:0] calc_parity();
 calc_parity = { pkt_length, pkt_addr };
 for (int i = 0; i calc_parity ^= pkt_payload[i];
endfunction :calc_parity

function void randomize_payload();
 pkt_addr = $urandom ;
 pkt_length = $urandom ;
 for (int i=0; i < pkt_length; i ++)
  pkt_payload[i]= $urandom;
endfunction:randomize_payload

function void post_randomize();
  randomize_payload();  
  if (parity_type == GOOD_PARITY)
  parity = calc_parity();
  else
  do
  parity = $urandom;
  while (parity == calc_parity());
endfunction:post_randomize

endmodule

class packet_c;
typedef enum bit { BAD_PARITY , GOOD_PARITY } parity_e;
typedef enum bit[1:0] { SMALL,MEDIUM, LARGE } payload_e;
  constraint c { parity_type == GOOD_PARITY ;}
  constraint c1 { payload_type == LARGE ;}
  constraint c3 { pkt_addr == 2; }
  constraint length_range {
  (payload_type == SMALL) -> pkt_length inside { [1 : 20] };
  (payload_type == MEDIUM) -> pkt_length inside { [21 : 44]};
  (payload_type == LARGE) -> pkt_length inside { [45 : 63]};
  }
// Define the Coverage module for the packet defined
  covergroup cg @ (pkt_event);
  coverpoint pkt_length {
  bins usb_range = {[0 : 20]};
  bins pci_range = {[21 : 44]};
  bins ahb_range = {[45 : 63 ]};
  }
  coverpoint pkt_addr;
  coverpoint parity;
  endgroup


Sunday, November 30, 2008

coverage

cited from http://www.ovmworld.org/forums/showthread.php?t=121
Code coverage: This will give information about how many lines are exected, how many times expressions, branches executed. This coverage is collected by the simulation tools. Users use this coverage to reach those corner cases which are not hit by the random testcases. Users have to write the directed testcases to reach the missing code covearage areas.

Functional coverage: This coverage will be defined by the user. User will define the coverage points for the functions to be covered in DUT. This is completly under user control. like covergroup definition defined in SV

Both of them have equal importance in the verification. 100% functional coverage does not mean that the DUT is completly exercised and vice-versa. Verification engineers will consider both coverages to measure the verifcation progress.

Coverage tool
All the HVL simulators have Functional Coverage tool with it.You have to write coverage code and then switch ON the coverage during simulation.
And use a coverage viewing tool (again, the same EDA company will have it) to view the coverage.
For Cadence IES/IUS:
1. For switching coverage ON:Use +nccovfile+dut_cov.txt while compiling.
The content of dut_cov.txt is:
select_coverage -all -module top
...
select_functional
select_fsm
During simulation use:-covoverwrite -covtest mycov.cov
2. To view coverage:
Do:
iccr -keywords+detail iccr.cmd
or:
iccr -keywords+summary iccr.cmd
or:
iccr -keywords+dontmerge iccr.cmd
The respective content of iccr.cmd is:
load_test cov_work/design/*merge * -output ALL
reset_coverage
load_test cov_work/design/ALL
report_detail -instance -betsafd -cgopt top... > detail.rpt

load_test cov_work/design/*merge * -output ALL
reset_coverage
load_test cov_work/design/ALL
report_summary -instance -cgopt top... > summary.rpt

load_test cov_work/design/*
report_summary -instance -cgopt top... > summary.rpt

There is a coverage quick start guide included with IUS as well in order to get you started. Search for "icc quick start guide" in cdnshelp

Tuesday, November 18, 2008

systemverilog keywords supported by synplify

Supported SystemVerilog Keywords:

always_comb, always_ff, always_latch, assert, bit byte, const, do, endinterface, enum, import, int, interface, logic, longint, modport, packed, priority, shortint, struct, typedef, unique.



Unsupported SystemVerilog Keywords:

assume, break, continue, endproperty, endsequence, expect, property, return, sequence, timeprecision, timeunit, union, void.

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