Chapter 2 – Defining the verification environment

Beforeunderstanding UVM, we need to understand verification.

Right now, wehave a DUT and we will have to interact with it in order to test itsfunctionality, so we need to stimulate it. To achieve this, we will need ablock that generates sequences of bits to be transmitted to the DUT, this blockis going to be named sequencer.

Usuallysequencers are unaware of the communication bus, they are responsible forgenerating generic sequences of data and they pass that data to another blockthat takes care of the communication with the DUT. This block will be the driver.

While the drivermaintains activity with the DUT by feeding it data generated from thesequencers, it doesn’t do any validation of the responses to the stimuli. Weneed another block that listens to the communication between the driver and theDUT and evaluates the responses from the DUT. This block is the monitor.

Monitors samplethe inputs and the outputs of the DUT, they try to make a prediction of theexpected result and send the prediction and result of the DUT to another block,the scoreboard, in order to be compared and evaluated.

All these blocksconstitute a typical system used for verification and it’s the same structureused for UVM testbenches.

You can find arepresentation of a similar environment in Figure 2.1.



Figure 2.1: TypicalUVM testbench

Usually,sequencers, drivers and monitors compose an agent. An agent and ascoreboard compose an environment. All these blocks are controlledby a greater block denominated of test. The test blockcontrols all the blocks and sub blocks of the testbench. This means that justby changing a few lines of code, we could add, removeand override blocks in our testbench and build different environments withoutrewriting the whole test.

To illustratethe advantage of this feature, let’s imagine a situation where we are testing aanother DUT that uses SPI for communication. If, by any chance, we want to testa similar DUT but with I2C instead, we would just need to add a monitor and adriver for I2C and override the existing SPI blocks, the sequencer and thescoreboard could reused just fine.

 

UVM Classes

The previousexample demonstrates one of the great advantages of UVM. It’s very easy toreplace components without having to modify the entire testbench, but it’s alsodue to the concept of classes and objects from SystemVerilog.

In UVM, all thementioned blocks are represented as objects that are derived from the alreadyexistent classes.

A class tree ofthe most important UVM classes can be seen in Figure 2.2.


Figure 2.2: PartialUVM class tree

The data thattravels to and from our DUT will stored in a class derived either from uvm_sequence_item or uvm_sequence.The sequencer will be derived from uvm_sequencer, the driverfrom uvm_driver, and so on.

Every each ofthese classes already have some useful methods implemented, so that thedesigner can only focus on the important part, which is the functional part ofthe class that will verify the design. These methods are going to addressedfurther ahead.

For moreinformation about UVM classes, you can consult the document Accellera’sUVM 1.1 Class Reference.

 

UVM Phases

All theseclasses have simulation phases. Phases are ordered steps of executionimplemented as methods. When we derive a new class, the simulation of ourtestbench will go through these different steps in order to construct,configure and connect the testbench component hierarchy.

The mostimportant phases are represented in Figure 2.3.



Figure 2.3: Partiallist of UVM phases

A briefexplanation of each phase will follow:

  • The build phase is used to construct components of the hierarchy. For example, the build phase of the agent class will construct the classes for the monitor, for the sequencer and for the driver.
  • The connect is used to connect the different sub components of a class. Using the same example, the connect phase of the agent would connect the driver to the sequencer and it would connect the monitor to an external port.
  • The run phase is the main phase of the execution, this is where the actual code of a simulation will execute.
  • And at last, the report phase is the phase used to display the results of the simulation.

There are manymore phases but none of them are mandatory. If we don’t need to have one in aparticular class, we can just omit it and UVM will ignore it.

More informationabout UVM phasing can be consulted in Verification Academy’s UVM Cookbook, page48.

 

UVM Macros

Anotherimportant aspect of UVM are the macros. These macros implement some usefulmethods in classes and in variables. they are optional, but recommended.

The most commonones are:

  • `uvm_component_utils – This macro registers the new class type. It’s usually used when deriving new classes like a new agent, driver, monitor and so on.
  • `uvm_field_int – This macro registers a variable in the UVM factory and implements some functions like copy(), compare() and print().
  • `uvm_info – This a very useful macro to print messages from the UVM environment during simulation time.

This guide willnot go into much detail about macros, their usage is always the same for everyclass, so it’s not worth to put much thought into it for now.

More informationcan be found in Accellera’s UVM 1.1 Class Reference, page 405.

 

Typical UVMclass

All this said, atypical UVM class will look a lot like the one described in Code 2.1.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

      class generic_component extends uvm_component;

     `uvm_component_utils(generic_component)

 

     function new(string name, uvm_component parent);

          super.new(name, parent);

     endfunction: new

 

     function void build_phase(uvm_phase phase);

          super.build_phase(phase);

 

          //Code for constructors goes here

     end_function: build_phase

 

     function void connect_phase(uvm_phase phase);

          super.connect_phase(phase);

 

          //Code for connecting components goes here

     endfunction: connect_phase

 

     task run_phase(uvm_phase phase);

          //Code for simulation goes here

     endtask: run_phase

 

     function void report_phase(uvm_phase phase);

          //Code for showing simulation results goes here

     endfunction: report_phase

endclass: generic_component

Code 2.1: Code for ageneric component

The code listedhere, is the most basic sample that all components will share as you will seefrom now on.

 

SimpleAdder UVMTestbench

After a briefoverview of a UVM testbench, it’s time to start developing one. By the end ofthis guide, we will have the verification environment from the Figure 2.4.

Figure 2.4: SimpleAdder Final Testbench

This guide willbegin to approach the top block and the interface (chapter 3), then it will explain what data willbe generated with the sequences and sequencers on chapter 4.

Following thesequencers, it will explain how to drive the signals into the DUT and how toobserve the response in chapters 5 and 6 respectively.

Subsequently, itwill explain how to connect the sequencer to the driver and the monitor to thescoreboard in chapter 7. Then it will show to build asimple scoreboard in chapter 8.

And finally, thetest will be executed and analyzed.

The testbenchcan be run with the execution of a Makefile provided in the repository. As I mentioned previously, thisMakefile uses Synopsys VCS but it should be easily modifiable to be executedwith any HDL simulator.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值