加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

systemverilog中的OOP

(2014-07-20 10:55:36)
标签:

systemverilog

oop

分类: Verification

1,OOP中的几个名词:Class--定义类;Object---类的例化,也是句柄指向的单元;Handle---句柄,指向一个Object的具体地址;Property---类中的变量,也可以称为variable;Method---类中定义的函数(function)或任务(task),也可以叫做routines。

2,一般工程的把一个类的定义放在一个单独的文件中,再把几个有关联的类和文件打包为一个package。

3,在SV中对于每个定义的类,都有一个默认的constructor。这个构建函数主要完成两个工作:分配地址和初始化变量,即2态的变量初始化为0,4态的变量初始化为X。用户也可以自定义自己的new()函数,然后完成自己的初始化赋值。在下例中,new有两个参数,在initial的调用中,只赋值了第一个参数,第二个参数仍为默认值5,除此两个参数外的其他参数都是默认值0或X。

Eg:               class   Transaction;

                          logic  [31:0]  addr,crc,data[8];

                          function  new(logic   [31:0]  a=3,d=5)

                                 addr = a;

                                 foreach (data[i])

                                        data [i] = d;

                          endfunction

                    endclass

                    initial  begin

                          Transaction  tr;

                          tr = new(10);

                    end   

4,应该尽量避免将Object的声明和构造放在一条语句中,因为如果new()的声明不是automatic的,那么在仿真的开始SV便会将类构造出来以分配地址,而可能要在进入block中时,类才会被声明。所以应该将类的声明和构造分开。

5,同一类型的句柄之间可以相互赋值,从而改变指向的Object。

6,Object的释放,SV中一条默认的规定是,当一个Object不再指向任何有效的地址时,将会将地址收回。可以通过赋值语句 tr = null来完成地址的释放。如果一个Object中还包含一个运行的thread,那么必须等到进程运行完成,才能释放地址。

7,类中的静态变量相比较于Object中的变量,前者适应在整个类中,所有的已经例化的Object,而Object中的变量只适用于本身。所以static变量的声明只能在class中,而不是在一个new()函数中。调用static变量,通过"::",调用Object自己本身中的变量通过"."。而且static的routines中只能调用static的变量,不能调用去其他的Object中的变量。在下例中,id可以表示每个已经声明的Object的id号,而count可以表示总共的声明的Object的数量。

Eg:                        class  Transaction;

                                   static  int  count = 0;

                                   int id;

                                   function  new();

                                             id = count ++;

                                   endfunction

                             endclass

8,在类外定义routines时,可以使用extern声明,在外部定义时,可以使用"::"表示引用。在类的内部定义的必须是一个prototype,在类外部定义时,完全按照这个定义routines的参数。

9,在类中可以使用"this"来指明是类中的变量,从而可以在赋值时方便一些。在下例中,oname在两个scope中都有定义,用"this"来特指类中的定义。在SV中scope可以有:module program task funtion class foreach begin-end  for,其中根范围可以用"$root来表示"

Eg:                      class   Scoping;

                                   string  oname;

                                   function  new(string  oname);

                                           this.oname = oname;

                                   endfunction

                              endclass

10,在类中定义子类,父类对子类的调用与其他变量相同,不过子类的构造最好直接放在父类的类定义中。在下例中,将stats的构造放在类Transaction中,否则handlestats指向为null。在子类定义比较靠后时,可以通过"typedef"来先进行声明,--typedef class  Statistics;

Eg:                         class   Statistics;

                                   ....

                              endclass

                              class   Transaction;

                                           bit [31:0] addr, crc, data[8];

                                           Statistics stats;

                                           function new ();

                                                     stats = new();

                                           endfunction

                                endclass

11,在methods中引用Object时,通过将Object传给method来进行调用,在声明时有两种方式:加ref,不加。在添加ref时,可以改变handle指向的Object的值,不加是,只能使用特指的那一个Object。

Eg:    task  transmit (Transaction t);          //t是一个Class的Object

              ......

         endtask

         Transaction  t;

          initial  begin

                 t = new ();

                 t.addr = 42;

                 transmit (t);               //只能调用object---t来调用。

           end

      2) function   void   create (  ref  Transaction tr);

                 tr = new();

                 .......

           endfunction

           Transaction  t;                //声明另外一个Object

            initial   begin

                   create (t);

                   $display (t.addr);   //任意调用,更符合一般的思维

            end            

12,Handle的矩阵表示,在下例中,先声明一个指向类的矩阵handle,然后在foreach中,逐一的来进行构造new()。

Eg:          task   generator ();

                   Transaction  tarray[10];

                    foreach  (tarray [i])

                           begin

                                 tarray[i] = new();

                                 transmit (tarray[i]);

                           end                               

                endtask  

13,对Object的copy操作,可以方便的完成对象值得赋值,但是因为copy的本质操作也是进行地址的赋值,本身并没有重新构建一个object,所以像id这样的标志两个copy的类会相同。还有一个问题是,在父类中有子类时,两个父类的子类的地址相同,所以任何一个类中的值的改变都会影响另外一个的值。

Eg:              class  Transaction;

                         Statistica stats;

                         .......

                   endclass

                   Transaction src, dst;

                   initial  begin

                        src = new ();

                        src.stats.startT = 42;

                        dst = new src;

                        dst.stats.startT = 96;        //src,dst指向同一个stats地址,所以src和dst的startT的值都变96.  

                        $display ( src.stats.startT ); 

                   end

一个比较好的解决方法是:自己写一个copy函数,像下面例子中的那样。

                   class  Transaction;

                         bit  [31:0]  addr, src, data[8];

                         function Transaction  copy();        //自定义copy函数,返回类型为Transaction

                                  copy = new();

                                  copy.addr = addr;

                                  copy.crc    = crc;

                                  copy.data = data;

                         endfunction

                   endclass

                   Transaction src, dst;

                    initial  begin

                          src = new ();

                          dst = src.copy ();               //调用

                    end

14,在SV中,变量和routines的默认声明会是public,也可以自己加label声明为local和protected的。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有