In a previous post I described all the steps that you have to take in order to start a register model using uvm_reg library.
One very nice feature of uvm_reg is the register callback extensions. This is just a fancy name for saying that you can set some action to be executed when a register field is accessed (e.g. clear field A when field B is written with value 1).
So let’s go through the steps required to use this feature.
Step #1 – Declare a Register Callback Extension
To declare a register callback you have to create a class which extends from uvm_reg_cbs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class cfs_dut_cbs_clear_int extends uvm_reg_cbs; `uvm_object_utils(cfs_dut_cbs_clear_int) //pointer to interrupts register cfs_dut_reg_irq ptr_irq; function new(string name = ""); super.new(name); endfunction virtual function void post_predict( input uvm_reg_field fld, input uvm_reg_data_t previous, inout uvm_reg_data_t value, input uvm_predict_e kind, input uvm_path_e path, input uvm_reg_map map); if(kind == UVM_PREDICT_WRITE) begin cfs_dut_reg_field reg_field; if($cast(reg_field, fld)) begin if(reg_field.write_data[0] == 1) ptr_irq.ovf.predict(0); end end end endfunction endclass |
Step #2 – Connect The Register Callback Extension
Once the register callback class is declared you have to instantiate it and connect it to the corresponding register field.
At step #1 I declared a callback which will clear an overflow interrupt field (ptr_irq.ovf) when value ‘1’ is written to the field containing the callback.
So let’s connect this callback to the “overflow interrupt clear” field:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class cfs_dut_env extends uvm_env; ... function void connect_phase(uvm_phase phase); //create an instance of the callback cfs_dut_cbs_clear_int cbs = cfs_dut_cbs_clear_int::type_id::create("cbs"); //connect the pointer to "interrupts" register cbs.ptr_irq = reg_block.irq; //connect the callback instance to the "overflow interrupt clear" field uvm_callbacks#(uvm_reg_field, cfs_dut_cbs_clear_int)::add(reg_block.irq_clr.ovf, cbs); endfunction endclass |
And that’s it! Now whenever there is a write with value 1 to reg_block.irq_clr.ovf field reg_block.irq.
Extra – Dealing with “Write One Clear” Fields
In most of the real cases fields which are clearing other fields are “Write One Clear”.
The problem with these fields is that in the callback class you can not easily determine if the field was written with value ‘1’ because the argument ‘value‘ of function post_predict() gives the cleared value of the field.
For this reason you can implement a custom register field which retains the written value:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class cfs_dut_reg_field extends uvm_reg_field; `uvm_object_utils(cfs_dut_reg_field) time write_time; uvm_reg_data_t previous_mirror_value; uvm_reg_data_t write_data; function new(string name = ""); super.new(name); write_time = 0; previous_mirror_value = 0; endfunction virtual function void do_predict(uvm_reg_item rw, uvm_predict_e kind = UVM_PREDICT_DIRECT, uvm_reg_byte_en_t be = -1); uvm_reg_data_t local_previous_mirror_value = get_mirrored_value(); if(kind == UVM_PREDICT_WRITE) begin write_data = rw.value[0]; end super.do_predict(rw, kind, be); if(kind == UVM_PREDICT_WRITE) begin previous_mirror_value = local_previous_mirror_value; write_time = $time; end endfunction endclass |
When you declare the “interrupts clear” register you just use this new register field class:
1 2 3 4 5 | class cfs_dut_reg_irq_clr extends uvm_reg; ... rand cfs_dut_reg_field ovf; ... endclass |
That’s it! Hope you found this information useful 🙂
Hi Cristain,
Can you please post example for “multiple reset types support with different reset values per reset type, per register field” ?
Hi Santosh,
I wrote an article on the subject you requested: http://cfs-vision.com/2016/07/22/systemverilog-how-to-model-multiple-reset-signals-in-uvm-registers/
Hope it will be useful to you!
Best regards,
Cristi
I didn’t quite understand what you mean by? How can we declare this new field class?. Because RAL automatic generation these UVM Registers right?
When you declare the “interrupts clear” register you just use this new register field class: