luyuan_0922的个人空间 https://blog.eetop.cn/106870 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

基本上是sv的书上的所有点了--转

已有 2985 次阅读| 2015-3-21 11:06

Systemverilog
数据类型

      合并数组和非合并数组

1)合并数组:

存储方式是连续的,中间没有闲置空间。

例如,32bit的寄存器,可以看成是4个8bit的数据,或者也可以看成是1个32bit的数据。

表示方法:

数组大小和位,必须在变量名前指定,数组大小必须是【msb:lsb】

Bit[3:0] [7:0] bytes   ;

 

2)二维数组和合并数组识别:

合并数组:  bit [3:0] [7:0] arrys;   大小在变量名前面放得,且降序

二维数组:  int arrays[0:7] [0:3] ;  大小在变量名后面放得,可降序可升序

位宽在变量名前面,用于识别合并和非合并数组,位宽在后面,用于识别数组中元素个数。

 

3)非合并数组

一般仿真器存放数组元素时使用32bit的字边界,byte、shortint、int都放在一个字中。

非合并数组:字的地位存放变量,高位不用。

表示方法:

 Bit   [7:0] bytes; 

       4)合并数组和非合并数组的选择

        (1)当需要以字节或字为单位对存储单元操作。

        (2)当需要等待数组中变化的,则必须使用合并数组。例如测试平台需要通过存储器数据的变化来唤醒,需要用到@,@只能用于标量或者合并数组。

      Bit[3:0] [7:0] barray[3]  ; 表示合并数组,合并数组中有3个元素,每个元素时8bit,4个元素可以组成合并数组

     可以使用barry[0]作敏感信号。

 

      动态数组

随机事物不确定大小。

使用方法:数组在开始是空的,同时使用new[]来分配空间,在new[n]指定元素的个数。

Int dyn[];

   Dyn = new[5];     //分配5个元素空间

          Dyn.delete() ;     //释放空间

      队列

在队列中增加或删除元素比较方便。

      关联数组

当你需要建立一个超大容量的数组。关联数组,存放稀疏矩阵中的值。

表示方法:

采用在方括号中放置数据类型的形式声明:

Bit[63:0] assoc[bit[63:0]];

 

      常量:

1)Verilog 推荐使用文本宏。

好处:全局作用范围,且可以用于位段或类型定义

缺点:当需要局部常量时,可能引起冲突。

2)Parameter

   作用范围仅限于单个module

3)Systemverilog:

   参数可以在多个模块里共同使用,可以用typedef 代替单调乏味的宏。

 


过程语句

      可以在for循环中定义变量,作用范围仅在循环内部

for(int i=0;i<10;i++)

array[i] =i;

 

      任务、函数及void函数

1) 区别:

Verilog中task 和function最重要的区别是:task可以消耗时间而函数不能。函数中不能使用#100的延时或@的阻塞语句,也不能调用任务;

Systemverilog中函数可以调用任务,但只能在fork  joinnone生成的线程中。

2)使用:

   如果有一个不消耗时间的systemverilog任务,应该把它定义成void函数;这样它可以被任何函数或任务调用。

  从最大灵活性角度考虑,所有用于调用的子程序都应该被定义成函数而非任务,以便被任何其它任务或函数调用。(因为定义成任务,函数调用任务很有限制)

 

      类静态变量

作用:

1)类的静态变量,可以被这个类的对象实例所共享。

当你想使用全局变量的时候,应该先想到创建一个类的静态变量

静态变量在声明的时候初始化。

2)

类的每一个实例都需要从同一个对象获取信息。

      静态方法

作用:

当静态变量很多的时候,操作它们的代码是一个很大的程序,可以用在类中创建一个静态方法读写静态变量,但是静态方法不能读写非静态变量。

      ref高级的参数类型

Ref 参数传递为引用而不是复制。Ref比 input 、output、inout更好用。

Function void print_checksum(const ref bit [31:0] a[ ]);

1)       也可以不用ref进行数组参数传递,这时数组会被复制到堆栈区,代价很高。

2)       用带ref 进行数组参数传递,仅仅是引用,不需要复制;向子程序传递数组时,应尽量使用ref以获得最佳性能,如果不希望子程序改变数组的值,可以使用const ref。

3)       Ref参数,用ref 传递变量;可以在任务里修改变量而且,修改结果对调用它的函数可见,相对于指针的功能。

 

      Return语句

增加了return语句。Task任务由于发现了错误而需要提前返回,如果不这样,那么任务中剩下的语句就必须被放到一个else条件语句中。体会下

Task load_array(int len. Ref int array[ ]);

If(len<0)  begin

  $display(“Bad len”);

  Returun;

//任务中其它代码

    endtask

 

      局部数据存储 automatic作用

Verilog中由于任务中局部变量会使静态存储区,当在多个地方调用同一个任务时,不同线程之间会窜用这些局部变量。

