The UVM Register Layer
Introduction, Experiences and Recipes
Steve Holloway Principal Verification Engineer
Dialog Semiconductor
Overview
Register Model Requirements
UVM Register Layer
Creating the Register Model
Register Modeling Recipes
Conclusions
2
Register Model Requirements
A standard modeling approach
Previous use of internal register models and OVM_RGM
Transition to UVM within Dialog
Distributed register blocks
Register block per IP
Access & update on a per-field basis
Non-standard "quirky" registers e.g.
Locking - dependent on bus master
"Snapshot" - coherency between registers
Interrupt / event generation
Passive update of register model
Re-use in other (directed) environments
Automated generation
3
UVM Register Layer (UVM_REG)
Abstract model for registers and memories in DUT
Maintains a "mirror" of the DUT registers
Hierarchy analogous to DUT:
Register Block
Register File
Memory
Register
Field
Standardised register access API
uvm_reg_block
uvm_reg_block
uvm_mem
uvm_reg
uvm_reg
uvm_reg_field
uvm_reg_field
uvm_reg
Address-independent instance/string names
Address maps
model access via a specific interface / bus master
4
uvm_reg
uvm_reg_field
Register Model Components
user sequence
m_regblock.R0.write(8'ha5);
m_regblock.R1.read(data);
. . .
Register Access API
uvm_reg_block
uvm_reg_map
uvm_reg_adapter
predict(uvm_reg_item)
Predictor
uvm_reg_adapter
0110110110
0010100100
1100100001
Bus Agent
DUT
S
D
bus_item
0110110110
0010100100
active part
5
1100100001
Register Access API
write()
Register Model
Generate a physical write to the DUT register set()
read()
Desired Value
Generate a physical read from the DUT register
Mirrored Value
set()
Set the desired value of the register in the model
get()
Get the desired value of the register from the model
update()
Update the DUT with the desired value in the model
mirror()
Read the DUT register and check / update the model value
predict()
Set the value of the register in the model
6
get()
update()
Creating the Register Model
field configuration
class SYS_CTRL_0 extends uvm_reg;
rand uvm_reg_field SYS_CONF0;
rand uvm_reg_field SYS_CONF1;
rand uvm_reg_field SYS_STATUS0;
function void configure(uvm_reg
parent,
int unsigned
size,
int unsigned
lsb_pos,
string
access,
bit
volatile,
uvm_reg_data_t
reset,
bit
has_reset,
bit
is_rand,
bit individually_accessible)
virtual function void build();
SYS_CONF0 = uvm_reg_field::type_id::create("SYS_CONF0");
SYS_CONF0.configure (this, 1, 0, "RW", 0, 1'h0, 1, 1, 1);
. . .
endfunction
function new(string name = "SYS_CTRL_0");
super.new(name,16,build_coverage(UVM_NO_COVERAGE));
endfunction
`uvm_object_utils(SYS_CTRL_0)
endclass: SYS_CTRL_0
hierarchical
build() of
regmodel
Handling "Quirky" Registers
UVM_REG gives simple model for "free"
"Dumb" storage subject to 1 of 25 pre-defined access policies:
{"RW", "RC", "RS", "WRC", . . .}
Most of our registers are more quirky than this
More complex behaviour is handled by callbacks
Pre-defined "hook" methods called during model update
pre_read()
post_read()
pre_write()
post_write()
post_predict()
Using "passive" prediction, important to use post_predict() hook
Simple Callback "Control" field
Set
Write 0 1
0 1
Clear
Write 1 0
0 0
After predictor
has observed
R/W
value before
predict()
class control_reg_field_cbs extends uvm_reg_cbs;
virtual function void post_predict(input
input
inout
input
input
input
uvm_reg_field
uvm_reg_data_t
uvm_reg_data_t
uvm_predict_e
uvm_path_e
uvm_reg_map
if (kind == UVM_PREDICT_WRITE)
value = (value === 2'b01) ? 2'b01 :
(value === 2'b10) ? 2'b00 : previous;
endfunction
endclass: control_reg_field_cbs
9
fld,
previous,
value,
kind,
path,
map);
value to be
set after
predict()
UVM_PREDICT_READ
UVM_PREDICT_WRITE
UVM_PREDICT_DIRECT
Callback for Locking Behaviour
class lock_reg_field_cbs extends uvm_reg_cbs;
string m_lock_name;
`uvm_object_utils(lock_reg_field_cbs)
Locking field
name in
constructor
function new(string name = "lock_reg_field_cbs", string lock_name = "");
super.new(name);
m_lock_name = lock_name;
endfunction: new
virtual function void post_predict(. . .);
Extract the lock
. . .
field from block
if (kind == UVM_PREDICT_WRITE) begin
lock_fld = m_reg_block.get_field_by_name(m_lock_name);
if (lock_field.get())
If locked, revert
value = previous;
endfunction: post_predict
to previous
10
Modeling Status Registers
RTC Counter Field declared as "RO"
DUT
SYS_RTC_COUNT
task my_scoreboard::update_rtc_count;
int unsigned cnt = 0;
Does not
use access
policy "RO"
forever begin
@(timer_event_e);
void'(m_regmodel.SYS_RTC_COUNT.predict(cnt++));
end
Possible to use
access policy &
callbacks
endtask: update_rtc_count
reg.predict(value, .kind(UVM_PREDICT_WRITE));
reg.predict(value, .kind(UVM_PREDICT_READ));
11
Handling DUT Uncertainty
Sometimes we don't know exactly when a DUT register will change
Register Model
DUT Register
???
1
Don't update if
comparison is
disabled
task my_scoreboard::uncertainty_window;
forever begin
@(window_start_e);
class my_reg_field extends uvm_reg_field;
my_fld.set_compare(UVM_NO_CHECK);
@(window_end_e);
function void do_predict(. . .);
my_fld.set_compare(UVM_CHECK);
super.do_predict(rw, kind, be);
end
if (kind == UVM_PREDICT_READ)
endtask: uncertainty_window
if (get_compare() == UVM_NO_CHECK)
value = previous;
endfunction: do_predict
endclass: my_reg_field
12
Using Extension Information
Additional information can be attached to register access via "extension" object.
uvm_reg my_reg;
Sending
my_bus_info extra_info = new();
master_id
m_regmodel.get_reg_by_name("SYS_CTRL_0");
with write()
extra_info.master_id = HOST;
my_reg.write(status, data, .parent(this), .extension(extra_info));
Adapter needs to use get_item() to access extension info
virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
my_bus_info
extra_info;
uvm_addr_map
uvm_reg_item item = get_item();
calls set_item()
$cast(extra_info, item.extension);
extension is a
uvm_object
bus_trans.addr
= rw.addr;
bus_trans.data
= rw.data;
bus_trans.master_id = extra_info.master_id;
return bus_trans;
endfunction: reg2bus
13
Synchronising to Register Access
class trigger_reg_field_cbs extends uvm_reg_cbs;
. . .
virtual function void post_predict(. . .);
uvm_event access_event;
if (kind == UVM_PREDICT_WRITE) begin
if (value != previous) begin
access_event = uvm_event_pool::get_global($psprintf("%s_WRITE", fld.get_name()));
access_event.trigger();
end
end
endfunction
Synchronise
endclass: trigger_reg_field_cbs
across env with
uvm_event_pool
task my_scoreboard::model_timer();
uvm_event ev_timer_start = uvm_event_pool::get_global("TIMER_START_WRITE");
ev_timer_start.wait_trigger();
. . .
endtask: model_timer
14
Using SVA with the Register Model
GPIO a function of input & register settings
gpio_config
gpo
gpi
property gpio_control_p @(gpio_change_e)
(gpo == (gpi ^ gpo_invert) & gpio_en);
endproperty
How can we "hook" the regmodel into a testbench?
15
Can only live in
module-based
code
Hooking in the Regmodel
uvm_env
testbench
uvm_component
uvm_reg_block
reg_monitor
DUT
0110110110
0010100100
uvm_reg_block
0110110110
0010100100
1100100001
SVA
Properties
bit [3:0] gpio_config;
initial begin
m_reg_monitor = new ("m_reg_monitor", null);
m_reg_monitor.add_field("GPIO_CONFIG");
forever begin
m_reg_monitor.wait_write("GPIO_CONFIG");
gpio_config = m_reg_monitor.get("GPIO_CONFIG");
end
end
16
Conclusions
Register Modeling Standard is key to UVM
Inconsistent approach with OVM
UVM_REG has all features necessary
Early UVM 1.1 issues
No support for passive compare & update (Mantis #3540)
~20 bug fixes in UVM-1.1a, several more in 1.1b; 1.1c
Callbacks have to be used for "quirky" registers
VMM concept adopted by UVM
Can become complex if "layering" behaviours
Good examples & boilerplate at http://www.verificationacademy.com
17
Energy Management Excellence
Any Questions ?
18