OOP:Object-Oriented Programming,有两点个人认为适合验证环境的搭建:1)Property(变量)和Method(function/task)的封装,其实是BFM模型更方便的应

用。2)继承(Inheritance)与合成(Composition)非常适合一个架构的搭建。

在SV中,类可以定义在program, module, package中,但是一般一个类或几个相关的类会单独写在一个文件中。最终在program中调用。而且在SV中,所有成员

默认都是public类型的,除非显示的用local/protected来声明。实际上,SV class中的变量应该尽可能的用public并且rand,来增加可控性。

local/protected都可以针对property和method来说明,local表示member只对该class的对象可见,extend出的subclass也是不可见的。

但是该class中non-local的method调用了local的method或者property,

inherit之后的method也是可以正常执行的。

protected表示member对该class和它的subclass都是可以见的。 对外部的大环境不可见。

基类的指针可以直接指向扩展类的对象,但是只能调用扩展类中基类的那一部分,

基类的指针也可以直接转换为扩展类的指针,通过$cast函数,此时的基类指针指向的已经是扩展类对象,通过cast,转变为扩展类指针,可以调用扩展类中自有的元素。

SV默认会为每个类创建一个new函数,并初始化对象(二值变量为0,四值变量为X)。用户一般自定义new函数赋初值,分配空间可以交给SV来做。

显式的释放一个句柄指向的对象的空间 tr=null。

在SV中可以用关键字(Static)创建静态变量,可以让类有一个类级别的全局变量。一般子初始化时即赋值,还可以建一个静态的方法,来单独的操作静态变量。静态变

量可以通过类名::变量名的方式来引用。类中的其他变量都默认是automatic的修饰符,而且可以通过this.变量名,来直接调用类一级别的变量。在类的外

部定义方法时,可以用关键字extern来在类中声明,后在类外通过类名::方法名的方式来定义。

当类作为一个function的传递参数时,此时不加ref传递的是一个句柄的复制量。在下边的例子中,tr只有一个t的句柄的复制量,所以是Null,之后tr的改变和t没有直

接关系。

Transaction   t;                                         function void create(Transaction tr);

initial  begin                                                                     tr = new ();

creat(t);                                                            tr.addr = 42;

$display(t.addr);                         endfunction

end

一个对象的复制,可以通过简单的new函数来实现,也可以通过一种自定义的copy函数来实现,这种实现方式在类包含中,很适用。

new函数,当要复制的对象中还包含另一个类的对象时,会直接复制另一个对象的所有东西,包括id,句柄。

Transaction  src, dst;                            function    Transaction copy

initial  begin                                                                 copy = new();

src = new;                                                     copy.addr = addr;

dst = new src;                                                copy.stats = stats.copy();

end                                          endfunction

copy函数,在每一个类中都定义,在使用时,递归调用。这是id号都会刷新,而且因为对象都是new来构造出来的,所以更符合设计意图。

在一个类中例化另一个类(Composition),这时对方法的调用:ststs.startT.function,为了确保在编译时,不会因为编译顺序而造成某个类还不能被识别,可以在文

件开头加 typedef class Statistics, 来先声明类Statistics。而且此时外层类的new函数中,必须包含内层类的new函数。这种composition的结构非常适合

去构建一个大的验证框架,因为它可以将各个部分联系起来。

类的继承(Inheritance),扩展类拥有基类的一切变量与方法,在扩展类中调用基类的变量与函数,可以通过super.+变量/方法来调用。在扩展类的构造函数中,应该

先对基类先进行new函数。在扩展类的对象中调用对象时,SV比较句柄的类型来决定调用的是基类function还是扩展类function。但是当function是virtual

类型时,SV会根据对象的类型来决定调用基类function还是扩展类function。推荐需要扩展的基类中使用virtual function的形式,这样符合OOP的多

态概念,也有利于向下转换。

class  Transaction;                                                                     class extends Transaction;

rand bit [31:0]src,dst,data[8];                                               rand  bit  bad_crc;

bit [31:0]crc;                                                                        virtual  function  void  calc_crc();

virual function void cal_crc();                                                                super.calc_crc();

crc = src^dst^data.xor;                                                      if(bad_crc) crc = ~crc;

endfunction                                                                              endfunction

endclass: Transaction                                                                 endclass:Badtr

Transaction  tr;

Badtr bad;

initial  begin

tr = new ();

tr.calc_crc ();                   //调用基类类型

bad = new();

bad.calc_crc ();                //调用扩展类类型

tr = bad;                         //基类句柄可以直接指向扩展类对象

tr.calc_crc ();                  //由对象类型来决定,所以调用BadTr.calc_crc

$cast(bad , tr);               //将指向扩展类对象的基类句柄指向扩展类句柄。只有这种情况下,可以成功,$cast非零

bad.calc_crc ();              //由对象类型决定,所以调用BadTr.cac_crc

