OVM wrapper for Verilog Bfms?

Hi Dave,
I do have a clarification with your example.
We can’t create an object of an abstract base class.
Hence how can I get an object of the abstract base class defined in the package?

That is correct, you can’t construct an object of an abstract base class. But you can extend an abstract class and construct that class, and assign that object to a handle of an abstract class.

Hi Anantv, Dave_59,

There is another method being discussed for module based bfms (not AVM) that may be useful for Anant to look at. [HTML]http://www.ovmworld.org/forums/showthread.php?t=100
[/HTML]

Umer

Hi Dave,

Thanks for the detailed example, which helped me to understand the approach clearly.

Hi Umery,

Thanks for referring to the thread:
http://ovmworld.org/forums/showthread.php?t=109

This gives another approach for the same.

Thanks to all.

Hello,

I have been looking through the methodologies. How do I handle Multiple Instance of
UART.

UART_TX U_tx0(line); UART_TX U_tx1(line);

Now Since their instance path have to hard coded in the concrete bfm class, one might
need that many class definitions…

class U_tx_c0 extends uart_pkg::uart_api_c;
class U_tx_c1 extends uart_pkg::uart_api_c;

In this example the number of tasks in the BFM is small. I am using BFMs that have
a large number of tasks. Whats the solution ?

(
It would be nice if Verilog permitted array like module instance… then I can pass the
index of the instance to the constructor of the concrete bfm class.

UART_TX U_tx0; UART_TX U_tx1;
)

Whats the proposed solution ?

Thanks,
Kiran

I’ve updated the example to use some more recently developed techniques. This example uses bindand the factory to create the objects

Dave

Thanks for sending out this example…

Never come across the BIND construct so far…

bind UART_TX : top.BLOCK[i].U_tx UART_TX_probe p();

Whats the Implication of “UART_TX :” following the bind command ? I could not find this
syntax in the LRM.

Also, when put in a for look, the module UART_TX_probe gets instance name p() ? Can you explain the mechanism behind this ? What does the run time environment do ? Make N
instances of UART_TX_probe ?

Thanks… I did some experiments and figured… the answers:

so its going to be top.BLOCK[i].U_tx.p

Also whats the standard for the

bind : instance const bind_inst ??
OR
bind inst const bind_inst

LRM says:
bind_directive ::= bind hierarchical_identifier constant_select bind_instantiation ;
bind_instantiation ::=
program_instantiation
| module_instantiation
| interface_instantiation

You must be looking at an old LRM. 1800-2009 says

bind_directive ::= 
     bind bind_target_scope [: bind_target_instance_list] bind_instantiation ; 
     | bind bind_target_instance bind_instantiation ;

You have to use the first option if you have a list of instances you want to bind to. Providing the bind_target_scope is also a good sanity check to make sure you are binding into the correct instance.

Dave

Thanks Dave…

Also, I am wondering… whats the value add in redefining all the tasks in the
abstract and concrete classes… It serves its purpose in making it a ovm_object and
provides an handle to the driver… so the driver can call the tasks as it see fit…

Whats your opinion ?

Hi, I am not clear about the code in abstract.sv.
I find a compile error under questa6.5b, such as following:
In non-vopt mode, only literal expressions are supported as indices in a bind target hierarchical reference. Please run vlog in the vopt flow.

Much thanks~

I moved the bind_target module to the same level as the module in which i was binding and this error went away…

I am not sure what it means, but thats the outcome.

Thanks Dave…
Also, I am wondering… whats the value add in redefining all the tasks in the
abstract and concrete classes… It serves its purpose in making it a ovm_object and
provides an handle to the driver… so the driver can call the tasks as it see fit…

The value is the driver can call the tasks with out a hierarchical reference to the DUT, and without any dependency on the DUT. In fact, the concrete classes could be replaced by other non-RTL model, removing the DUT, without the driver ever knowing it.

BTW, the issues with bind and no-vopt is a tool issue that should be discussed directly with Mentor.

Dave

I guess I’m having trouble understanding what is about the OVM that is preventing you from doing what you did in the AVM.
I’ll try to explain using the examples in the paper using OVM terminology. Let’s say this is your legacy BFM module:

