(in my verification environment we use vr_ad
package.). I try to implement the next: When data is written to one of the registers ( timer_load
), another register ( timer_bgload
) should be updated with the same data.
I've found the next example in UVM User Guide :
// Attaching the target register file to the broadcasted register
extend ex_c_bus_env {
post_generate() is also {
xcore_regs.vr_ad_rx_data.attach(xbus_regs);
};
};
// Implement the broadcast:
// When writing to register VR_AD_RX_DATA in XCORE vr_ad_reg_file,
// propagate the value to the VR_AD_XBUS_DATA register in ACTIVE_XBUS.
extend ACTIVE_XBUS vr_ad_reg_file {
indirect_access( direction : vr_ad_rw_t, ad_item : vr_ad_base) is {
if ad_item is a VR_AD_RX_DATA vr_ad_reg (d) {
vr_ad_xbus_data.write_reg_val(d.get_cur_value());
};
};
};
My registers:
reg_def TIMER_LOAD_0 TIMER 20'h00010 {
reg_fld timer_load : uint (bits : 32) : RW : 0xffff;
};
reg_def TIMER_BGLOAD_0 TIMER 20'h00014 {
reg_fld timer_bgload : uint (bits : 32) : RW : 0xffff;
};
reg_def TIMER_BGLOAD_1 TIMER 20'h00028 {
reg_fld timer_bgload : uint (bits : 32) : RW : 0xffff;
//another reg with the same instance name
};
My code for updating the timer_bgload
register after a data was written to tiemr_load
:
extend TIMER vr_ad_reg_file {
indirect_access( direction : vr_ad_rw_t, ad_item : vr_ad_base) is {
if ad_item is a TIMER_LOAD_0 vr_ad_reg (d) {
timer_bgload.write_reg_val(d.get_cur_value());
};
};
};
unit timer_env_u like any_env {
post_generate() is also {
timer_regs.timer_load_0.attach(timer_regs.timer_bgload_0.timer_bgload);
};
};
I get a compilation error :
*** Error: No such variable 'timer_bgload'
at line 17 in @timer_reg_db
timer_bgload.write_reg_val(d.get_cur_value());
I really appreciate any help.
You can attach the timer_load
register to the timer_bgload
register directly and implement indirect_access(...)
there:
// attach the regs
extend TIMER vr_ad_reg_file {
post_generate() is also {
timer_load_0.attach(timer_bgload_0);
};
};
// implement indirect_access()
extend TIMER_BGLOAD_0 vr_ad_reg {
indirect_access(direction : vr_ad_rw_t, ad_item : vr_ad_base) is {
if direction == WRITE and ad_item is a TIMER_LOAD_0 vr_ad_reg (d) {
write_reg_val(d.get_cur_value());
};
};
};
I don't know why the Cadence example took the long route of attaching the register file to the indirect register.
Also, if you have more than one TIMER_LOAD/BGLOAD registers (seems like you may have 2), then the best thing to do is define the types first:
// define register types without instantiation in reg_file
reg_def TIMER_LOAD {
reg_fld timer_load : uint (bits : 32) : RW : 0xffff;
};
reg_def TIMER_BGLOAD {
reg_fld timer_bgload : uint (bits : 32) : RW : 0xffff;
};
After you define the types, you instantiate them in the register file manually as many times as you need to. Have a look in the manual, there is an example showing you exactly how to do it.
This means that it's enough to implement the indirect_access(...)
method in the TIMER_BGLOAD
subtype (only once) as opposed to two times (for TIMER_BGLOAD_0
and TIMER_BGLOAD_1
).
I'd implement it with post_access
, something like that:
extend TIMER_LOAD_0 TIMER vr_ad_reg {
post_access(operation : vr_ad_rw_t) is {
if operation == WRITE {
var rgf := get_access_path()[0].as_a(TIMER vr_ad_reg_file);
rgf.timer_bgload_0.timer_bgload = timer_load;
};
};
};
Pay attention, that it might not work on first hit. If it's not, I'd build it gradually, starting with 'empty' code like this:
extend TIMER_LOAD_0 TIMER vr_ad_reg {
post_access(operation : vr_ad_rw_t) is {
print me, operation;
};
};
And putting a breakpoint in the print
statement, opening a data browser, looking what are the exact names of the fields we got there, try to access them from Specman CLI - and when it works - code it back.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.