Parameterized Classes, Interfaces & Registers

Mark Lierick

© Verilab & Accellera 1 Introducon to Parameters

• In SystemVerilog parameters enable flexibility – compile-me specializaon of code-base – e.g. RTL module with variable FIFO depth, bus width, etc. – e.g. verificaon component with variable channels, etc. • Parameterizaon enables horizontal reuse – e.g. same DUT RTL code in different project derivave – e.g. same verificaon code adapng to different projects • Parameterized code trades flexibility with complexity – in RTL parameters are usually easy to deal with and simple – in verificaon code the benefits are less clear... PARAMETERIZED PARAMETERIZED PARAMETERIZED CLASSES INTERFACES REGISTERS

© Verilab & Accellera 2 PARAMETERIZED CLASSES

© Verilab & Accellera 3 Parameterized Classes • Parameterized classes are a good fit for many cases: – extensive horizontal reuse for a set of derivaves – UVM base classes (e.g. TLM, sequencer, driver, monitor,...) • But parameterizaon is intrusive... – creates verbose code base (harder to read and maintain) – parameter proliferaon is ubiquitous (all over the code) – all files need parameters just to idenfy specialized types • When is it worth the effort? – parameterizaon is a lot of effort for the developers – ... but can be very good for the user of the code!

© Verilab & Accellera 4 Non-Parameterized Setup DERIVATIVE-SPECIFIC ENV DERIVATIVE-SPECIFIC DERIVATIVE-SPECIFIC MY_ENV REGISTER SEQUENCES seq lib REGISTER MODEL C (CLONE & MODIFY) VS MY REG REG MODEL SHARED ENVIRONMENT SHARED SEQUENCES NOP_ENV HAVE NO ACCESS TO seq lib REGISTER FIELDS UVC_BUS C VS BASE P S C (SINCE FIELDS ONLY ACTIVE CHANNELS MODEL A IN DERIVED CLASS) D M SCOREBOARD HELD IN CONFIG

UVC_PRX UVC_STXRX TX RX RX D S C C S D 1 - 4 M M MY VS TX RX TX UVC_PTX S D DUT 1 - 4 D S C M M

SERIAL PARALLEL CONFIG-AWARE MAX-FOOTPRINT AGENTS & SEQUENCES INTERFACES

© Verilab & Accellera 5 Parameterized Environment

REGISTER MODEL OF PARAMETER TYPE SHARED ENVIRONMENT SHARED SEQUENCES P_ENV#(REG,T,R) HAVE ACCESS TO seq lib REGISTER FIELDS UVC_BUS C VS REG P S C REG (PARAMETERIZED) PARAMETERS MODEL A D M SCOREBOARD (REGISTER TYPE, NUM CHANNELS) UVC_PRX#(T) UVC_STXRX#(T,R) TX RX RX D S C C S D 1 - 4 M M MY VS TX RX TX UVC_PTX#(R) S D DUT 1 - 4 D S C M M

PARAMETERIZED PARAMETERIZED AGENTS & SEQUENCES INTERFACES

© Verilab & Accellera 6 Reuse of Parameterized Env A FEW DERIVATIVE-SPECIFIC DERIVATIVE-SPECIFIC ENVS e.g. B12_ENV SETS: • REG TYPE = REG_B, REGISTER SEQUENCES (SPECIALIZE PARAMETERS) • NUM SERIAL TX = 1 • NUM SERIAL RX = 2

A21_ENV B12_ENV seq lib seq lib

P_ENV#(REG_A,2,1) P_ENV#(REG_B,1,2) seq lib seq lib UVC_BUS C UVC_BUS C VS P P REG_A S C VS REG_B S C REG REG MODEL MODEL A D M SCOREBOARD A D M SCOREBOARD

UVC_PRX#(2) UVC_PRX#(1) UVC_STXRX#(2,1) UVC_STXRX#(1,2) S C TX RX RX D TX RX RX D S C C S D C S D M M M M A21 B12 VS TX VS TX RX TX DUT UVC_PTX#(1) RX TX DUT UVC_PTX#(2) S D S D D S C D S C M M M M