Systemverilog中,module和program块中,缺省使用静态存储;如果想使用自动存储,需加入automatic关键词。

 


测试平台

      Interface

背景  

一个信号可能连接几个设计层次,如果增加一个信号,必须在多个文件中定义和连接。接口可以解决这些问题。

好处:

如果希望在接口中增加一个信号,不需要改变其他模块,如TOP模块。

使用方法:

(1)接口中去掉信号的方向类型;

(2)DUT 和测试平台中,信号列表中采用接口名,例化一个名字

注意:

因为去掉了方向类型,接口中不需要考虑方向信号,简单的接口,可以看做

是一组双向信号的集合。这些信号使用logic类型[d1] 

双向信号为何可以使用logic呢?

这里的双向,只是概念上的双向,不想verilog中databus多驱动的双向。

双向信号如何做接口?

 

(1)仲裁器的简单接口

Interface arb_if( input bit clk);

     Logic [1:0] grant,request;

     Logic rst;

Endinterface

DUT 使用接口:

Module arb(arb_if arbif);

Always @(posedge arbif.clk or negedge arbif.rst)

  …

endmodule

 

(2)DUT 不采用接口,测试平台中使用接口(推荐)

    DUT 中源代码不需要修改,只需要再top中,将接口连接到端口上。

   Module top;

       Bit clk;

       Always #2 clk =~clk;

      Arb_if arbif(clk);

      Arb_port al(.grant(arbif.grant),

                .request(arbif.grant),

                .rst(arbif.rst),

                .clk(arbif.clk)

                );

      Test t1(arbif);

   Endmodule

 

      Modport

背景:

端口的连接方式包含了方向信息,编译器依次来检查连续错误;接口使用无信号的连接方式。Modport将接口中信号分组并指定方向。

例子:

      在总线设计中使用modport

并非接口中每个信号都必须连接。Data总线接口中就解决不了,个人觉得?

因为data是一个双驱动

 

      时钟块

作用:

一旦定义了时钟块,测试平台就可以采用@arbif.cb等待时钟,而不需要描述确切的时钟信号和边沿,即使改变了时钟块中的时钟或边沿,也不需要修改测试代码

应用:

将测试平台中的信号,都放在clocking 中,并指定方向(以测试平台为参考的方向)。并且在modprot test(clocking cb,

 

 

 

最完整的接口:

Interface arb_if(input bit clk);

Logic[1:0] grant,request;

Logic rst;

 

Clocking cb @(posedge clk);

    Output request;

    Input grant;

Endclocking

 

Modport test (clocking cb,

           Output rst);

Modport dut (input clk, request,rst,

           Output grant);

   endinterface

 

变化:将request 和grant移动到时钟块中去了,test中没有使用了。

 

      接口中的双向信号

Interface master_if(input bit clk);  //在类中为了,不使用有符号数,常用bit[]定义变量

   Wire [7:0] data;

  Clocking cb@(posedge clk);

     Inout data;

  Endclocking

 Modport TEST(clocking cb);

endinterface

 

program test(master_if mif);

initial begin

   mif.cb.data <= ‘z;

@mif.cb;

$display(mif.cb.data);     //总线中读数据

@mif.cb;

Mif.cb.data <= 8’h5a;     //驱动总线

@mif.cb;

Mif.cb.data <= ‘z;        //释放总线

 

注:

(1)interface 列表中clk 采用的是input bit clk;为什么要用bit?

(2)时钟块 clocking cb 中,一般将testbench中需要的信号,方向指定在这里;

 而在modprot 指定test信号方向的时候,采用clocking cb。

(3)interface中信号,不一定都用logic,也可采用wire(双驱动);systemverilog

中如果采用C代码的风格(参数列表中方向和类型写一起),必须采用logic类型

(4)现在的风格,DUT 没才用clocking cb ,测试平台和DUT的时钟如何统一?

      激励时序

DUT和测试平台之间时序必须密切配合。

 

      测试平台和设计间的竞争状态

好的风格:

使用非阻塞赋值可以减少竞争。

systemverilog验证中initial 中都采用<= 赋值,而等待延迟采用@arbif.cb等待一个周期来实现。

而verilog中采用的风格时,initial 中采用 =阻塞赋值,沿时可以采用#2,等实现。

因此时钟发生器,只能放在module 中,而不能放在program中

 

 

      Program中不能使用always块

测试平台可以使用initial 但不能使用always,使用always 模块不能正常工作。

原因:测试平台的执行过程是进过初始化、驱动和响应等步骤后结束仿真。

如果确实需要一个always块,可以使用initial forever 来完成。比如:在产生时钟时。


点赞

全部作者的其他最新日志

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 4

    粉丝
  • 1

    好友
  • 1

    获赞
  • 11

    评论
  • 1002

    访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-5-2 19:05 , Processed in 0.025003 second(s), 13 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部