synopsys svtb lab1:SystemVerilog Verification Flow

前言:

这是路科的V0课程实验,就是路桑所说的“把大象装进冰箱里”,其实就是Synopsys公司的SV testbench lab(有英文的pdf,要是有这样的指导,就可以对sv验证有个清晰的感知了),如果需要pdf文档,去eetop下载,或者进企鹅群:11427一七989下载。


 设计模块介绍

实验中的待测试模块(DUT)是一个16输入,16输出的路由器,这个路由器的功能是把数据通过各个输入端(Input)发送到任意输出端(Output)。下面是最终完成的整个验证平台示意图。

打开实验文件,你将会看到如下实验代码的结构,其中rtl中为设计代码,labs中为原始代码,solutions中为参考答案。

实验一

在Lab1中我们应该掌握以下内容:

  1. 用SV给待测试模块(DUT)搭建最简单的测试平台(Testbench)。
  2. 用SV写一个任务(Task)来重置(Reset)DUT。
  3. 编译(Compile)和仿真(Simulate)这个SV程序。

我们需要建立的几个文件:顶层(Top)文件:router_test_top.sv ,接口(Interface)文件:router_io.sv ,待测试(DUT)文件:router.v , 测试(Test)文件:test.sv。在该实验完成时,你将得到如下验证结构。

lab overview

constructing systemverilog testbench

使用VCS创建这个SystemVerilog测试平台的过程如下:

  • 创建一个接口来连接测试程序和DUT。
  • 编写测试程序。
  • 使用包含接口的装具文件连接测试和DUT。

 

任务一:进入lab1文件夹

任务二:创建SV接口(interface)文件

1.创建router_io.sv文件,并用编辑器打开它。

//router_io.sv
//文件开始的样子,可以直接拷贝,进行实验


interface router_io(input bit clock);
  logic reset_n;
  logic [15:0] din;
  logic [15:0] frame_n;
  logic [15:0] valid_n;
  logic [15:0] dout;
  logic [15:0] valido_n;
  logic [15:0] busy_n;
  logic [15:0] frameo_n;


  //Lab 1 - Task 2, Step 3
  //
  //Declare a clocking block driven by posedge of signal clock
  //Add all signals required to connect test program to the DUT
  //All directions must be with respect to test program
  //ToDo


    //Lab 1 - Task 2, Step 4
    //
    //Add input and output skew in clocking block(optional)
    //ToDo


  //Lab 1 - Task 2, Step 5
  //
  //Create a modport to connect to test program
  //Arguments should list clocking block and all other potential asynch signals
  //ToDo


endinterface: router

2.以下是需要连接到DUT的信号。

interface router_io(input bit clock);

logic reset_n ;

logic [1 5 :0] din ;

...

logic [1 5 :0 ] frameo_n ;

endinterface: router_io

注意:在这一部分的所有接口都是异步且没有方向的(例如input,output,inout就是有方向)。接口的方向只能在针对同步信号的时钟模块(Clocking block)或是针对异步信号的(modport)中被说明。

 

在下一步中,我们会去创建同步(synchronous)信号给测试程序(test program)从而可以驱动(drive)和采样(sample)DUT中的信号。

 

3.声明一个由时钟上升沿所驱动的时钟模块(Clocking block,以后简称CB)。这个时钟模块将会被测试程序用来实施同步驱动(drive)和采样(sample)。这个CB中的所有信号的方向(direction)必须和DUT中的信号方向一致。

这是dut中的接口,我们需要根据这个来完成端口的声明
input reset_n, clock;
input [15:0] din, frame_n, valid_n;
output [15:0] dout, valido_n, busy_n, frameo_n;

 

 

4.如果需要的话,可以对input和output的(skew)添加说明,就是确保有建立时间和保持时间以避免竞争;

5.最后创建一个modport TB(),来连接这个测试程序。在它的参数(argument)列表中,应该引用我们之前创建的时钟模块CB和其它所有可能会用到的异步(asynchronous)信号。

6.保存并关闭router_io.sv文件。

//router_io.sv
//任务2结束的样子,可以直接拷贝,进行实验
interface router_io(input bit clock);
  logic reset_n;
  logic [15:0] din;
  logic [15:0] frame_n;
  logic [15:0] valid_n;
  logic [15:0] dout;
  logic [15:0] valido_n;
  logic [15:0] busy_n;
  logic [15:0] frameo_n;


  //Lab 1 - Task 2, Step 3
  //
  //Declare a clocking block driven by posedge of signal clock
  //Add all signals required to connect test program to the DUT
  //All directions must be with respect to test program
  //ToDo
  clocking cb @(posedge clock);
