SystemVerilog 第4章 连接设计和测试平台


在这里插入图片描述


4.1 将测试平台和设计分开

  • SV引入程序块(program block),从逻辑和时间上将TB和DUT分开

4.1.1 测试平台和DUT通信

  • 验证分为:生成激励→获取输出响应→决定对错→衡量进度
    在这里插入图片描述

4.1.2 端口通信

  • 使用端口进行通信的arbiter
//RTL
module arb_port(
	output logic [1:0] grant,
	input logic [1:0] request,
	input logic rst,
	input logic clk
);
...
always @(posedge clk or posedge rst) begin
...
end
endmodule

//TB
module test(
	input logic [1:0] grant,
	output logic [1:0] request,
	output logic clk,
	output logic rst
);
initial begin
	@(posedge clk) request <= 2'b10;
	...
end
endmodule

//TOP
module top;
logic [1:0] grant, request;
bit clk, rst;
always #5 clk = ~clk;

arb_port a1(grant,request,rst,clk);
test t1(grant,request,rst,clk);
endmodule

4.2 接口

  • 接口像模块一样例化,可以用于模块间以及RTL与TB间的信号连接

4.2.1 使用接口简化连接

  • 在RTL, TB, TOP模块外要提前声明interface
    使用接口进行通信的arbiter
//interface
interface arb_if(
input bit clk
);
logic [1:0] grant, request;
logic rst;

endinterface: arbif

//RTL
module arb(
arb_if arbif
);
...
always @(posedge arbif.clk or posedge arbif.rst) begin
...
end
endmodule: arbiter

//TB
module test(
arb_if arbif
);
...
initial begin
	@(posedge arbif.clk) arbif.request <= 2'b01;
	...
end
endmodule: test

//TOP
module top;
bit clk;
always #5 clk = ~clk;

arb_if arbif(clk);
arb a1(arbif);
test t1(arbif);
endmodule: top

4.2.2 连接接口和端口

  • 可以使用 .port(ifc.signal) 的形式将 端口 连接到 接口
arb_port a1(
.grant(arbif.grant),
.request(arbif.request),
.rst(arbif.rst),
.clk(arbif.clk)
);

4.2.3 modport将信号分组

  • modport可以将信号分组指明其方向
//interface
interface arb_if(
input bit clk
);
logic [1:0] grant, request;
logic rst;

modport DUT(
input request,clk,rst,
output grant
);

modport TEST(
output request,rst,
input grant,clk 
);

modport MONITOR(
input request,grant,clk,rst
);
endinterface: arbif

//RTL
module arb(
arb_if.DUT arbif
);
...
endmodule: arbiter

//TB
module test(
arb_if.TEST arbif
);
...
endmodule: test

//TOP没有变动
module top;
bit clk;
always #5 clk = ~clk;

arb_if arbif(clk);
arb a1(arbif);
test t1(arbif);
endmodule: top
  • 使用modport名的方式有两种
    ①在TB和RTL的portlist中声明,TOP不声明(更具物理意义)
    ②在TOP中声明,在TB和RTL中申明(适用于多次例化同一模块)

4.2.4 总线设计modport

  • 由于不是每个信号都必须连接,所以总线接口中要为主/从设备、仲裁器和监视器定义不同的modport

4.2.5 监视器模块

module monitor(arb_if.MONITOR arbif);
...
endmodule

4.2.6 接口优缺点

  • 优点
    ①便于设计重用
    ②避免连错
    ③便于增减信号
    ④modport可用于信号方向检测
  • 缺点
    ①点对点连接冗长
    ②同时使用 接口名.信号名
    ③专用接口复用率低,工作量大
    ④不同接口之间连接困难

4.3 激励时序

4.3.1 时钟块控制同步信号时序

  • 接口块中使用时钟块来指定需要同步的信号相对于时钟的时序,时钟中的任何信号都将同步地驱动和采样
  • 可以使用default语句指定一个时钟偏移,但默认输入信号尽在设计执行前被采样,且设计的输出信号在当前时间片又被驱动回当前设计
  • clocking块默认在clk到来前#1step延时前采样输入信号(前一个time slot的postponed区域),#0后驱动输出信号
clocking cb @(posedge clk);
	default input #1step output #0step;
	input ...;
	output ...;
endclocking
  • 一个接口可以包含多个时钟块
  • 定义时钟块之后,测试平台可以使用@arbif.cb表达式等待时钟,不用描述确切地时钟信号名和边沿
  • 时钟块地声明和调用
//interface
interface arb_if(input bit clk);
	logic [1:0] request, grant;
	bit rst;

clocking cb @(posedge clk);
	output request;
	input grant;
endclocking

modport TEST(
clocking cb,
output rst
);

modport DUT(
input request,clk,rst,
output grant
);
endinterface

//测试平台
module test(
arb_if.TEST arbif
);

initial begin
	arbif.cb.request <= 0;
	@arbif.cb;
	$display("@%0t: Grant = %b",$time,arbif.cb.grant);
end
endmodule

4.3.2 接口中的logic和wire

  • logic可以用于接口中的过程块(过程赋值语句),但不能用于多驱动源(会报错)
  • wire只能用于连续赋值语句,但interface中的wire型clockvar可以直接在过程块中赋值

4.3.3 verilog时序问题

  • 测试平台应该在逻辑时序方面都独立于设计
  • 测试平台需要模仿测试仪的行为:当在有效时钟边沿或边沿之后驱动待测设计,然后再有效时钟边沿到来之前,尽可能晚地采样(满足协议前提下)
  • 如果测试平台和DUT仅由verilog模块构成,无法实现合理地时序实现

4.3.4 测试平台/设计之间的竞争

  • 如果仿真放在module中,那么DUT和TB执行是同时进行的,有可能发生clk拉高激活DUT但对应的共有信号data在clk拉高同时还未update,产生竞争
  • 解决办法即将仿真放在program block中
  • 什么是竞争和冒险?如何避免?
    竞争:在组合电路中,信号经由不同的途径达到某一会合点的时间有先有后,这种现象称为竞争.
    冒险:由于竞争而引起电路输出发生瞬间错误现象称为冒险.表现为输出端出现了原设计中没有的窄脉冲,常称其为毛刺.
    竞争与冒险的关系
    消除方法:增加冗余项;输出端并联电容;引入选通信号

4.3.5 程序块(program block)和时序区域(timing region)

  • SV中将测试代码放在程序块中实现测试和设计的事件(event)分开调度
  • program的语法和module十分类似(可以在module中例化),但program中不能有任何的层次级别(module实例,interface以及其他program)
  • 采用program的testbench
program test(
arb_if.TEST arbif
);

initial begin
	arbif.cb.request <= 0;
	repeat(2) @arbif.cb;
	$display("@%0t: Grant = %b",$time,arbif.cb.grant);
end
endprogram: test
  • program使用注意事项
    ①测试代码应当包含在一个单个的program中
    ②不能有层次级别,但可以使用OOP来创建动态、分层的testbench
    ③可以采用多个程序块将多个测试代码结合在一起
  • program的时间片划分(timing region)
    – active: RTL, 门级代码, clock generator
    – observed: assertion
    – reactive: testbench
    _ postponed: 所有活动结束后的只读时间段采样信号
    在这里插入图片描述

4.3.6 仿真结束

  • verilog:只有遇到$finish才结束仿真
  • system verilog:
    ①$finish同样适用
    ②每个program被看作一个测试,当所有program中所有initial都结束时即结束仿真
    ③$exit提前中断program

4.3.7 指定DUT和TB之间的延时

  • clocking模块会同步输出信号(即软件延迟为0),将输出信号直接送到DUT中,在reactive区域运行的program块在同一个time slot内再触发一次active区域

