Bus Functional Models (System Verilog) - system-verilog

I'm looking to design a bus functional model for SPI and UART bus. First, I want to understand if my perception of a bus functional model is correct.
It is supposed to simulate bus transactions, without worrying about the underlying implementation specifics.
For instance,
If I were to build a BFM for an SPI bus, the design should be able to simulate transactions on the SPI acting as a master based on some protocol for example reading instructions from a file and then showing them on a simulator accordingly,
For example a generic data transfer instruction, like send_write(0x0c, 0x0f), that sends data byte 0c to the slave address 0f, should drive the Chip Select line low and send the data bits accordingly on the clock edge based on the SPI mode, is my understanding of BFM correct in this case?
Now what I don't understand this is, how is it helpful?
Where in between the DUT and the TestBench does a BFM sit, and how does it help a system designer.
I also want to know if there are any reference BFMs that have been built and tested that are available to study,
I'd appreciate if someone could help me with an example, preferably in System Verilog.

So had to research a lot on this so I thought I would answer, but here's an idea of what it is,
Think of a Bus Functional Model(BFM) that simulates transactions of a bus, like READ and WRITE, reducing the overhead of a testbench of taking care of the timing analysis for the same. There are a lot more interpretations of a BFM, BFMs typically reduce the job of a testbench by making it more data focused.
Okay that was a high-level answer, let's dig a little deeper,
Think of BFM as a block that sits within the testbench block as a whole, when the test bench needs to perform a task, for instance, wants to write at a particular address, it asks the BFM to write at that address, the BFM, which is a black box to the test-bench does the transaction whilst taking care of the timing. It can be driven by a file that could be loaded by the test-bench or it could be a bunch of tasks that the test-bench uses to do the transactions.
The Design Under Test's(DUTs) response to the BFM transacts is of interest to the tester for the design. One may argue that the BFM may change based on DUT, which is what distinguishes a better BFM per say.
If the BFM could have a configuration vector that could be loaded to initialize and behave according to the DUT specifications, then it becomes portable to helping test other designs.
Further the BFM, may be defined as abstract virtual functions(in SV), that could have further concrete implementations based on the DUT.
virtual class apb_bfm;
pure virtual task writeData(int unsigned addr, int unsigned data);
pure virtual task readData (int unsigned addr, output int unsigned data);
pure virtual task initializeSignals();
endclass
The above BFM abstraction is for the APB Master, that does the tasks mentioned, the low level details of each of these must be encapsulated by interfaces and clocking blocks in order to have sanity of the clocks as well as abstract interface types. I have referenced a book in the section, which describes beautifully how to architect test benches and design Transaction Level Models(TLMs). Reading this will give you a good understanding of how to design one.
Also this paper on abstract BFMs gives a good idea on how BFMs should be modeled for a good design. The APB example is derived off that.
The following image on how a BFM could be placed in the test framework was what I could gather from Bergeron's book.
Hopefully that gives a basic understanding of what BFMs are. Of course writing one and getting it to work is difficult but this basic knowledge would allow you to have a high level picture of it.
Book Reference:
Bergeron, J. (n.d.). Writing TestBenches in System Verilog. Springer.

A BFM is a VIP with dual roles. It can act as a Driver or a Monitor/Receiver. In a Driver role, it packs the transactions and makes it drive on a signal level using the interface handle, else the DUT is unable to accept the transactions (it only has signal interface). As a receiver, it unpacks the signal bits coming through the interface handle, to transactions and sends it to Scoreboard/Checker. It can also act as a Protocol Checker in some cases.
You can get a good example of BFM usage here
http://www.testbench.in/SL_00_INDEX.html

Related

What is the purpose of a driver in UVM?