default input #1ns output #1ns;
    output reset_n;
output din;
output frame_n;
output valid_n;
input  dout;
input  valido_n;
input  frameo_n;
input  busy_n;
  endclocking: cb


    //Lab 1 - Task 2, Step 4
    //
    //Add input and output skew in clocking block(optional)
    //ToDo


  //Lab 1 - Task 2, Step 5
  //
  //Create a modport to connect to test program
  //Arguments should list clocking block and all other potential asynch signals
  //ToDo
  modport TB(clocking cb, output reset_n);


endinterface: router_io

任务三:创建SV测试程序文件。

1.创建测试程序文件test.sv,并用编辑器打开它。

//test.sv
//最开始的样子,可以直接复制粘贴进行实验

//Lab 1 - Task 3, Step 2
//
//Declare a program block with arguments to connect
//to modport TB declared in interface
//ToDo

  //Lab 1 - Task 3, Step 3
  //
  //Declare an initial block 
  //In the initial block print a simple message to the screen
  //ToDo

  //Lab 1 - Task 6, Steps 3 and 4 -
  //
  //Replace $display() in initial block with $vcdpluson
  //Call reset() task
  //ToDo - Caution!! Do only in Task 6

//Lab 1 - Task 6, Step 2
//
//Define a task called reset() inside the program to reset DUT per spec.
//ToDo - Caution!! Do only in Task6

2.在这个文件中,引用接口模块中的modport TB作为参数(argument),来将interface和test program连接在一起。

program automatic test (router_io . TB rtr_io) ;


endprogram: test

3.在这个程序(program)模块中,在屏幕上输出一个简单的信息;

program automatic test (router_io . TB rtr_io) ;

  initial begin
  $display("Hello World!");  
  end
endprogram: test

4.保存和关闭test.sv文件。

//test.sv
//任务二结束的样子


//Lab 1 - Task 3, Step 2
//
//Declare a program block with arguments to connect
//to modport TB declared in interface
//ToDo
program automatic test(router_io.TB rtr_io);

  //Lab 1 - Task 3, Step 3
  //
  //Declare an initial block 
  //In the initial block print a simple message to the screen
  //ToDo
  initial begin
    $display("Hello World!");
  end
  //Lab 1 - Task 6, Steps 3 and 4 -
  //
  //Replace $display() in initial block with $vcdpluson
  //Call reset() task
  //ToDo - Caution!! Do only in Task 6

//Lab 1 - Task 6, Step 2
//
//Define a task called reset() inside the program to reset DUT per spec.
//ToDo - Caution!! Do only in Task 6
endprogram:test

任务四:创建SV测试的壳文件(即TOP文件)

1.创建和打开router_test_top.sv文件。

//router_test_top.sv
//最开始的样子

//Lab 1 - Task 4, Step 6a
//
//Add `timescale
//ToDo

module router_test_top;
  parameter simulation_cycle = 100;

  bit SystemClock;


  //Lab 1 - Task 4, Step 3
  //
  //Add an interface instance
  //ToDo
  
  //Lab 1 - Task 4, Step 4
  //
  //Instantiate the test program
  //Make I/O connection via interface
  //ToDo


  router dut(
    //Lab 1 - Task 4, Step 5
    //
    //Modify DUT connection to connect via interface
    //ToDo


    .reset_n (reset_n),
    .clock (clock),
    .din (din),
    .frame_n (frame_n),
    .valid_n (valid_n),
    .dout (dout),
    .valido_n (valido_n),
    .busy_n (busy_n),
    .frameo_n (frameo_n)
  );


  initial begin
    //Lab 1 - Task 4, Step 6b
    //
    //Add $timeformat
    //ToDo


    SystemClock = 0;
    forever begin
      #(simulation_cycle/2)
        SystemClock = ~SystemClock;
    end
  end
endmodle

2.上面展示了基本结构。

3.给Top文件中添加接口的实例化(instance)

4.实例化这个测试程序。(通过将测试程序在top中的例化t 和接口在top中的例化top_io相联系,将test程序和Top连接在一起)

5.将待测试模块和top_io连在一起,实现DUT与Top的连接。

此时你有没有发现呢?Top文件中经过三次例化成功将DUT文件,test program文件,interface文件包含了起来。