4.4 接口的驱动和采样

4.4.1 接口同步

  • 测试平台才能使用带有clocking block的interface同步信号的驱动和采样
  • clocking block中的信号将得到同步,clocking block之外的异步信号在通过interface时没有任何延迟
  • 使用clocking block中的信号时候要加上前缀 arbif.cb.request/.grant
  • 使用@和wait同步信号
    @等待电平信号发生跳变;wait等待电平信号为

4.4.2 信号采样

  • clocking block中input采样是在clk到来之前进行(postponed区域)
  • 如果DUT在clk到来时信号发生变化,采样任然保持clk前值,不会立即更新(因为DUT是硬件,信号改变有延时,需要setup time)

4.4.3 信号驱动

  • 如果program在clk到来时驱动信号,那么信号会立即驱动到DUT(因为program是软件,没有延时,且clocking block的驱动output skew默认为#0step)

4.4.4 时钟块信号驱动&延时

  • 时钟块驱动应采用“同步驱动(synchronous drive)”,即“<=”来驱动信号
  • 时钟块接口信号驱动时的延时
    ##2 arbif.cb.request <= 0;
    ② repeat(2) @arbif.cb; arbif.cb.request <= 0;

4.4.5 接口中的双向信号

  • 在接口中声明的inout信号驱动方式有二
    ①连续赋值语句
    ②虚接口(传入program的interface默认即为虚接口)
  • 在接口中的clocking block中列出的inout、input或ouput信号,在SV中可以直接采用过程赋值语句驱动,因为clocking block中的信号是clockvar,SV通过将clockvar关联到接口信号的方式间接进行驱动

4.4.6 program中不能使用always

  • program是软件块,语句顺序一次执行,不符合always的多次执行
  • program在initial执行完即仿真结束(相当于$finish),program中的always需要额外添加$exit才能强制结束
  • program中可以使用initial forever来实现always的功能

4.4.7 时钟发生器

  • 时钟产生应该放在module中,使其拥有一定物理延迟(在program中产生的话,clk会和驱动信号同时到达DUT,在DUT中会产生竞争)
  • 阻塞赋值“=”避免了0时刻产生有效clk沿;非阻塞赋值“<=”设初值后可以在0时刻产生有效clk沿

4.5 模块连接

  • 使用top模块例化interface,DUT,TB从而实现模块连接
  • 隐式端口连接(.*)的使用条件
    ①端口名字相同
    ②端口位宽相同
    ③数据类型兼容

4.6 顶层作用域

  • verilog中只有宏定义可以跨越模块边界创建全局变量
  • SV中引入了编译单元(compilation unit),是和源文件一起编译的一个组合
  • 顶层作用域:即块外的作用域,等同于编译单元作用域(也称$unit)。顶层作用域的成员是全局成员
  • SV可以采用$root或$unit来引用块外成员
  • 顶层常数定义方法有二
    ①定义顶层参数: parameter TIMEOUT = 1000;
    ②const声明: const string time_out_msg = “error: time out”

4.7 程序模块交互

  • program不能例化module,但可以读写访问module中所有信号;module可以例化program,但不能访问program中的信号
  • program中不能有任何层次实例,但是可以调用module中的例程执行不同的动作

4.8 SV断言

绿皮书上这一块写的太简略了,这里转发两位前辈的博客
SV Assertions 断言
SVA 断言语法


在这里插入图片描述


4.9 四端口ATM路由器

ATM(asynchronous) router

4.10 ref端口方向

  • ref参数是对变量的引用(net除外)

4.11 仿真结束

  • initial块结束时,隐性调用$exit标志program结束
  • 当所有program块结束时,隐形调用$finish结束仿真
  • module或program中可以定义finial块指定仿真器退出前需要执行的代码,但不能含事件调度以及任何延时
final command;

4.12 LC3 取指模块定向测试

  • little computer 3(LC3)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值