|
||||||||||
Transactions in an OVM SystemVerilog Verification EnvironmentBy Rich Edelman, Mentor Graphics Modeling a verification environment with transactions encompasses many areas, including test bench design and debug, golden model comparison, functional verification between abstraction levels and overall system operation. This paper will discuss certain techniques for modeling with transactions in each of these different abstraction levels and how to effectively combine them using the OVM [1] and SystemVerilog [6]. Introduction Transactions have been used in verification environments for many years [7][3]. A transaction can represent a bus transaction or a packet transaction or an entire test. Using transactions meant that you needed to consider many aspects of the transaction. Among the considerations – what is being modeled, when is it valid – when does it begin and end, what is contained in the transaction and how this transaction is related to other transactions. With the release of the SystemVerilog OVM, generating transactions has become quite easy – with certain abstractions in the test environment automatically mapped to transaction attribute like “begin” and “end”. The OVM SystemVerilog class library contains an ovm_transaction base class and an ovm_sequence_item base class. (Figure 1) An ovm_sequence usually generates ovm_sequence_items and then “puts” them to an ovm_sequencer/ovm_driver pair. (Figure 3) In addition, there is another fundamental transaction in the OVM – it is the “recorded transaction” – or the transaction that is recorded into a database.
A recorded transaction has a beginning time and an ending time. A recorded transaction also has attributes – (name, value) pairs – attached to it. Two recorded transactions can have a relationship – like parent/child or predecessor/successor. A recorded transaction can begin or end in the past. It cannot begin or end in the future. A stream can be thought of as a drawn row on a waveform window, or as a finite state machine controlling an interface [10]. A stream is a way to organize transactions – for drawing, analysis or recording convenience. A recorded transaction and an ovm_transaction are related to each other. The recorded transaction is the “occurrence” of the ovm_transaction, recorded on a stream. The ovm_transaction contains a handle, tr_handle, which is the handle to the recorded transaction. This is an important link between the ovm_transaction during simulation, and the recorded transaction, recorded on the stream. In the OVM, a transaction can be recorded “on the ovm_component” or “by the ovm_transaction”. A transaction recorded on the ovm_component is a transaction which passes through, or executes on a component. For example, a driver might execute a transaction, and record it. A transaction recorded by the ovm_transaction Kinds of transactions There are many kinds of transactions, four of which are outlined below. An abstract transaction is just that – an arbitrary collection of communication or computation that is grouped together. A bus can have transactions – either protocol specific, or generic. A communication fabric can have transactions – like “transfer item A from Initiator 1 to Target 3”. There are many other kinds of transactions, which may be modeled, simulated, recorded and debugged similarly. Abstract Transactions Transactions are usually thought of as communication or computation – Merriam-Webster [4] 2.b. says “b: a communicative action or activity involving two parties or things that reciprocally affect or influence each other”. As an abstraction, transactions are very useful, since they allow higher level abstractions, and provide a vehicle for more abstraction reasoning about the behavior of the system. Studies have been done showing that at a constant productivity rate; a human can “do” N things in a day. The N things should represent as much communication or computation as possible, in order to achieve maximum productivity. “Send a network packet from A to B” is a good example of an abstract transaction. “Run the test named read_all_registers” is another. An abstract transaction usually starts other lower-level transactions that perform work. Those lower level transactions in turn create transactions, etc, until there is some transaction which performs communication or computation. Once all the lower level transactions complete, we might reason about the state of the system, and the length of time that was required by the transaction. Bus Independent Transactions Bus independent transactions are abstract transactions – just a lower level transaction – WRITE(addr, data) or READ(addr, data). Bus independent transactions are used to specify communication without regard to the underlying bus implementation or protocol. Whether the bus implements a burst protocol or allows out-of-order transactions is not important at this level. Tests can be written at this level and re-used across various bus implementations. Bus Dependent Transactions A bus dependent transaction is tied explicitly to an underlying bus implementation and specification. Two different bus implementations will have different bus dependent transactions. A bus dependent transaction represents the physical data transfer of information across a bus – it understands how to issue a WRITE on an AHB bus, for example. Transfer Transactions Transfer transactions are not thought of as bus transactions, but rather simply specify that some data is being transferred from point A to point B. For example, network or switches might have transactions written for them to move data across them. A transfer might move data from port 1 to port 4 on the switch. Design Structures One of the most common and direct applications of transaction modeling is to model communication on design structures such as busses or interfaces. Each bus or interface is modeled as a stream, with activity on the bus represented as transaction activity. SystemVerilog Interface
bit[31:0] data_i; bit[31:0] data_o; bit[31:0] addr; task read( tr = ovm_begin_transaction(“-”,s, “READ”); addr = l_addr; $add_attribute(tr, l_data, "my_data"); rwenable = 0; task write( ovm_end_transaction(tr); rwenable = 0;
Many previous examples (including [5] and [2]) have been created showing how assertions can be used to recognize a transaction on a bus or collection of pins, then form an ovm_transaction derived class. The ovm_transaction derivative is then entered into the class based testbench. For example, an assertion could be used in the DUT or the interface in Figure 3 (#5 or #6). Once the assertion recognizes the transaction, an analysis could be written using an analysis port or other TLM connection. Transactions in Testbench Structures Figure 3 is a canonical diagram representing some hypothetical testbench. It is used here to demonstrate the many places that transactions might occur. tlm_fifo A tlm_fifo is a basic building block of transaction level tests and test benches. While it is possible to record transactions in tlm_fifos – for example starting the recording when the transaction enters the fifo, and ending the recording when it exits the fifo – this is a transaction about waiting. While a transaction is in a fifo, it is usually not causing anything to happen – it is waiting. When a transaction is retrieved from a fifo, then it is usually operated on, or causes some action – like pin wiggles in a driver. Measuring waiting can be useful, but can be achieved more easily using the “accept time”. When a transaction is “received” the accept time can be set. When a transaction causes some action, the begin time can be set. The difference between accept time and begin time is the time that the transaction was available to cause work, but did not – it was waiting. Figure 3 - Canonical Testbench A driver can be annotated to record transactions it drives or receives (Figure 3 #4). class my_driver function new(string name, ovm_component p); task run(); OVM Sequences The sequences in this example generate ‘simple_items’. A simple_item is just a transaction containing an address and data field, which will be randomized by the calling sequences. class simple_item extends ovm_sequence_item; rand int unsigned addr; `ovm_object_utils_begin(simple_item) virtual task body(); The ‘simple_seq_do’ sequence is a simple sequence which generates four items. Each item is the same type – a simple_item. class simple_seq_do The ‘simple_seq_do_with’ sequence is similar to a simple_seq_do, but adds inline constraints. The inline constraints are used to refine the items values for randomization. Three items are generated. class simple_seq_do_with simple_item item; virtual task body(); The ‘simple_seq_do_with_vars’ sequence is similar to a simple_seq_do_with, but now the inline constraints are constrained against a variable, not a constant. Four items are generated. class simple_seq_do_with_vars simple_item item; virtual task body(); The ‘simple_seq_sub_seqs’ sequence is different than the three preceding. It is actually a “virtual sequence”, or perhaps a test (Figure 3 #1 or #2) – producing no transactions directly, but instead calling three lower level sequences to generate transactions. The sequences “seq_do”, “seq_do_with” and “seq_do_with_vars” are called in turn. This loop is repeated 100 times. class simple_seq_sub_seqs OVM Registers In register testing, an address map independent transaction is generated – WRITE(”regA”, 42). This transaction causes an address lookup sometime later, which creates an address specific transaction –WRITE(0x1000, 42). That bus transaction is accepted by a driver, and turned into a bus transaction on the pins of the bus. The driver understands how to convert WRITE(0x1000, 42) into an AHB or AXI transaction. Comparing transactions Transactions are easily compared in the OVM using the built-in classes like in-order-comparator and algorithmic-comparator or a custom designed comparator in a scoreboard. Relations Any large system is likely to have most if not all of these kinds of transactions and have relationships between them. In order to build the relationships, the transactions and the environment must be designed with this in mind. When a transaction is started, its parent may wish to be registered as the parent. When a transaction finishes it may have a reference saved, so that the next transaction can be created with a successor/predecessor relationship. With the OVM, some of these relationships can be created automatically. For example, a sequence may be the parent of a sequence_item that it starts. A driver may be the predecessor of all the traffic generated on a bus. As a general purpose solution to finding parents or children, a string lookup table can be created. This lookup table can find parents or children (or any relation), given the proper key. This infrastructure does not yet exist in the OVM, but has been used by individual testbench architects. Conclusions SystemVerilog provides the facilities for transaction modeling and test bench construction using object-oriented techniques, which improve maintenance and productivity. The OVM Class Library further enhances this productivity by providing a collection of base classes which provide necessary structure and functionality, like drivers, scoreboards, sequences, configuration, fifos Using SystemVerilog and the OVM allows for the easy generation of transactions for use in debug and analysis. The canonical testbench can be instrumented with transactions in a variety of ways, suitable to the need. Additionally the OVM provides ways to automatically record many of these transactions into a debug database. The current API for recording is historical, and will change once a common use-model is proposed, negotiated and accepted. One of the easiest areas to clarify is the recording of transaction attributes. Currently the only data type recorded is a 1024 bit vector – that can easily be fixed with the current $add_attribute(). Another approach is to provide a more transparent layering for the existing PLI – effectively promoting the PLI API into the SystemVerilog OVM base class api. The SystemVerilog OVM combines object oriented techniques with a powerful base class library and automated or customized transaction recording providing a powerful mechanism for transaction modeling, debug and analysis in tests and testbenches. [2] Mark Glasser, Adam Rose, Tom Fitzpatrick, Dave Rich, Harry Foster, “The Verification Cookbook”, [3] Frank Ghenassia (editor), “Transaction-level Modeling with SystemC: TLM Concepts and Applications for Embedded Systems”, Springer, 2005. [4] Merriam Webster [5] Verification Horizons, Q3’06-Vol.2, #3, p 17. [6] SystemVerilog LRM. IEEE 1800-2005. [8] Draft Standard for Verilog Transaction Recording [9] Rich Edelman, IPSOC 2005, “A SystemVerilog DPI Framework for reusable transaction level testing, debug and analysis of SOC designs”. [10] Rich Edelman, Mark Glasser, Bill Cox, IPSOC2004, “Debugging SOC Designs with Transactions”. Appendix function TRH ovm_create_fiber ( function void ovm_set_attribute_by_name ( function TRH ovm_begin_transaction( function void ovm_end_transaction ( function void ovm_link_transaction( function void ovm_free_transaction_handle(
|
Home | Feedback | Register | Site Map |
All material on this site Copyright © 2017 Design And Reuse S.A. All rights reserved. |