Testbench debug logging tips
Testbench logging is front end of the debug. These logging guidelines are designed to help make debug effective, not only for selected geniuses in team…
Testbench logging is front end of the debug. These logging guidelines are designed to help make debug effective, not only for selected geniuses in team but also for everyone. Debug activity affects entire team and carried out throughout product’s life cycle. Logging is one of the very important contributors in making debug efficient and simple.
Some of the following guidelines for easing the debug may require additional code implementation beyond normal testbench or test functionality. But this additional effort pays off by saving the valuable engineer’s time during debug throughout product’s life cycle. Let machine’s do bit extra work to reduce the human effort. What do you say?
Testbench data to be logged is primarily made up of state, events, transactions, configurations and execution flow to help understand stimulus generation and checking.
Configurations in the constrained random environment are randomized at the start of the test. Multiple randomized transactions are generated during the course of execution of the test based on configuration and state. Stimulus from generators and response from DUT or reactive response from testbench flows through various verification components.
Logging specification related messages
- Don’t invent new terminologies for already defined standard terms
- Use the same standard terms in the logging. This helps any one with the understanding of the standard specification to understand the logging
- For example, in USB if you are writing test bench make sure the application level stimulus logged has term “TRANSFER” in it
- For transaction fields logging pay attention to make it readable. Do not print the packed hex bytes of transaction or packed instructions of processor in hex format. Although if required packed hex bytes can be logged separately as some times its useful but the default logging print them as different “field:value” format. This saves manual effort of decoding and reading the content
- By default do not log the data contents of the transaction. In a constrained random environment the data is randomized and it may not have much meaning for many debugs. However provide a switch to enable the data logging.
- When data logging is required for example debugging scoreboard failure, data logging switch can be enabled to obtain the data byte information. This method also helps save on the size of log files and test simulation time. More than that reduces clutter in the log files
- If the data generated as stimulus is transformed either by encoding or scrambling, print the original data bytes along with transformed data. It makes it easy to relate the data in the symbol form to actual data
- While logging data in hex format at lower abstractions don’t just log the hex numbers but also the corresponding logical significance and any additional context that can help it understand better. For example in communication interface link layer logging
- If the hex symbol is a special control symbol such SOP (Start of packet), EOP(end of packet), ESC (escape symbol) etc. log them explicitly
- Broad category to which hex data belongs
- Initialization related. If its initialization consider logging the state of initialization state machine
- Data frame related
- Control frame related
Ease the frequent tracing
- If the stimulus or response goes through multiple layers of transformations, make it easy to trace it across the layers by making it easy to correlate same information across multiple layers of abstractions
- For example USBx application stimulus generated as TRANSFER, it should be possible to correlate it to the multiple protocol layer TRANSACTIONs resulting from single application level TRANSFER. Packets of the transactions should be correlated to transaction and transfer. Symbols resulting from packet should be able to correlate to packet, transaction and transfer and so on
Error injection logging
- Error injection verification is one of the tricky areas of the verification. All the preparation that we can put in to ease it should be done. Logging is no exception
- Very clearly log what is being corrupted, corrupted information before corruption and after corruption. Often one requires visualization of how corrupted information would have looked without corruption.
- For example in communication protocol verification if you are corrupting the transaction,
- First log the transaction being printed is corrupted
- Second log if it’s field corruption or sequence corruption
- If its field corruption log the corrupted and uncorrupted values of the field
- If its sequence corruption, log the transaction type with and without corruption, if corrupted transaction is addition, deletion or duplication log it explicitly
- Tag the messages relating to error recovery explicitly. For example in communication interface the data frame transmitted first time and retransmitted as part of recovery may not look really different. If there is data frames being retransmitted as part of recovery tag them as retransmitted to make it easier to distinguish
State machine logging
- For FSMs first log basics adhering to FSM fundamentals. Log current state, event triggering state transition, next state and hints about the output actions such as any timers started and stopped, packets sent or expected etc.
- Tag all logging from FSM with corresponding FSM name and instance number so that it’s easy to filter all the related messages out. For example there might be multiple input events taking place simultaneously and FSM might be doing prioritized list selection. Logging multiple input triggering events with the FSM name makes it easy to understand why the FSM selected the current trigger for processing
Reactive verification component logging
- Reactive verification components wait for event from DUT, such as interrupt and then do the processing of the events
- Log the waiting, event detected and hints about processing done
Register read and writes
- Register read and writes information plays important role in debug
- Make it easy to filter out the register access related transactions
- Log additional information about the component and context as to why the register access is initiated. Like initialization, control event programming, clearing interrupts, reading status, polling etc.
Testbench debug
Logging for debugging the testbench components needs to take following in to consideration. If the following information is not sufficient then it’s always better to get in to doing the interactive debug with the help of breakpoint, watch windows and single stepping. Logging following can help provide insights in to where to put the breakpoints and what to watch
- Communication among blocks: Log the communication between the blocks. It helps to identify how far the transactions or events have traveled and which block is suspected for having issues
- Threads: Blocks containing threads, log the thread state especially when it’s waiting for something. Race among threads is a common problem. It’s difficult to visualize the time axis and concurrency. Some thread that was thought to be active could have been terminated or not started yet. It might be good idea to indicate when thread has started and stopped. Zero time context switch among threads can be another dangerous problem that can break all assumptions about execution flow
- Internal state machines: Log the internal state machines similar to external state machine described above
- Entry & exit: In some cases it might be good idea to log the entry and exit from tasks or function. It can provide a very detailed execution trace. Allow control on this logging with the separate switch otherwise it might be too much of information. This is helpful where remote debugs have to be done without access to the interactive debug sessions.