Assembly/C test cases are written to access all subcomponents and their registers like timer, SPI, I2C.
In directed verification, assembly/C test cases are written to access all subcomponents and their registers like timer, SPI, I2C.
In the test cases, L1 and L2 cache can be enabled to verify if data is coming out of cores. In a V8 architecture, like that of A53, data may not come out of bus interface if shared memory, which is also cacheable, is accessed. Similarly, when data is read from shareable memory, data would be read from the L1/L2 cache.
If the L2 memory is not a third-party IP, then you can write test cases that help in verifying integration of L1 and L2 with the core. Other tests that you can try in directed testing include Wifi and interrupts.
An important point to note white writing a directed test case is that you should make sure the RTL code (for code coverage and conditional coverage) is accessed as much as possible. Therefore, directed test cases have to be detailed and elaborate.
For instance, writing a 1-0-1 pattern to all the bits in register would help in increasing toggle coverage. It also helps in verifying the register block (the register block can be verified using the register read/write test case).
Status registers can be verified either by functionality, creating a scenario to toggle to 1, and again clearing the bits by performing the operation as mentioned in the spec. The other method of testing would be to forcibly drive those status bits to toggle using Verilog/System Verilog.
Here's a table that would help in mapping instructions with ACE lite/AXI3/AXI4 interface signal on A53 bus interface (click here to download the table in PDF). If you follow the description in the table, all the signals would be toggled. I have provided example code in some cases.
In a multicore environment, data access with respect to shared memory (shared among all cores) is very important as it tests the functionality of L1 and L2 caches.
You can use Verilog/System Verilog for verifying a few tests. Some of them are mentioned below.
Assertions can also be used( as this paper tries to explain in simple terms, verilog is taken as reference)
These can be verified using either Assembly/C or Verilog or, in some cases, a combination of both.
a. C and Verilog
Let us consider usage of Verilog and Assembly in a simple example. A directed test case can be written where the processor executes a code and after a finite time (you can make processor execute code in a loop), you can drive reset to the core using test bench. After resets are de-asserted, the core again needs to branch to reset vector and again execute the code.
You can observe this using waveforms or logs. The same can be applied to other blocks, like caches and register block (values are set to default values). This is to make sure that resets are applied properly and functionality meets the requirements. Driving resets is done through the Verilog/System Verilog test bench.
For verification, we need to ensure that reset signals are toggled only with respect to their clock domain.
*__Figure 3:__ Reset assertion and de-assertion should be with respect to these clock domains.*
There are different clock domains CPU_CLKIN, SOC_CLKIN, SOC_CLKIN/4, SOC_CLKIN/2. Reset assertion and de-assertion should be with respect to these clock domains. You can write a simple Verilog file to check the working of resets.
Verification of connectivity is important for checking the point-to-point connections. This makes sure that all your signals are connected and it helps in toggle coverage and identifies unconnected ports. A script can be used to verify the connection between points.
Clock frequency, clock enable
This verification is related to clock frequency where we are trying to verify that all clocks that are generated meet the expected clock frequency. The clock frequency of all clock domains is verified using Verilog/System Verilog.
You can use a simple Verilog file to verify if the hardware blocks are tied-off. Tie-off check is done to make sure that unused signals and signals that are required to have constant value are tied to appropriate value. For example, if one of the unused interrupts is not tied to correct value, it would result in an unwanted interrupt when interrupts are enabled in boot code.