Tutorials
ENVIRONMENT
Enviroment class contains instancess of all the verification components. Environment class is extension on rvm_env class.
The testbench simulation needs some systamatic flow like reset,initilize etc. rvm_env base class has methods to support this simulation flow.
The rvm_env class divides a simulation into the following steps, with corresponding methods:
-- gen_cfg() : Randomize test configuration descriptor
-- build() : Allocate and connect test environment components
-- reset_dut_t() : Reset the DUT
-- cfg_dut_t() : Download test configuration into the DUT
-- start_t() : Start components
-- wait_for_end_t() : End of test detection
-- stop_t() : Stop data generators and wait for DUT to drain
-- cleanup_t() : Check recorded statistics and sweep for lost data
-- report() : Print final report
CODE:env.vr
//A top-level source file shall include all ancillary source files
#include <rvm_std_lib.vrh>
#include "Configuration.vr"
#include "packet.vr"
#include "ports.vr"
`ifndef ENV_CLASS
`define ENV_CLASS
//A channel class shall be declared for any class derived from the bu_data class
rvm_channel( packet)
//An instance of a rvm_channel object shall be used to pass transactions between two transactors
rvm_atomic_gen( packet,"packet" )
#include "drvr.vr"
#include "rcvr.vr"
#include "score_board.vr"
class Environment extends rvm_env {
//All simulation log output shall be done through the message service.
rvm_log log;
Configuration cfg;
packet pkt;
packet_atomic_gen gen;
packet_channel gen2drv_chan;
packet_channel rcv2sb_chan;
packet_channel drv2sb_chan;
drvr_xtor drvr;
rcvr_xtor rcvr_0;
rcvr_xtor rcvr_1;
rcvr_xtor rcvr_2;
rcvr_xtor rcvr_3;
scoreboard sb;
task new ();
virtual task gen_cfg();
virtual task build();
virtual task reset_dut_t();
virtual task cfg_dut_t();
virtual task start_t();
virtual task wait_for_end_t();
virtual task stop_t();
virtual task cleanup_t();
virtual task report();
}
task Environment:: new (){
super .new ( "Environment" );
this .log = new ( "ENV_LOG" ,"0" );
this .cfg = new ();
rvm_note( this .log," ENV CREATED \n" );
}
//The return value of the randomize() method shall be checked
//and an error be reported if it is FALSE
task Environment:: gen_cfg(){
super .gen_cfg();
rvm_note( this .log," Starting... Gen_cfg \n" );
if ( !cfg.randomize ())
rvm_fatal( this .log, "Configuration Randomization Failed!\n" );
cfg.display();
}
task Environment:: build() {
super .build();
rvm_note( this .log," Starting... build \n" );
pkt = new ();
pkt.do_cfg( cfg);
gen = new ( "Generator" ,"0" );
gen.stop_after_n_insts = 20 ;
gen2drv_chan = new ( "gen2drv" ,"0" );
rcv2sb_chan = new ( "rcv2sb" ,"chan" ,10 );
drv2sb_chan = new ( "drv2sb" ,"chan" ,10 );
gen.out_chan = this .gen2drv_chan;
drvr = new ( "driver" ,0 ,gen2drv_chan,drv2sb_chan);
rcvr_0 = new ( "reciver_0" ,0 ,rec_0,rcv2sb_chan);
rcvr_1 = new ( "reciver_1" ,1 ,rec_1,rcv2sb_chan);
rcvr_2 = new ( "reciver_2" ,2 ,rec_2,rcv2sb_chan);
rcvr_3 = new ( "reciver_3" ,3 ,rec_3,rcv2sb_chan);
sb = new ( rcv2sb_chan,drv2sb_chan);
}
//Blocking methods shall have a name that ends with the "_t" suffix.
task Environment:: reset_dut_t(){
super .reset_dut_t();
rvm_note( this .log," Starting... reset_dut \n" );
@( posedge intf.clk);
intf.data_status <= 0 ;
intf.data_in <= 0 ;
intf.read_0 <= 0 ;
intf.read_1 <= 0 ;
intf.read_2 <= 0 ;
intf.read_3 <= 0 ;
intf.mem_data <= 0 ;
intf.mem_add <= 0 ;
intf.reset <= 0 ;
intf.mem_en <= 0 ;
intf.mem_rd_wr <= 0 ;
@( posedge intf.clk);
intf.reset <= 1 ;
@( posedge intf.clk);
intf.reset <= 0 ;
@( posedge intf.clk);
@( posedge intf.clk);
rvm_note( this .log," Ending... reset_dut \n" );
}
//The generated value of the configuration descriptor shall be
//downloaded into the DUT in the rvm_env::cfg_dut_t() method
task Environment:: cfg_dut_t(){
integer i;
super .cfg_dut_t();
rvm_note( this .log," Starting... cfg_dut \n" );
for ( i = 0 ; i<4 ; i++)
{
intf.mem_en <= 1 ;
@( posedge intf.clk);
intf.mem_rd_wr <= 1 ;
@( posedge intf.clk);
intf.mem_add <= i;
intf.mem_data <= cfg.da_port[i];
}
@( posedge intf.clk);
intf.mem_en <= 0 ;
intf.mem_rd_wr <= 0 ;
intf.mem_add <= 0 ;
intf.mem_data <= 0 ;
rvm_note( this .log," Ending... cfg_dut \n" );
}
//The rvm_env::start_t() method shall start all transactors and generators
//The rvm_env::start_t() method should not block the execution thread
task Environment:: start_t() {
super .start_t();
rvm_note( this .log," Starting... start \n" );
gen.start_xactor();
drvr.start_xactor();
rcvr_0.start_xactor();
rcvr_1.start_xactor();
rcvr_2.start_xactor();
rcvr_3.start_xactor();
sb.start_xactor();
}
task Environment:: wait_for_end_t() {
super .wait_for_end_t();
rvm_note( this .log," Starting... wait_for_end \n" );
fork //watchdog
{
void = gen.notify.wait_for_t( gen.DONE );
rvm_note( this .log," DONE:: packet_atomic_gen \n" );
repeat ( 100 ) @( posedge intf.clk);
rvm_error( this .log," Watchdog timeout occured \n" );
}
{
while ( sb.no_rcv_pkt != 20 ) @( posedge intf.clk);
rvm_note( this .log," DONE:: total number of sent pkts are receved \n" );
}
join any
rvm_note( this .log," Ending ... wait_for_end \n" );
}
task Environment:: stop_t() {
super .stop_t();
rvm_note( this .log," Starting... stop \n" );
this .drvr.stop_xactor();
this .rcvr_0.stop_xactor();
this .rcvr_1.stop_xactor();
this .rcvr_2.stop_xactor();
this .rcvr_3.stop_xactor();
this .sb.stop_xactor();
rvm_note( this .log," Ending ... stop \n" );
}
task Environment:: cleanup_t() {
super .cleanup_t();
rvm_note( this .log," Starting... cleanup \n" );
}
task Environment:: report() {
rvm_note( this .log," Starting... report \n" );
super .report();
rvm_note( this .log," Ending... report \n" );
}
`endif