Todays complex chips has thousands of register to configure the chip and to communicate the status to software. These registers play a complex role in the chip operation So a test bench should verify these registers properly. Verification of these registers is tedious. As there are thousands of registers in a chip, the testbench should have a handy hooks to access these registers. Implementing testbench components for these registers is not one time job. Most designs change their register specification during the design development. So a very flexible testbench component should be available to satisfy these needs. When I was working for Ample, we had a script which generates testbench component for these registers. Register specification is input to these script. So when ever register file is changed, Just run the script, we don't need to change verilog module for these changes. These scripts can be used across modules, across projects and across companies also. There are some EDA tools just to do this job. I believe that a proper homemade script has better control then getting it from some EDA guy and you know home made scripts are life time free.
Registers can be mainly classified in to these categories
1) Configuration Registers.
2) Status Registers.
3) Mask Registers.
4) Interrupt Registers(makeable and nonmaskable).
What are the features that this testbench component should support?
1) It should have a data structure to store the values of config register .Testbench will write in to these register while it is writing to dut registers. These are called shadow registers. Shadow registers should have the same address and register name as DUT so it is easy to debug.
2) Back door access: There are two type of access to register in DUT. Front door and back door. Front door access uses physical bus . To write a value in to DUT registers, it takes some clock cycles in front door access. And writing for thousands of registers is resource consuming. Remember, only one register can be assigned at a time. One cannot make sure that only one method is called at one time. To make sure that only one method is assessing the bus, semaphore is used. In back door access, registers are access directly. In zero time. Accessing to these locations using back door will save simulation time. There should be a switch to control these feature. So after verifying the actual access path of these registers, we can start using back door access. In verilog, using Hierarchy reference to DUT register, we can by pass this path.
3) The Shadow registers by default should contain default values from register specification. A task should be provided to compare each register in shadow registers and DUT. After reset, just call this task before doing any changes to DUT registers. This will check the default values of the registers.
4) Methods should be provided for read or write operation to dut registers using name and also address. Named methods are handy and readable mainly from test cases. While address based methods are good while writing to bulk locations( using for loop etc...).
5) Every register in Testbench may have these information.
// Comments which describes the register information.
Address of register.
Offset of register.
Width of register.
Register name as string.( Name should be self descriptive and same as in DUT. This string is used in printing while debugging.)
Some are methods which are used for register in functional verification .
All the above methods should be accessible by name and also by address.
Write random task:
Some registers values can be any constrained random value. Lets take an ether net. The unicast destination address can be any value which is not broadcast or multi cast. So the random values should be constraint. Some times, these random values depend on some other registers also. If this task is not provided, while writing the test cases, one may forget the limitation of the register value and the DUT misbehaves and may spend hours in debugging. The best way to use random values is using this task.
Interrupt and status registers in Testbench should be updated by update task. These registers should contain the expected values. When check function is called, the check reads the register values in DUT and compares with the expected value in shadow registers.
Check task compares the DUT and shadow registers. Care should be taken while using back door access, as they are not cycle accurate. Config registers are compared for what is configured and what is in the register. Interrupt and status registers are compared with what is in DUT with the expected values.
Each register in test bench should maintain the permissions. This permissions are used in write, read, check methods.
Fallowing are possible types of permissions:
read only, write can be by the design
clear on read
automatically set to 1 by design.
Automatically set to 0 by design.
Readable and settable by writing 1
Readable and clearable by writing 1
By default the type of permission is read/write. If you are using any scripts, if you don't mention any permission, then it should be considered as read/write.