MASSIVE REUSE & SHARED ENVIRONMENTS AUTOMATIC TUNING: (IDENTICAL CODE BASE) WHAT’S NOT TO LIKE?

© Verilab & Accellera 7 Generic p_env Environment PARAMETER DECLARATION class p_env #(type REG=uvm_reg_block, int T=1, int R=1) extends uvm_env; PARAMETER PROPAGATION

my_regREG reg_model; // register block base p_env_sequencer # (REG ) sequencer; // virtual sequencer stxrx_env #( T , R ) stxrx; // serial UVC ... `uvm_component_utils_beginuvm_component_param_utils_begin(p_env)( p_env#(REG,T,R)) ... MUST function USE *_PARAM_UTILS void build_phase (...); MUST USE PARAMETERIZED TYPES IN ... UTILS (OR YOU GET THE WRONG TYPE) reg_model = my_regREG::type_id::type_id::create::create(...);(...); sequencer = p_env_sequencer::#(type_idREG)::type_id::create::(...);create(...); stxrx = stxrx_env::#(type_idT,R)::type_id::create::(...);create(...); ... reg_model.build(); MUST USE PARAMETERIZED TYPES IN ... CREATE (OR YOU GET THE WRONG TYPE) uvm_config_object::set(this, "*", "reg_model", reg_model); ...

© Verilab & Accellera 8 uvc_stxrx – Env/Agent/Comps class stxrx_env extends#(int NT uvm_env=1, int; NR=1) extends uvm_env; stx_agent tx_agent#(NT) tx_agent; ; PROPAGATE PARAMETERS srx_agent rx_agent#(NR) rx_agent; ; THROUGHOUT HIERARCHY ... class stx_agent extends#(int N=1) uvm_agent extends; uvm_agent; stx_driver #driver(N) ; driver ; INTRODUCE NEW PARAMETERS s_monitor #monitor(TX,N) ;monitor ; AS REQUIRED (e.g. SHARED virtual s_interface vif#(N;) vif ; MONITOR FOR TX AND RX) ... class s_monitor extends#(s_dir_enum uvm_monitor D=RX, ;int N=1) extends uvm_monitor; ... s_transaction m_trans[4N]; USE PARAMETERS AT LOW LEVELS ... (e.g. ARRAY SIZE, MESSAGES, ETC.) if (D==TX) `uvm_warning (...,”error injected in Tx traffic to DUT”) else `uvm_error(...,”error inobserved DUT traffic”) in Rx traffic from DUT”) ...

© Verilab & Accellera 9 p_env – Virtual Sequencer

PARAMETERIZE SEQUENCER TO GIVE SEQUENCES ACCESS TO REG_MODEL OF CORRECT TYPE class p_env_sequencer # (type REG=uvm_reg_block) extends uvm_sequencer;

my_regREG reg_model reg_model; //; //handle handle to toregister register model model

`uvm_component_utils_beginuvm_component_param_utils_begin(p_env_sequencer(p_env_sequencer) #(REG)) `uvm_field_object(reg_model, UVM_ALL_ON | UVM_NOPRINT) ... function void build_phase(...); super.build_phase(...); DON’T FORGET ☺ if (reg_model == null) `uvm_fatal("NOREG", ”null handle for reg_model") ...

© Verilab & Accellera 10 p_env – Sequences P_SEQUENCER MUST BE CORRECT TYPE OR YOU GET RUN-TIME CAST FAIL ERROR “...SEQ CANNOT RUN ON SEQUENCER TYPE...” class p_env_base_seq # (type REG=uvm_reg_block) extends uvm_sequence;

`uvm_declare_p_sequencer(p_env_sequencer) #(REG)) `uvm_object_param_utils(p_env_base_seq) #(REG)) ... SEQUENCES MUST EXTEND CORRECT BASE TYPE => SEQUENCES MUST BE PARAMETERIZED class p_env_init_seq # (type REG=uvm_reg_block) extends p_env_base_seq; #(REG);

