Register Testing the “Easy Way” at DVCON Europe

DVCON Europe is coming to Munich, December 6-7, 2022. Hope to see you there! I’ll be presenting a paper on “Register Testing – Exploring Tests, Register Model Libraries, Sequences and Backdoor Access” between 10:45am and 12:15pm on Wednesday, December 7.
Writing Simple Code
It’s really a paper on writing simple, easy to understand models and libraries as opposed to building a register package – although the examples operate as small register packages.
I’ll share a simple register modeling package and share a small example as we cruise through the ideas and concepts.

The UVM Register package is well used, and well loved – clocking in at about 20,000 lines of code in total. The package discussed in the paper does not assume to be as complete as the UVM Register package – but is it complete enough? I’d love to hear your thoughts in Munich.
I’m a fan of registers, but many (most?) registers cannot just be randomized or stomped through with marching ones. Some can. But could you imagine setting registers to random values in the control chip for the wood chipper that the tree guys use? Wood chippers are scary enough already.
Instead, I think register tests “know what the registers can do” – they are aware. Or at least register tests embody relationships between registers (regA has to be non-zero, when regB[3] is 1). These kinds of relationships can be captured in tests or constraints for example.
Sometimes a useful register testbench just monitors the addresses, and maps the addresses into register names for easier debug.
In any case, a register model is a useful thing. But does it have to be so big?
Register-To-Bus Layering
You were getting ready to ask – “What about the register-to-bus layering”? Simple. A sequence does the work. You write code to go back and forth between the register layer and the bus protocol layer. But not much code. You can change format. You can issue many transactions. It’s just code. And small.
class REGISTERtoBUS_rw_sequence extends uvm_sequence#(bus_transaction);
`uvm_object_utils(REGISTERtoBUS_rw_sequence)
bit all_done;
task body();
`uvm_info(get_type_name(), "...running", UVM_MEDIUM)
all_done = 0;
wait (all_done == 1);
endtask
task start_reg_item(register_transaction register_tr);
bus_transaction bus_tr;
// Translate to BUS
bus_tr = new("bus_tr");
bus_tr.rw = register_tr.rw;
bus_tr.addr = register_tr.addr;
bus_tr.data = register_tr.data;
start_item(bus_tr);
register_tr.bus_tr = bus_tr; // Save it for later.
// Translate back to register
endtask
task finish_reg_item(register_transaction register_tr);
bus_transaction bus_tr;
// Translate to BUS
$cast(bus_tr, register_tr.bus_tr);
bus_tr.rw = register_tr.rw;
bus_tr.addr = register_tr.addr;
bus_tr.data = register_tr.data;
finish_item(bus_tr);
register_tr.data = bus_tr.data;
// Translate back to register
endtask
endclass
But now I’m getting ahead of the story. More details and discussion at the show.
A Register
Create functionally interesting registers like a status register with a READ-ONLY field named ‘active_tr’. The bit-fields are described with a struct. The behavior of this register is “regular” – nothing fancy, except that the the field ‘active_tr’ is READ-ONLY. It cannot be written. So the write() routine is implemented as such.
typedef struct packed {
reg [1:0] status;
reg [7:0] error_count;
reg [4:0] active_tr; // READ-ONLY
} csr_t;
class csr_RO_active_tr extends register#(csr_t);
function void write(T v);
value.status = v.status;
value.error_count = v.error_count;
endfunction
endclass
Simple.
Come by DVCON Europe to chat – the paper will be presented Wednesday, December 7. The conference is December 6 and 7. Hope to see you there.
Rich