end

BluePrint pattern:其实是类的继承在可重用验证环境中的一种典型用法。以Transaction为例,定义一个Transaction的基类,然后再定义一个Transaction的扩展

类,然后在顶层Test中,指定Generator需要哪一个Transaction。其实和UVM中的sequencer调用sequence如出一辙。

class Generator;                                                                         class Environment;

mailbox gen2drv;                                                                        Generator gen;

Transaction tr;                                                                            Driver drv;

function new (input mailbox gen2drv)                                           mailbox gen2drv;

this.gen2drv = gen2drv;                                        function void build;      //new函数的构建,mailbox, drv, gen

tr = new();                                                           task  run();

endfunction                                                                                 task  wrap_up() ;

task run;                                                                          endclass

Transaction tr1;

forever begin

assert(tr.randomize() );

tr1 = tr.copy();       //copy一份到driver

gen2drv.put (tr1);

end

endtask

endclass

program  automatic test;

Environment  env;

initial begin

env = new();

env.build();        //new函数

begin
                                               BadTr bad = new();

env.gen.tr = bad;           //通过类的顶层关系来调用,Transaction的替换

end

env.run();

env.wrap_up();

end

endprogram

CallBack:在顶层中定义一个Task,在Driver中调用。便于直接添加task,并且因为是在顶层,所以更好针对项目来定制。

class Driver;

Driver_cbs cbs[$];   //用于存放扩展类的句柄,这个扩展类可以使driver也可以是scoreboard,只要是需要回调的。

task  run();

bit drop;

Transaction tr;

forever  begin

drop = 0;

agt2drvget(tr);

foreach (cbs[i])  cbs[i].pre_tx(tr, drop);        //前回调

if(!drop)  continue;

transmit (tr);      //最基本的driver就负责一种发送transaction

foreach (cbs[i]) cbs[i].post_tx(tr);              //后回调

end

endtask

class  Driver_cbs_drop  extends  Driver_cbs;

scoreboard scb;

virtual task pre_tx (ref Transaction tr, ref bit drop)          //从一个纯虚类继承而来,之所以使用纯虚类,为了能够重载

scb.save_expected (tr);                      //与scoreboard连接起来,

drop = ($urandom_range (0,99) == 0);   //随机丢掉一个transaction

endclass

program autmatic test;                                                                              class Scoreboard;

Environment env;                                                                                        Transaction scb[$];

initial  begin                                                                                                function void save_expect (input Transaction tr)

env= new();                                                                                 function void compare_actual( input Trans..  tr)

env.build();                                                                          enclass   //一个简单的scoreboard模型

begin

Driver_cbs_drop  dcd = new();

env.drv.cbs.push_back(dcd);         //在顶层加入一个task

end

end

endprogram

纯虚类和纯虚方法:只为继承的基类和方法。纯虚方法+pure声明,只需要定义一个prototype,并且只能在纯虚类中定义,必须继承才能使用。同样纯虚类,可以定

义非纯虚方法,但是还是必须继承才能例化。

virtual  class  BaseTr;

static int count;

int id;

function new();

id = count ++;

endfunction

pure virtual function bit compare(input BaseTr to);

pure virtual function BaseTr copy(input BaseTr to = null)

endclass

还有一个问题:在基类中定义虚方法时,copy函数可以进一步优化。因为虚函数在基类和扩展类中,必须参数一致,返回类型一样,所以建议将copy_data单独分出

来。copy_data中传入指向扩展对象的指针,copy函数内进行new。copy的返回类型可以是基类指针,所以也可以是扩展类对象。

class  BadTr extends Transaction

rand bit bad_crc;

virtual function void copy_data(input Transaction tr);

BadTr bad;

super.copy_data(tr);          //这样返回的还是基类句柄,因为copy_data是virtual function

$cast(bad,tr)

bad.bad_crc = bad_crc;     //此处返回的应该是基类指针,也可以是扩展类对象

endfunction

。。。。。。。

virtual  function void copy(input Transaction1 to == null);       //新的copy函数,更加健壮

BadTr  bad;

if(to == null)

bad = new();

else  bad = to;

copy_data(bad);          //扩展类对象。

return bad;

endfunction

基类句柄可以直接指向扩展类对象,此时基类的句柄可以赋值给扩展类的句柄$cast(base,extends),来访问扩展类中的变量。

如果基类句柄没有指向扩展类对象,那这个复制会报错。