p_env_reset_seq # ( REG reset_seq) reset_seq; // drive; // resetdrive reset p_env_wait_cfg_seq # (cfg_seqREG) ;cfg_seq // ;wait // cfg wait ack cfg ack p_env_wait_ready_seq ready_seq#(REG) ready_seq; // wait; // ready wait ready

`uvm_object_param_utils_begin(p_env_init_seq) # (REG)) ... DON’T EVER FORGET ☺

© Verilab & Accellera 11 DUT-Specific Environment

SPECIALIZE P_ENV ENVIRONMENT BY SETTING ACTUAL PARAMETER VALUES class a21_env extends uvm_env; p_env #env(reg_a,2,1; // specific) env; //environment generic environment

`uvm_component_utils_begin(a21_env) ... function void build_phase(...); env = p_env::#(type_idreg_a,2,1::create)::type_id("env::",create this);("env ", this); ...

DON’T FORGET THIS EITHER ☺ ... OR REPLACE ALL OF THAT WITH CONVENIENCE TYPE DEFINITION typedef p_env#(reg_a,2,1) a21_env;

© Verilab & Accellera 12 DUT-Specific Sequences MUST EXTEND CORRECT TYPE

class a21_example_seq extends p_env_base_seq #(reg_a,2,1); `uvm_object_utils(a21_example_seq) ... DEFINE CONVENIENCE TYPE

typedef p_env_base_seq #(reg_a,2,1) a21_base_seq;

