Custom Field Access Policies in UVM RAL

As promised in my last post today we're going to look at how to define a custom field access policy in the UVM register package.


This is a companion discussion topic for the original entry at https://verificationgentleman.netlify.app/2014/04/13/custom-field-access-policies-in-uvm-ral.html

Hello Tudor,

I found this post really helpful and easy to understand, I have a question regarding to this lets say your register has 64 different fields and if you want to define access policy for the entire register (i.e secure only write access) you’ll need 64 uvm_reg_field_cb::add(field_n, custom_cbs); which to me seems to a lot code to be written, do you think/know if there is a different way to setup custom register access policies(for the entire register at once).

Since ‘predict()’ isn’t virtual and there aren’t any ‘pre/post’ predict hooks defined in ‘uvm_reg_field’, our options are limited.

One solution would be to override ‘do_predict()’, which is virtual and gets called by ‘predict()’. Since it’s not mentioned in the standard, I wouldn’t recommend doing this.

The only viable option is to use callbacks. Adding the callback on 64 fields doesn’t mean we need 64 calls to ‘add(…)’, since we can loop over all fields of a reg:

uvm_reg_field fields[$];
some_reg.get_fields(fields);
foreach (fields[i])
uvm_reg_field_cb::add(fields[i], some_cb_inst);

We could also create another convenience class that adds the callback to all fields of a certain reg:

class some_reg_cb extends uvm_callbacks #(uvm_reg, some_cb);
static function void add(uvm_reg rg, some_cb cb);
uvm_reg_field fields[$];
some_reg.get_fields(fields);
foreach (fields[i])
uvm_reg_field_cb::add(fields[i], some_cb);
endfunction
endclass

This way we don’t have to duplicate the looping code every time we want to define another register with the callback on all of its fields:

some_reg_cb::add(some_reg0, some_cb_inst);
some_reg_cb::add(some_reg1, some_cb_inst);
some_reg_cb::add(some_reg2, some_cb_inst);

(Note; I didn’t try this code out, but I’m pretty confident it should work.)

Thank you very much for your reply Tudor, indeed I works, Sorry to hijack with questions your blog, I have another question that has been causing me a lot of trouble to implement my register model, most of the examples over the web (if not all) describe how to create custom accesses based on fields using post predict which is pasive and gets triggered no matter who triggered the write/read operation (if explicit prediction it is used) this is fine but what about predicting the write value based on physical bus signals send from (APB PPROT for example or AXI PROT) this signals can alter the predicted write value of the register based on its value. I have come across to the usage of the extension field memeber of the uvm_reg_item in the reg2bus function of adapter class to provide any additional information for write/read to the actual VIP/sequencer that is going to execute the bus transaction, but only afects how the transaction is send to the bus

virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
my_bus_info extra_info;
uvm_reg_item item = get_item();
$cast(extra_info, item.extension);
bus_trans.addr = rw.addr;
bus_trans.data = rw.data;
bus_trans.master_id = extra_info.master_id;
return bus_trans;
endfunction: reg2bus

I couldn’t find any mechanism (callback, method) to predict accurately the model based on signals such as those, even extending the predictor doesnt helped me out since all information about the bus operation is (except for data and addr) is discarded by the predictor when calling adapter.bus2reg(tr,rw)
Sorry if I was no able to elaborate my question/comment properly

If you just need to ignore writes/reads when a protection level doesn’t match, then you can create your own predictor class and override its ‘write(…)’ function:

class my_protected_predictor extends uvm_reg_predictor #(apb_item);
apb_prot_t allowed_prot;

virtual function void write(apb_item tr);
if (apb_item.prot >= allowed_prot)
write(tr);
endfunction
endclass

This is usually the case. Moreover, wrong protection should also issue a bus error and the predictor shouldn’t get triggered in that case. Ideally this would have been done through a ‘UVM_NOT_OK’ response in the converted ‘reg_bus_op’, but I think there’s a bug in the UVM code so you need a custom predictor for that too:

class my_protected_predictor extends uvm_reg_predictor #(apb_item);
apb_prot_t allowed_prot;

virtual function void write(apb_item tr);
if (apb_item.resp == OKAY)
write(tr);
endfunction
endclass

If depending on the value of the protection signal you can get different read/write values, then it’s more complicated. You need to capture the current transaction in some callback somewhere and assign it from the ‘write(…)’ function of the predictor:

class some_callback extends uvm_reg_cbs;
apb_item trans;

// do stuff in ‘post_predict(…)’ based on trans
endclass

class my_protected_predictor extends uvm_reg_predictor #(apb_item);
some_callback cb;

virtual function void write(apb_item tr);
cb.trans = tr;
write(tr);
endfunction
endclass

The same instance of the CB you need to pass to the registers as well. This way you know what protection you had. It’s also guaranteed that the transaction is updated before ‘predict(…)’ gets called.

P.S. No problem with asking questions, that’s what the blog is for.

Again Tudor thank you so much for your explanation, I totally forgot that I can override the write function of the predictor :slight_smile:

The last one isn’t the cleanest approach, but I don’t really see any other possibility, because the code for ‘uvm_reg_predictor’ isn’t modular at all (the ‘write(…)’ function has 100 lines, for example).

Hi Timi,

I have slightly different question.
In my environment mixed languages, SV-UVM is for passive and specman for drive part.
I want to use UVM RAL only for passive mode only , is this possible?
Can we have uvm_reg_adapter,uvm_reg_predictor and call back’s way of predicting in this environment for passive mode only? I saw that with out sequencer specified for address map , uvm ral throws error from uvm_reg_map class’s set_sequencer() method definition.

I never tried this, but this should be theoretically possible. At the end of the day, it’s not much different from a situation where you’re doing virtual reuse. Whether there’s some “bug” in the UVM source code that prevents this, I can’t say (e.g. some calls to sequencer stuff, even when working in passive operation).