SV中的OOP的更多相关文章

  1. 不会JS中的OOP,你也太菜了吧!(第二篇)

    一.你必须知道的 1> 原型及原型链在继承中起到了关键的作用.所以你一定要理解他们.2> 不会JS中的OOP,你也太菜了吧!(第一篇) 二.继承的6种方法 1> 原型链继承 原型链继 ...

  2. oc中的oop基础及类的基本介绍

    面向对象的(OOP)的基础知识 类(class):表示一组对象数据的结构体,对象通类来得到自身.类名首字母大写. 对象(objcet):是一种包含值和指向其类的隐藏指针的结构体.运行中的程序中通常会有 ...

  3. SV中的随机化

    SV搭建testbench的关键概念:CRT(constraint random test),测试集的随机化. 由于对象class由数据和操作组成,所以对数据的随机化一般放在一个class内.(对环境 ...

  4. SV中的线程

    SV中线程之间的通信可以让验证组件之间更好的传递transaction. SV对verilog建模方式的扩展:1) fork.....join 必须等到块内的所有线程都执行结束后,才能继续执行块后的语 ...

  5. SV中的Interface和Program

    Interface:SV中新定义的接口方式,用来简化接口连接,使用时注意在module或program之外定义interface,然后通过'include来添加进工程. interface  arb_ ...

  6. SV中的task和function

    SV中class的properties和methods默认都是public的,但是可以声明为local和protected. 一个properties声明为local类型的,则只在该class中的me ...

  7. SV中的数据类型

    Verilog-1995中规定的数据类型有:变量(reg), 线网(wire), 32位有符号数(integer), 64位无符号数(time), 浮点数(real). SV扩展了reg类型为logi ...

  8. Python3中面向对象 OOP

    Python3中面向对象 OOP 定义: python中通过关键字 class 实现类的定义: class ClassName(object): pass 获取成员变量:ClassName.变量名 修 ...

  9. 小结JS中的OOP(下)

    关于JS中OOP的具体实现,许多大神级的JS专家都给出了自己的方案. 一:Douglas Crockford 1.1 Douglas Crockford实现的类继承 /** * 原文地址:http:/ ...

随机推荐

  1. 【JSP】EL函数和自定义EL函数

    简介 EL原本是JSTL1.0中的技术(所以EL和JSTL感情如此好就是自然的了),但是从JSP2.0开始,EL就分离出来纳入了JSP的标准了.但是EL函数还是和JSTL技术绑定在一起.下面将介绍如何 ...

  2. Altium Designer 输出 gerber 光绘文件的详细说明

    Altium Designer 输出 gerber 光绘文件的详细说明 PCB画好后,我们需要输出光绘文件交给制版厂家.由此,输出光绘文件的重要性就显出来了. 先复习一下介绍各层的定义吧,哈哈 (1) ...

  3. 【CF887E】Little Brother 二分+几何

    [CF887E]Little Brother 题意:给你n个圆和一条线段,保证圆和圆.圆和线段所在直线不相交,不相切,不包含.求一个过线段两端点的圆,满足不和任何圆相交(可以相切.包含).问圆的最小半 ...

  4. SVG学习笔录(二)

    一.svg动画SMIL SVG采用的是使用文本来定义图形,这种文档结构非常适合于创建动画.要改变图形的位置.大小和颜色,只需要调整相应的属性就可以了.事实上,SVG有为各种事件处理而专门设计的属性,甚 ...

  5. jQuery将时间转化为时间戳或将时间戳转化为时间

    下面的这段代码,是可以将时间戳转为时间,或者将时间戳转为时间: <script type="text/javascript"> $.extend({ myTime:{ ...

  6. 各浏览器Cookie大小、个数限制【转】

    先插入一条广告,博主新开了一家淘宝店,经营自己纯手工做的发饰,新店开业,只为信誉!需要的亲们可以光顾一下!谢谢大家的支持!店名: 小鱼尼莫手工饰品店经营: 发饰.头花.发夹.耳环等(手工制作)网店: ...

  7. Nginx防止恶意域名解析

    为了防止别人恶意将大量域名解析到自己的网站上面.我们可以对nginx做防止恶意域名解析,这样就只能通过自己的域名访问网站,其他域名就会显示错误500 打开Nginx配置文件nginx.conf,在原来 ...

  8. 高盛为什么认为中国AI领域将超越美国?

    不久前,高盛发布的名为<中国在人工智能领域崛起>的研究报告,报告中,高盛认为中国已经成为AI领域的主要竞争者,中国政府建设“智慧型经济”和“智慧社会”的目标将有可能推动中国未来GDP的增长 ...

  9. python数据结构之堆栈

    本篇我以堆栈的数据类型和操作方法两个方面总结学习笔记 堆栈(Stack) 一种后进先出(LIFO)的线性数据结构,对堆栈的插入和删除操作都只能在栈顶(top)进行. 堆栈可以通过数组和链表轻松实现 一 ...

  10. @font-face 字体图标的应用

    所谓字体图标,顾名思义就是图标以字体的形式存在,可以利用 font-size.color 对字体图标的大小和颜色进行渲染.将小图标集中放到字体库里,利用css3 @font-face 引用图标,不仅有 ...