Since the generator generates test stimuli for the DUT (Design Under Test), why not feed them directly? What is the need for a driver? Please enlighten me with an example if possible.
UVM is based on transaction-level modeling (TLM). This means that you can model things like memory reads and writes at a high level of abstraction using a transaction object. For example, a memory transaction can be represented by:
Data value
Address
Direction (read or write)
In UVM, we typically create a uvm_agent which consists of a sequencer, a driver and a monitor. The sequencer plays the role of the transaction generator. You will also create a sequence which is attached to the sequencer to generate several transactions. Each transaction object is sent from the sequencer to the driver.
When the driver receives a transaction object, it looks at the object properties and assigns the transaction values to the interface signals. In the testbench, the interface signals are connected directly to the DUT ports.
The driver contains more details than the sequencer or transaction. It controls the timing of the signals, adding delays, wait-states, etc.
See also chapter 1 of the UVM User's Guide
The UVM was developed using the Separation of Concerns principle in software programming. In Object Oriented Programming, this usually means giving a class one basic responsibility and passing data on to another class for another responsibility.
The UVM separates the job of generating stimulus from driving the signals into the DUT to enable re-use at different stages of abstraction because of different levels of unit testing. In the UVM, you will see that even the passing of data is abstracted into a separate set of classes called TLM ports and exports.
An example might be a design that processes an encrypted image received through a serial port. Your design will probably have stages the deserialized the serial input, decrypted the input, and finally stores an image in memory. Depending on which stage you are testing, you would want to use the same image generator and send the image through a sequence, and have layered sets of sequences to translate to the particular stage you are testing.

What is the purpose of register model in UVM?

In UVM, the testbench does not have any visibility into the internal registers of the DUT. Then why is there mirroring and creation of Register models in the UVM testbench architecture? What purpose does it serve?
The testbench would not come to know if any status bit etc is ever updated or not inside DUT since it only has access to its input output ports.
The DUT may not have direct access internal registers via ports, but some registers are accessible via an interface protocol. The register model is primarily intended for these registers. But you can access any register in the design via the backdoor (but not always desirable as it requires more work to setup and maintain).
The mirror stores the value of what the test-bench thinks are the register values of the DUT. When you do a .mirror(), the register model compares the register value (actual) verses the mirror (expected).
Status bits are often complicated to predict. To simplify things you can turn off the compare of the field (or register) with .set_compare(UVM_NO_CHECK). If you disable the check at the field level, other fields in the same register will still be compared.
If your ambiances and want to do more complex predictions/mirror-compare on status bits, then you do have the options, such as register callbacks or of extending the uvm_reg and uvm_reg_field classes to overwrite the .predict and .mirror methods.
UVM RAL provides several benefits
It provides high-level abstraction for reading and writing registers in your design. This is especially useful when the RTL for your registers has been compiled from another description. All of the addresses and bit fields can get replaced with human readable names.
Your test can be written independent of the physical bus interface. Just call the read/write methods.
The mirrored registers make it easy to know the state/configuration of your DUT without having to add your own set of mirrored variables, or perform extra read operations.
Register model is an entity that represents the hierarchical data structure of the class object for every register and its individual field. A register model (or register abstraction layer) could be a set of classes that model the memory mapped behavior of registers and memories within the DUT so as to facilitate stimulus generation. we can perform read and write operation on design employing a RAL model. It goes to mirror the design registers by making a model within the verification surroundings. By applying the stimulus to the register model, the actual design registers can exhibit the changes applied by the stimulus.
The advantage of the RAL model comes from the high level of abstraction provided. It provides back door access for registers and memory with easy integration liability in UVM verification environment. Whenever a read or write operation is performed, the RAL Model will be automatically updated. It supports design with multiple physical interfaces.
For more information, use this link.
Thanks,
Mayank

Is there any standard for supporting Lock-step processor?