6.添加`timescale和$timefornat到Top中。

7.保存并关闭router_test_top.sv文件。

//router_test_top.sv
//此处任务结束时的代码效果

//Lab 1 - Task 4, Step 6a
//
//Add `timescale
//ToDo
`timescale 1ns/100ps
module router_test_top;
  parameter simulation_cycle = 100;

  bit SystemClock;

  //Lab 1 - Task 4, Step 3
  //
  //Add an interface instance
  //ToDo
  router_io top_io(SystemClock); 
  //Lab 1 - Task 4, Step 4
  //
  //Instantiate the test program
  //Make I/O connection via interface
  //ToDo
  test t(top_io);
  router dut(
    //Lab 1 - Task 4, Step 5
    //
    //Modify DUT connection to connect via interface
    //ToDo

    .reset_n (top_io.reset_n),
    .clock (top_io.clock),
    .din (top_io.din),
    .frame_n (top_io.frame_n),
    .valid_n (top_io.valid_n),
    .dout (top_io.dout),
    .valido_n (top_io.valido_n),
    .busy_n (top_io.busy_n),
    .frameo_n (top_io.frameo_n)
  );

  initial begin
    //Lab 1 - Task 4, Step 6b
    //
    //Add $timeformat
    //ToDo
    $timeformat(-9,1,"ns",10);
    SystemClock = 0;
    forever begin
      #(simulation_cycle/2)
        SystemClock = ~SystemClock;
    end
  end
endmodule

任务五:编译(compile)和仿真(simulate)

此时,我们一共拥有四个文件:待测试文件:router.v,接口文件:router_io.sv ,测试文件:test.sv , 顶层文件:router_test_top.sv。

1.用VCS编译和仿真

直接使用命令

vcs -sverilog router_test_top.sv test.sv router_io.sv ../../rtl/router.v

会生成simv文件,执行./simv仿真

 

2.用Questasim进行编译和仿真

  • 建立项目

    • 新建项目名称File -> New -> Project,在project name处填入名称例如lab1

 

  • 添加文件和编译

    • 在project窗口单击右键,选择Add to Project -> Existing File,找到下载的lab1实验文件。

 

  • 编译文件。

  • 仿真与添加波形

    • 在Library -> Work中找到顶层router_test_top,点击右键选择“Simulate without Optimization”,这种仿真模式是为了消除仿真器可能会加入的一些优化处理。

 

  • 选中top_io,在objects一栏中可以看到它的端口和内部信号。

 

 

  • 接下来在instance ->router_test_top ->top_io上点击右键,选择Add Wave,这是为了在仿真时存储波形。
  • 在命令窗口中敲入命令“run 1us”或者在工具栏中运行1us。

 

  • 观察波形

 

到这里我们整个验证的最基本框架就建立起来,以后我们会不断向里面填充东西,并将它们标准化,在整个过程结束后我们可以建立起一个完整的验证平台。

 

任务六 重置路由器(Reset the Router)

1.打开test.sv文件,定义一个任务(Task):Reset(),实现重置DUT的功能。

2.在初始化模块中(initial begin),调用reset()任务来重置DUT。(reset_n既可以是同步信号也可以是异步信号

3.在initial block中,用$vcdpluson替换$display(),在仿真时得到波形文件

4.在$vcdpluson后面立马调入reset()任务

5.保存和关闭文件。

//test.sv
//此时的文件

//Lab 1 - Task 3, Step 2
//
//Declare a program block with arguments to connect
//to modport TB declared in interface
//ToDo
program automatic test(router_io.TB rtr_io);

  //Lab 1 - Task 3, Step 3
  //
  //Declare an initial block 
  //In the initial block print a simple message to the screen
  //ToDo
  initial begin
    $vcdpluson;
reset();
  end

  //Lab 1 - Task 6, Steps 3 and 4 -
  //
  //Replace $display() in initial block with $vcdpluson
  //Call reset() task
  //ToDo - Caution!! Do only in Task 6

//Lab 1 - Task 6, Step 2
//
//Define a task called reset() inside the program to reset DUT per spec.
//ToDo - Caution!! Do only in Task 6
task reset();
  rtr_io.reset_n = 1'b0;
  rtr_io.cb.frame_n <= '1;
  rtr_io.cb.valid_n <= '1;
  ##2 rtr_io.cb.reset_n <= 1'b1;
  repeat(15) @(rtr_io.cb);
endtask: reset
endprogram:test

任务七.编译和仿真

A.编译

vcs -sverilog -debug router_test_top.sv test.sv router_io.sv ../../rtl/router.v

-debug这个开关可以结合$vcdpluson函数产生vcdplus.vpd

B.仿真

任务八.用dve查看波形。 


后记:

冲冲冲!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰之行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值