Verilog实现信号对齐,并且打一拍。以及测试文件中阻塞赋值和非阻塞赋值的区别。

实现功能:

在这里插入图片描述在这里插入图片描述

标题首先我遇到的问题是,所有信号变化与时钟上升沿对齐,所以时钟上升沿时候,这些信号该如何取值?

以第三个时钟上升沿为例,a信号在这一时刻该取1还是取2?
a信号在第三个时钟上升沿前一点时间取值,所以a信号取值为1;同理,b信号取值为3,c信号取值为5,d信号取值为2.
也就是说在时钟上升沿时刻,一般信号采样会采该信号前面一点点时刻所对应的值。

如何打一拍

“打一拍”是指信号延迟一个时钟周期。
我们可以看到,vld_out是vld_in打一拍输出后的结果,那么如何进行打拍呢?
使用D触发器即可实现打一拍。

always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
    vld_out<=1'b0;
else 
    vld_out<=vld_in;
end

设计文件代码

该代码上述功能要求:

module four_data_multiply(
clk    ,
rst_n  ,
vld_in ,
a      ,
b      ,
c      ,
d      ,
vld_out,
dout
);

//参数定义
parameter      DATA_W =         4;
parameter      DATA_O_W =      16;

//输入信号定义
input               clk    ;
input               rst_n  ;
input               vld_in ;
input[DATA_W-1:0]   a      ;
input[DATA_W-1:0]   b      ;
input[DATA_W-1:0]   c      ;
input[DATA_W-1:0]   d      ;
//输出信号定义
output[DATA_O_W-1:0]  dout ;
output              vld_out;
//输出信号reg定义
reg   [DATA_O_W-1:0]  dout   ;
reg                 vld_out; 
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
     dout<=1'b0;
end
else begin   
     dout<=a*b*c*d;      
end
end

always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
    vld_out<=1'b0;
else 
    vld_out<=vld_in;
end
endmodule

测试文件中阻塞赋值和非阻塞赋值区别

在Verilog眼中无论testbench、dut还是assertion都是code。

所以先把code吃进来,然后有一个时间轴参数,仅仅处理set t = 0时刻的code.这个code有阻塞语句、$display、assignment…0时刻还有#0语句、在处理非阻塞的LHS、最后monitor语句。

当我的测试文件是使用非阻塞赋值

`timescale 1ns / 1ps
module testBench(

    );
    reg        clk   ;
    reg        rst_n ;
    reg        vld_in;
    reg[3:0]   a     ;
    reg[3:0]   b     ;
    reg[3:0]   c     ;
    reg[3:0]   d     ;
    wire[15:0] dout  ;
    parameter CYCLE=10   ; 
    parameter RST_TIME=2 ;
    four_data_multiply test(
    .clk(clk)   ,
    .rst_n(rst_n)  ,
    .vld_in(vld_in) ,
    .a(a)      ,
    .b(b)      ,
    .c(c)      ,
    .d(d)     ,
    .vld_out(vld_out),
    .dout(dout)
    );
    initial begin
        clk=1;
        #1;
        forever #(CYCLE/2)clk=~clk;
    end
    
    initial begin
        rst_n=1;
        #(1) rst_n=0;
        #(RST_TIME) rst_n=1;
    end
    integer i;
    initial begin 
        #(1);
        for(i=0;i<6;i=i+1)begin 
            #(CYCLE);
            a<=i;
            b<=i+1;
            c<=i+2;
            d<=i+3;
        end  
    end
    
    initial begin
        vld_in<=0;
        #(CYCLE*2+1);
        vld_in<=1;  
        #(CYCLE*2);
        vld_in<=0;
        #(CYCLE*1);
        vld_in<=1;
        #(CYCLE*1);
        vld_in<=0;
    end
endmodule

然后我的仿真结果如下所示:
在这里插入图片描述可以完成该要求。

当我的测试文件使用阻塞赋值:

`timescale 1ns / 1ps
module testBench(

    );
    reg        clk   ;
    reg        rst_n ;
    reg        vld_in;
    reg[3:0]   a     ;
    reg[3:0]   b     ;
    reg[3:0]   c     ;
    reg[3:0]   d     ;
    wire[15:0] dout  ;
    parameter CYCLE=10   ; 
    parameter RST_TIME=2 ;
    four_data_multiply test(
    .clk(clk)   ,
    .rst_n(rst_n)  ,
    .vld_in(vld_in) ,
    .a(a)      ,
    .b(b)      ,
    .c(c)      ,
    .d(d)     ,
    .vld_out(vld_out),
    .dout(dout)
    );
    initial begin
        clk=1;
        #1;
        forever #(CYCLE/2)clk=~clk;
    end
    
    initial begin
        rst_n=1;
        #(1) rst_n=0;
        #(RST_TIME) rst_n=1;
    end
    integer i;
    initial begin 
        #(1);
        for(i=0;i<6;i=i+1)begin 
            #(CYCLE);
            a=i;
            b=i+1;
            c=i+2;
            d=i+3;
        end  
    end
    
    initial begin
        vld_in=0;
        #(CYCLE*2+1);
        vld_in=1;
        #(CYCLE*2);
        vld_in=0;
        #(CYCLE*1);
        vld_in=1;
        #(CYCLE*1);
        vld_in=0;
    end
endmodule

仿真结果如下:
在这里插入图片描述可以看出,虽然我在设计文件里写了打拍节奏,然而依然没有实现打拍。

原因如下:

在Verilog眼中无论testbench、dut还是assertion都是code。所以先把code吃进来,然后有一个时间轴参数,仅仅处理set t = 0时刻的code.这个code有阻塞语句、$display、assignment…0时刻还有#0语句、在处理非阻塞的LHS、最后monitor语句。
所以当使用阻塞赋值时,在时钟上升沿时,首先执行阻塞赋值,然后信号采样阻塞赋值的结果。
所以当使用非阻塞赋值时,在时钟上升沿时,信号采样非阻塞赋值的前一时刻的结果,等到采样结束,才执行非阻塞赋值的LHS。


版权声明:本文为kongbeiruhai原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。