I want to ask about supporting Lock-step(lockstep, lock-step) processors in SW-level.
As I know, in AUTOSAR-ASILD, Lock-step processor is used for fault torelant system as below scenario.
The input signals for a processor is copied to another processor(its Lock-step pair).
The output signals from two different processors are compared.
If two output signals are different, trap is generated.
I think that if there is generated trap, then this generated trap should be processed somewhere in SW-level.
However, I could not find any standard for this processing.
I have read some error handling in SW topics specified in AUTOSAR, but I could not find any satisfying answers.
So, my question is summarized as below.
In AUTOSAR or other standard, where is the right place that processes Lock-step trap(SW-C or RTE or BSW)?.
In AUTOSAR or other standard, what is the right action that processes Lock-step trap(RESET or ABORT)?
Thank you.
There are multiple concepts involved here, from different sources.
The ASIL levels are defined by ISO 26262. ASIL-D is the highest level and using a lockstep CPU is one of the methods typically used to achieve ASIL-D compliance for the whole system. Autosar doesn't define how you achieve ASIL-D, or any ASIL level at all. From an Autosar perspective, lockstep would be an implementation detail of the MCU driver, and Autosar doesn't require MCUs to support lockstep. How a particular lockstep implementation works (whether the outputs are compared after each instruction or not, etc.) depends on the hardware, so you can find those answers in the corresponding hardware manual.
Correspondingly, some decisions have to be made by people working on the system, including an expert on functional safety. The decision on what to do on lockstep failure is one such decision - how you react to a lockstep trap should be defined at the system level. This is also not defined by Autosar, although the most reasonable option is to reset your microcontroller after saving some information about the error.
As for where in the Autosar stack the trap should be handled, this is also an implementation decision, although the reasonable choice is for this to happen at the MCAL level - to the extent that talking about levels even makes sense here, as the trap will run in interrupt/trap context and not the normal OS task context. Typically, a trap would come with a higher priority than any interrupt, and also typically it's not possible to disable the traps in software. A trap will be handled by some routine that is registered by the OS in the same way it registers ISRs, so you'd want to configure the trap handler in whatever tool you're using for OS configuration. The lockstep trap may (again, depending on the hardware) be considered a non-recoverable trap, meaning that the trap handler should trigger a reset eventually. Calling the standard ShutdownOS() function may be reasonable.

How to update regmodel with writes going from RTL blocks

I understand that regmodel values are updated as soon as transaction initiates from test environment on any of the connected interfaces.
However consider a scenario:
RTL registers being updated from ROM on boot-up (different value than default)
Processor in RTL writing to register as compared to test environment.
In these 2 cases regmodel doesn't get updated/mirrored with correct RTL value. I would like to know what is correct procedure to get regmodel updated, if there is none at the moment what other approach can be taken to keep these 2 in sync?
For the first case you have to pre-load your memory model with your ROM contents at the start of the simulation. There isn't any infrastructure to do this in uvm_memory (unfortunately), so you'll have to implement it yourself.
For the second case, you have to use a more grey-box approach to verification. You have to monitor the bus accesses that the processor does to the peripherals and update the register values based on those transactions. This should be OK to do from a maintainability point of view, because the architecture of your SoC should be pretty stable in that sense (you've already decided to use a processor so that will always be there, but you might not know which peripherals will make it to the end).

Can 'mov' instructions, which do not require any offset/displacement added to it, be executed without any assistance of ALU?

I've recently started exploring the field of computer architecture. While studying the instruction set architecture, I came across 'mov' instruction which copies data from one location to another. I understand that some type of mov' instructions are conditional while some need to have offset or displacement added to it to find a particular address, and hence they need ALU assistance. For e.g. Base-plus-index, Register relative, Base relative-plus-index, Scaled index etc.
I was wondering, if it is possible to bypass ALU for those mov' instructions (for e.g. register to register data transfer) who do not require any ALU assistance.
Yes. Obviously, an instruction that doesn't require any arithmetic to be performed doesn't require the assistance of the ALU.
Obviously, though, it still requires the "intervention of microprocessor"; the registers, program counter, instruction fetch/decode/execute pipeline are all part of the CPU.