module UART_Tx(output logic line);
int NBits;
time BitPeriod;
task setNBits(input int N);
if (N>0 && N<=10) NBits = N;
endtask : setNBits
task setBitPeriod(input time T);
if (T>0) BitPeriod = T;
endtask : setBitPeriod
task send(input logic [9:0] d);
...
endtask : send
endmodule : UART_Tx

And your legacy testbench looked like:

module top;
wire line;
UART_DUT  u_dut(line);
UART_TX u_tx(line);
endmodule
module test;
initial begin  
top.U_tx.setNBits(8);
top.U_tx.setNPeriod(100); 
top.U_tx.send(8); 
repeat (30) 
top.U_tx.send($random);
...
endmodule

Now here’s the abstract class definition, defined as an ovm_object so it can be passed through a config object

package UART_pkg; 
virtual class UART_BFM extends ovm_pkg::ovm_object;
pure virtual task setNBits(input int N); 
pure virtual task setBitPeriod(input time T); 
pure virtual task send(input logic [9:0] d);
function new(string name);
super.new(name);
endfunction
endclass
endpackage : UART_pkg

Now in module test, or anywhere other than in a package, you define the concrete class, and register the config object:

module test;
class U_TX extends UART_pkg::UART_BFM;
task setNBits(input int N); 
TB_top.U_tx.setNBits(N); 
endtask 
task setBitPeriod(input time T); 
TB_top.U_tx.setNPeriod(100); 
endtask 
…
function new(string name);
super.new(name);
endfunction
endclass
U_TX u_tx=new("U_TX");
initial set_config_object("driver_path","BFM",u_tx,0); // 0 - means don't clone
endmodule

Then in your driver (or monitor/whatever) you would use get_config_object to retrieve your handle:

import uart_pkg::*;
import ovm_pkg::*;
class uart_driver extends ovm_component;
uart_bfm bfm_h;
function void configure();
ovm_object h;
assert (!get_config_object("BFM",h) else ovm_report_error(...);
$cast(bfm_h = h);
endfunction
task that_does_something(...);
...
bfm_h.send(data);
…
endtask
endclass

Dave

===============
Those coming from C++ background may recognize the elegant design solution presented here is an exercise in the application of what’s known as an Adapter Design Pattern in OOP. A solution for a problem already exist (as Verilog code), question is: how to use it without duplicating it? That is, how to interface it with OVM driver class? Four-step solution: (1) create abstract class (2) Derive concrete class from abstract class (3) Derived class has to have some way of knowing (i.e. reference) to legacy code, and finally (4) Driver class has to have a reference to abstract class.

In reply to dave_59:

Dear Dave:

    Thanks!
    Can you explain a little more about bind?
  
   In statement below:

    bind UART_TX:top.BLOCK[i].U_tx UART_TX_probe p()

    "UART_TX" is a module.
    "top.BLOCK[i].U_tx" is a scope
    "UART_TX_probe p()" is an instantiation.

    Totoally , What bind really want to do?

     If I dont want use bind, can it still achieve such function?

In reply to Jules:


bind
is just a shortcut for instantiating a module (or interface) inside another module without modifying the source code for that other module. You can use all the concepts from the abstract class example here without using
bind
.

In reply to dave_59:

The code is no more accessible. can I have the full working code for ovm wrapper for verilog bfm.

email: akulkarni@lateralsands.com

thanks,
Amit

In reply to amtoya:

This site was moved recently and the file attachment links did not get properly updated.

Here are temporary links to the files:

https://s3.amazonaws.com/attachments.verification.academy.com/abstract.sv

In reply to dave_59:

This thread has been very helpful. Is there a UVM example for this implementation?

I have a DUT bfm with built in tasks that I want to access(register writes/reads etc). My approach is going to be as follows:

I create the abstract class with the pure virtual functions, and I extend the abstract class in the top module that has the DUT and the virtual interface. I do this here so I can get hierarchical access to the tasks in the bfm, instead of binding it. I store the extended class in the uvm_config_db so I can access it in the driver. My only concern would be that the driver won’t be able to see my extended class in the top module and I do not know how to address that. Please advise.

In reply to rthakur1:

This paper illustrates the same concepts and has been updated for UVM

In reply to dave_59:

This is exactly what I needed! Thank you! You’re a legend!