class a21_example_seq extends a21_base_seq; `uvm_object_utils(a21_example_seq) USE CONVENIENCE TYPE ... p_sequencer.reg_model.TX2_FIELD.write(status, 1'b0); ...

typedef p_env_init_seq #(reg_a,2,1) a21_init_seq; typedef p_env_config_seq #(reg_a,2,1) a21_config_seq; ... SHARED SEQUENCES MUST ALSO BE SPECIALIZED TO RUN ON SPECIALIZED ENVIRONMENT SEQUENCER => DEFINE AND USE CONVENIENCE TYPES

© Verilab & Accellera 13 DUT-Specific Tests

class test_example_seq extends a21_base_seq; a21_init_seq init_seq; // init sequence a21_config_seq cfg_seq; // cfg handshake ... task seq_body(); SEQUENCES ARE ALREADY `uvm_do(init_seq) SPECIALIZED BY TYPEDEFS `uvm_do_with(cfg_seq, {...}) p_sequencer.reg_model.TX2_CFG_STAT.read(status, m_val); ... NON-PARAMETERIZED SEQUENCES ALL RUN ON OBJECTS & COMPONENTS ENVIRONMENT SEQUENCER AT THE TOP-LEVEL class test_example extends a21_base_test; test_example_seq example_seq = new(); virtual task run_phase(...); example_seq.start(tb.env.sequencer); tb.env.reg_model.RX1_OFFSET_FIELD.write(status, 0); ...

© Verilab & Accellera 14 Parameterizaon Tips • Don’t do it! – avoid parameterizaon if possible – ...but someme it is an ideal fit for horizontal reuse • It is hard to implement first me round but relavely easy to retrofit – errors are all related to types specializaon – bugs are all caused by bad parameter proliferaon – so get the inial version working, then parameterize • Pracce makes perfect... – clone a working environment right now... – ...and retrofit parameterizaon just for fun!

© Verilab & Accellera 15 PARAMETERIZED INTERFACES

© Verilab & Accellera 16 Normal Interfaces

class my_comp extends uvm_component; config database virtual my_intf vif; function void build_phase(...); CIF uvm_config_db#(virtual my_intf) config_db::get config_db::set ::get(this,"","cif",vif);

BASE-TEST

ENV module testbench; C S TESTBENCH MODULE my_intf mif;

UVC my_dut dut(.ADDR(mif.addr),...); C

SVA initial begin

uvm_config_db#(virtual my_intf)

S D VIF DUT ::set(null,"*","cif",mif);

M VIF AGENT run_test(); (MIF) INTERFACE end Other AGENTs

interface my_intf(); Other OVCs logic [31:0] addr; ...

© Verilab & Accellera 17 Parameterized Interfaces

• RTL Parameters oen affect module ports – e.g. signal width (e.g. input logic [WIDTH-1:0] ADDR) – (but not the presence or absence of signal ports) • Tempng to parameterize the interface to match RTL ... interface my_intf ();#(int WIDTH=1)(); SIMPLE CHANGE TO logic [31WIDTH:0]-1:0] addr; addr; ADD PARAMETER ... TO INTERFACE

module testbench; SIMPLE CHANGES TO my_intf #mif(32;) mif; SPECIALIZE INTERFACE my_dut dut(.ADDR(mif.addr),...); AND SEND TO CONFIG_DB initial begin uvm_config_db#(virtual my_intf)#( 32)) NOTE THE INTERFACE ::set(null,"*","cif",mif); TYPE IS SPECIALIZED run_test(); IT IS NOT JUST my_intf end

© Verilab & Accellera 18 Using Parameterized Interfaces • Parameterized interfaces create a lot of superfluous code – in structural components (monitor, driver, agent, env, ...), and in – funconal objects (transacon, sequences, scoreboard, predictor,...) class monitor#(int W=1) extendsPARAMETERIZED uvm_monitor INTERFACE; `uvm_component_param_utils(monitor#(W)) PARAMETER PROLIFERATION uvm_analysis_port #(trans#(W)) aportclass; trans#(int W=1) extends virtual my_intf#(W) vif; uvm_sequence_item; rand bit[W-1:0] addr; class agent#(int W=1) extends uvm_agent; `uvm_object_param_utils(trans#(W)) `uvm_component_param_utils(agent#(W)) monitor#(W) mon; class seq#(int W=1)extends uvm_sequence#(trans#(W)) class env#(int W=1) extends uvm_env `uvm_object_param_utils; (seq#(W)) `uvm_component_param_utils(env#(W)) agent#(W) agt; e.g. ADD ONE PARAMETER class test_env extends uvm_env; TO INTERFACE CHANGED `uvm_component_utils(test_env) 43 LINES IN 11 FILES env#(32) env; PARAMETER SPECIALIZATION

© Verilab & Accellera 19 Accessor Class • Alternave for parameterized interfaces... • Uses object handle instead of virtual interface – classes support inheritance, interfaces do not!

HANDLES OF CAN REFERENCE OBJECT REGARDLESS OF INTERFACE BASE TYPE OF ANY DERIVED TYPE PARAMETERIZATION

UVC TESTBENCH MODULE C INTERFACE S D BASE CLASS DEFINES embedded DUT M accessor ACCESSOR API: AGENT object • set/get signal values • get parameter values • wait for N clocks CONCRETE CLASS IMPLEMENTS API: • ... • scoped within the interface instance • direct access to interface signals

© Verilab & Accellera 20 Accessor Class Code

`define MAX_WIDTH 256 MAX-FOOTPRINT PARAMETER ... typedef bit [MAX_WIDTH-1:0] t_uvc_data; ABSTRACT BASE CLASS DEFINES ACCESSOR API

virtual class my_uvc_accessor extends uvm_object;DEFINES FULL API, pure virtual function int get_data_width(); IS A LOT OF CODE, pure virtual task wait_cycles(int N=1); RESTRICTED TO API pure virtual function t_uvc_data get_data(); ... GET HANDLE FROM CONFIG_DB (LIKE VIF BUT A CLASS HANDLE) class monitor extends uvm_monitor#(my_uvc_txn); my_uvc_accessor accessor; MONITOR & DRIVER USE VARIABLE task get_data(); OF THE TO DO accessor.wait_cycles(); LOW-LEVEL ACCESSES if (accessor.get_strobe()) begin t_uvc_data data = accessor.get_data(); ...

© Verilab & Accellera 21 Accessor Class Interface interface my_uvc_intf #(int DATA_WIDTH=32); import my_uvc_pkg::*; PARAMETERIZED INTERFACE bit [DATA_WIDTH-1:0] data; clocking cb @(posedge clock); CONTAINS ACCESSOR CLASS input #1step data; ... EXTEND ABSTRACT endclocking BASE-CLASS & class accessor extends my_uvc_accessor; IMPLEMENT METHODS function t_uvc_data get_data(); return cb.data; endfunction function int get_data_width(); return DATA_WIDTH; endfunction ... endclass DIRECT ACCESS TO INTERFACE function accessor get_acc(string name); VARIABLES & PARAMETERS get_acc = new(name); uvm_config_db#(uvm_object)::set(null, name, "accessor", get_acc); endfunction accessor acc = get_acc($sformatf("%m")); endinterface CREATE (WITH UNIQUE NAME) AT INITIALIZATION TO AVOID RACE WITH UVM TEST START

© Verilab & Accellera 22 Accessor Class Comments • Advantages: – supports polymorphic extensions to signal interacon – highlights the limitaons of virtual interfaces! • Disadvantages: – restricts how driver & monitor can access signals (API) – lot of code setup, duplicaon & maintenance – not the standard UVM approach • Suitability? – some protocols that have to support mulple diverse I/Fs – wrapper methodology for legacy HDL transactors – ... but not appropriate for most UVM environments

© Verilab & Accellera 23 Maximum Footprint

• Avoid parameterizaon using maximum sized interface – oen referred to as maximum footprint interface INTERFACE NOT PARAMETERIZED class my_config extends uvm_object; interface my_intf(); rand int width; logic [31:0] addr, data; constraint wc {soft width == 32;} ... INTERFACE SUPPORTS MAX WIDTH class test_env extends uvm_env; module testbench; cfg.randomize() with {width == 16;} my_intf mif; UVC USES CONFIG TO my_dut16 dut( CONSTRAIN OUTPUT VALUES .ADDR(mif.addr[15:0]), & CHECK INPUT VALUES .DATA(mif.data[15:0]),...); (CAN BE UGLY BIT-SLICE CODE) initial begin uvm_config_db#(virtual my_intf) ::set(null,"*","cif",mif); DUT IGNORES UNUSED INPUT BITS run_test(); & UNUSED OUTPUT BITS ARE ‘Z end DUT CONNECTS TO REQUIRED SLICE

© Verilab & Accellera 24 Interface Wrapper • Maximum footprint can be enhanced with wrapper – parameterized interface wrapper for testbench module – contains a maximum footprint interface for class world interface my_intf_wrapper PARAMETERIZED WRAPPER INTERFACE #(int WIDTH=8, string INST=“*”, string FIELD=“cif”)(); import uvm_pkg::*; NON-PARAMETERIZED MAXIMUM logic [WIDTH-1:0] addr, data; FOOTPRINT INTERFACE FOR UVC my_intf mif(); assign mif.data[WIDTH-1:0] = data; // from DUT to UVC ENCAPSULATE PARTIAL assign addr = mif.addr[WIDTH-1:0]; // from UVC to DUT SIGNAL ASSIGNMENTS initial uvm_config_db#(virtual my_intf)::set(null,INST,FIELD,mif); ENCAPSULATE CONFIG module testbench; FOR VIRTUAL INTERFACE my_intf_wrapper#(16) ifw; my_dut16 dut(.ADDR(ifw.addr),.DATA(ifw.data),...); initial EASY WRAPPER USE IN run_test(); TESTBENCH MODULE

© Verilab & Accellera 25 Interface Tips

• Parameterized interfaces look good in theory, but implementaon is complex • If interface adapon is only reason for parameters... – recommend you do not use parameterized interfaces – use the maximum footprint approach with wrapper – (or in some cases consider the accessor class soluon) • If classes are parameterized for other reasons... – then use parameterized interfaces as well!

© Verilab & Accellera 26 PARAMETERIZED REGISTERS

© Verilab & Accellera 27 Generic Registers

• Two approaches for register generaon: – generate DUT-specific register model on-demand

(separate model for each derivave) MOST COMMON • registers are specialized in all representaons APPROACH (RTL, documentaon, UVM register model) • code is simpler, but needs to be generated for each derivave – generate generic register model once for all DUTs (one model that adapts to each derivave) APPROPRIATE FOR • registers are generic in all representaons RTL IP & UVC (RTL, documentaon, UVM register model) COMBO PACKAGES • code is more complex, harder to read, but is only generated once PARAMETERIZED CONFIGURABLE REGISTERS REGISTERS

© Verilab & Accellera 28 Normal Registers

• Fields, registers & blocks are generated on-demand – they are specialized for DUT-specific requirements class my_reg extends uvm_reg; CREATE & CONFIGURE `uvm_object_utils(my_reg) EACH FIELD virtual function void build(); my_field = uvm_reg_field::type_id::create(”my_field"); my_field.configure(this, 32, 0, "W1R”,1,'h0,1,1,1); FIELD WIDTH USES A class my_reg_block extends uvm_reg_block; GENERATED NUMBER `uvm_object_utils(my_reg_block) ... rand my_reg my_reg; ... CREATE, CONFIGURE function void build(); & BUILD EACH REG my_reg = my_reg::type_id::create(”my_reg"); my_reg.configure(this, null, ”my_reg"); my_reg.build();

© Verilab & Accellera 29 ALL GENERATED CODE Parameterized Registers

• Fields, registers and blocks are classes – they can be parameterized (e.g. width, default, etc.): class my_reg #(int WIDTH=1) extends uvm_reg; `uvm_object_param_utils(my_reg#(WIDTH)) FIELD WIDTH USES virtual function void build(); PARAMETER my_field = uvm_reg_field::type_id::create(”my_field"); my_field.configure(this, WIDTH, 0, "W1R”,1,'h0,1,1,1);

class my_reg_block #(int WIDTH=1) extends uvm_reg_block; `uvm_object_param_utils(my_reg_block#(WIDTH)) ... PARAMETER rand my_reg#(WIDTH) my_reg; PROLIFERATION ... (REG, BLOCK,...) function void build(); my_reg = my_reg#(WIDTH)::type_id::create(”my_reg"); my_reg.configure(this, null, ”my_reg"); my_reg.build();

© Verilab & Accellera 30 ALL GENERATED CODE e.g. ADD ONE FIELD Using Parameterized Registers PARAMETER CHANGED 30 LINES • Parameterizaon is invasive & ubiquitous IN 6 FILES – all classes referencing model become parameterized or specialize the required type by fixing the parameter class reg_sequencer#(int W=1) extends uvm_sequencerPARAMETER; my_reg_block#(W) reg_model; PROLIFERATION `uvm_component_param_utils(reg_sequencer#(INW) )MIDDLE LAYERS (SEQ,SEQR,AGT,ENV,...) class reg_base_seq#(int W=1) extends uvm_sequence; `uvm_object_param_utils (reg_base_seq#(W)); `uvm_declare_p_sequencer(reg_sequencer#(W))

class top_vsequencer extends uvm_sequencer; reg_sequencer#(32) reg_sequencer; PARAMETER `uvm_component_utils(top_vsequencer) SPECIALIZATION IN UPPER LAYER class my_reg_seq extends reg_base_seq#(32); (SEQ,SEQR,ENV...) `uvm_object_utils (my_reg_seq);

© Verilab & Accellera 31 ALL USER CODE Configuraon-Aware Registers

• Alternave generic register model – build & configure based on configuraon object fields – no parameters or compile-me defines • Problem: – uvm_reg_block is a uvm_object not a uvm_component – so it does not follow UVM phasing for safe configuraon • Soluon: – implement uvm_component wrapper around model – extract configuraon during build phase & use in model

© Verilab & Accellera 32 Normal Register Build NOTE : REG_MODEL IS class my_env extends uvm_env; CONSTRUCTED BUT EMPTY my_reg_block reg_model; AFTER CREATE function void build_phase(...); reg_model = my_reg_block::type_id::create("reg_model", this); reg_model.configure(null, "reg_model"); CREATE THE reg_model.build(); REG_BLOCK reg_model.lock_model(); BUILD THE class my_reg_block extends uvm_reg_block; REG_BLOCK function new (...); super.new(); ... virtual function void build(); CREATE & BUILD reg_a = my_reg_a::type_id::create(”reg_a"); EACH REGISTER reg_a.configure(this, null, ”reg_a”); reg_a.build(); CREATE & CONFIGURE EACH FIELD class my_reg_a extends uvm_reg; function new (...); super.new(); ... FIELD WIDTH USES A virtual function void build(); GENERATED NUMBER field_x = uvm_reg_field::type_id::create(”field_x"); field_x.configure(this, 32, 0, ”RW", 1, 'h0, 1, 1, 1);

© Verilab & Accellera 33 Configurable Register Build class my_reg_wrapper extends uvm_component; NOTE : REG_MODEL IS my_reg_block reg_model; CONSTRUCTED AND NOT USE CONFIG TO SET my_config cfg; EMPTY AFTER CREATE KNOBS function IN FIELD void CLASS build_phase (...); reg_model = my_reg_block::type_id::create("reg_modelCREATE", REG_BLOCK,this); reg_model.reg_a.field_x.set_width(cfg.width); REGISTERS & FIELDS reg_model.configure(null, "reg_model"); reg_model.build(); CREATE reg_model MOVED .lock_model(); BUILD TO NEW BUILD THE REG_BLOCK class my_reg_block extends uvm_reg_block; function new (...); reg_a = my_reg_a::type_id::create(”reg_a");... BUILD EACH virtual function void build(); REGISTER reg_a.configure(this, null, ”reg_a”); reg_a.build(); CONFIGURE EACH FIELD class my_reg_a extends uvm_reg; function new (...); field_x = my_reg_field::type_id::create(”field_xFIELD");... WIDTH COMES virtual function void build(); FROM CONFIG KNOB field_x.configure(this, field_x.width, 0, ”RW", 1, 'h0,...);

© Verilab & Accellera 34 Using Register Wrapper

• All funconality is contained inside wrapper class – just instanate and configure like a normal component CONFIGURATION-AWARE REGISTERS class my_env extends uvm_env; USING WRAPPER COMPONENT ... IS MORE AD-HOC AND LIMITED my_reg_wrapper reg_wrapper; BUT BETTER ENCAPSULATED my_config cfg; ... `uvm_component_utils_begin(my_env) INSTANTIATE WRAPPER `uvm_field_object(cfg, UVM_ALL_ON) ... CREATE WRAPPER function void build_phase(...); reg_wrapper = my_reg_wrapper::type_id::create(...); uvm_config_object::set(this, "*", ”cfg", cfg); ... PASS DOWN CONFIG

© Verilab & Accellera 35 Register Tips

• Generate derivave-specific registers on-demand – if possible, since it makes life easy for everyone! – ...but it is not always appropriate (e.g. many DUT parameters in registers, bundled IP&VIP) • If class environment is already parameterized – then generate and use parameterized registers • If class environment is not parameterized – then do not use parameterized registers – use configuraon-aware registers and encapsulate in a wrapper component

© Verilab & Accellera 36 References and further reading • “Abstract BFMs Outshine Virtual Interfaces for Advanced SystemVerilog Testbenches” D.Rich, J.Bromley, DVCon 2008, www.doulos.com/downloads • “Parameterized Interfaces and Reusable VIP” A.Pra, Blog, hps://blogs.synopsys.com/vip-central • “On SystemVerilog Interface Polymorphism and Extendability” T.Timi, Blog, hp://blog.verificaongentleman.com • “Pragmac Verificaon Reuse in a Vercal World” M.Lierick, DVCon 2013, www.verilab.com/resources

© Verilab & Accellera 37 Quesons

© Verilab & Accellera 38