实验二:四位全加器的验证平台搭建

    技术2024-07-07  72

    1.验证平台结构 2.各功能模块实现 3.makefile脚本集成 4.验证结果展示

    1.验证平台结构

    如下图所示,一个完整的验证平台包括以下几个模块:激励(driver)、待测模块(dut)、监视器(monitor)、参考模型(refm)、比分板(scb)。 本次实验基于四位全加器的前端RTL设计进行验证,具体实现见实验一。 验证平台的结构分为rtl、sim、tb三个目录,具体见验证概述,在脚本集成时需要注意目录结构。

    2.各功能模块实现

    (1)tb_top.v

    `timescale 1ns/1ps module tb_top(); parameter CYCLE = 10; reg clk ; reg rst_n ; wire en; wire [3:0] num1 ; wire [3:0] num2 ; wire cout ; wire [3:0] sum ; //instance adder_4bits DUT ( .clk ( clk ), .rst_n ( rst_n ), .en ( en ), .num1 ( num1 ), .num2 ( num2 ), .cout ( cout ), .sum ( sum ) ); tb_env #(4)ENV ( .clk ( clk ), .rst_n ( rst_n ), .out ( sum ), .cout ( cout ), .in1 ( num1 ), .in2 ( num2 ), .en ( en ) ); initial begin $timeformat(-9,1,"ns",10); #20 clk=1'b0; forever begin #(CYCLE/2) clk=~clk; end end initial begin integer i; rst_n = 1'b0; #20; rst_n = 1'b1; $display("Test starting!"); `include "test.v";//testcase #20ns; ENV.en = 1'b0; #50; $display("Test end!"); $finish; end initial begin $vcdpluson(0,tb_top); //0 means dump all ports in tb_top end endmodule

    (2)tb_env.v

    `timescale 1ns/1ps module tb_env #( parameter DATA_WIDTH =4 )( input clk, input rst_n, input [DATA_WIDTH-1:0] out, input cout, output reg [DATA_WIDTH-1:0] in1, output reg [DATA_WIDTH-1:0] in2, output reg en ); reg mon_en; reg evt; reg [DATA_WIDTH-1:0] mon_in1; reg [DATA_WIDTH-1:0] mon_in2; reg [2:0] mon_op; reg [DATA_WIDTH:0] refm_out; reg [DATA_WIDTH:0] dut_out; reg [31:0] chk_num=0; reg [31:0] failed_num=0; task driver; input [DATA_WIDTH-1:0] a; input [DATA_WIDTH-1:0] b; input [7:0] delay; begin @(posedge clk)begin #2ns; in1 <= a; in2 <= b; en <= 1; if(delay>0)begin @(posedge clk)begin en<=0; repeat(delay-1)@(posedge clk); end end end end endtask initial begin init(); @(posedge rst_n); fork in_monitor(); out_monitor(); refm(); scb(); join end task init(); begin mon_en <= 1'b0; en <= 1'b0; in1 <= 'b0; in2 <= 'b0; end endtask task in_monitor(); begin while(1)begin @(posedge clk)begin mon_in1 <= in1; mon_in2 <= in2; mon_en <= en; evt <= mon_en; end end end endtask task out_monitor(); begin while(1)begin @(posedge clk)begin if(mon_en)begin dut_out <= {cout,out}; end end end end endtask task refm(); begin while(1)begin @(posedge clk)begin if(mon_en)begin refm_out<=mon_in1+mon_in2; end end end end endtask task scb(); begin while(1)begin @(posedge clk)begin if(evt)begin if(refm_out!=dut_out)begin $display("ERROR,%t data compare failed,expect %h,but %h tested",$time,refm_out,dut_out); failed_num=failed_num+1; end else begin $display("%t data compare passed,expect %h,and %h tested",$time,refm_out,dut_out); end chk_num=chk_num+1; end end end end endtask final begin $display("-------------------------------------"); $display("--%0t Total Compare Number is %0d!---",$time,chk_num); if(failed_num==0)begin $display("-------------Test passed-------------"); end else begin $display("-------------Test failed-------------"); end $display("-------------------------------------"); end endmodule

    (3)testcase.v

    //根据不同的功能需求有不同的testcase //此处给出一个简单的例子 begin for(i=0;i<20;i++)begin ENV.driver(i,i*2,2); end end

    (3)adder_4bits.v

    `timescale 1ns/1ps module adder_4bits( input clk, input rst_n, input en, input [3:0] num1, input [3:0] num2, output cout, output [3:0] sum ); wire cout_0; wire cout_1; wire cout_2; adder_1bit adder0 ( .clk ( clk ), .rst_n ( rst_n ), .en ( en ), .num1 ( num1[0] ), .num2 ( num2[0] ), .cin ( 1'b0 ), .cout ( cout_0 ), .sum ( sum[0] ) ); adder_1bit adder1 ( .clk ( clk ), .rst_n ( rst_n ), .en ( en ), .num1 ( num1[1] ), .num2 ( num2[1] ), .cin ( cout_0 ), .cout ( cout_1 ), .sum ( sum[1] ) ); adder_1bit adder2 ( .clk ( clk ), .rst_n ( rst_n ), .en ( en ), .num1 ( num1[2] ), .num2 ( num2[2] ), .cin ( cout_1 ), .cout ( cout_2 ), .sum ( sum[2] ) ); adder_1bit adder3 ( .clk ( clk ), .rst_n ( rst_n ), .en ( en ), .num1 ( num1[3] ), .num2 ( num2[3] ), .cin ( cout_2 ), .cout ( cout ), .sum ( sum[3] ) ); endmodule module adder_1bit( input clk , input rst_n , input en , input num1 , input num2 , input cin , output reg cout , output reg sum ); always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin {cout,sum} = 2'b0; end else if(en==1'b1)begin {cout,sum}=num1+num2+cin; end else begin {cout,sum} = 2'b0; end end /* assign {cout,sum}=num1+num2+cin; */ endmodule

    3.Makefile脚本集成

    本次实验在Linux系统下的VCS完成。为了验证平台可复用,将相关参数及编译命令集成到makefile中

    RTL_PATH=../rtl TB_PATH=../tb SEED=1 #------------------------------------- # DEVICR UNDER TEST #------------------------------------- DUT_SRC += -f ../adder_4bits.v DUT_CMP_OPTIONS += +notimingcheck +nospecify +delay_mode_unit TEST = test_add all: copy comp run copy: cp -rf ../tb/testcase/${TEST}.v ./test.v comp: vcs -sverilog -debug_pp -timescale=1ns/1ps\ -f ../tb/tb_top.v ../tb/tb_env.v ../rtl/adder_4bits.v \ -l comp.log run: ./simv +ntb_random_seed=${SEED} -l test.log dve: dve -vpd vcdplus.vpd& clean: rm -rf csrc simv* *.log ucli* DVE* vcd* test.v

    VCS小结: (1)当编译文件有多个时,需要添加-f选项,否则可能找不到顶层模块 (2)熟悉VCS参数选项,debug_pp,timescale,vpd等 Makefile小结 (1)多行分割符使用"\",目录分隔符使用"/" (2)-l打印日志,方便查看出错的地方

    4.验证结果展示

    (1)在终端打印测试结果

    (2)dve启动波形窗口

    Processed: 0.014, SQL: 9