verilog - 非阻塞分配在 Vivado 仿真中立即分配

标签 verilog system-verilog verification

在实现cordic算法时,我的非阻塞赋值立即分配变量,而不是在一个时钟周期之后。我不知道为什么。我的代码或 Vivado 设计套件有问题吗? 在我的代码中,我需要分配 z[0]z[0] <= angle 。但是,在我的 Vivado 模拟器中,z[0]只是与angle同时变化.

环境:Windows10、Vivado 2020.2默认模拟器

`timescale 1ns/10ps

module cordic_tb #(

)(

);
    localparam real PI = 3.1415926535;
    logic clk,rst_n,en;
    
    logic signed [31:0] step=integer'((3/180.0)*(2.0**31.0));
    logic signed [31:0] angle;
    logic signed [31:0] cosine,sine;
    initial begin
        clk=0;
        en=1;
        forever #50 clk=~clk;
    end
    initial begin
        rst_n=0;
        #100 rst_n=1;
    end
    always_ff @( posedge clk ) begin
        if(!rst_n) angle='0;
        else if(en) angle=angle+step;
    end
    cordic #()
    theCordicInst(clk,rst_n,en,angle,cosine,sine);
    //test 45°
    /*
    initial begin
        clk=0;
        rst_n=1;
        en=1;
        repeat(62)
        begin
            #5 clk = ~clk;
            if(cosine || sine)
            begin
                $display((real'(cosine))*(2.0**(-31.0)));
                $display((real'(sine))*(2.0**(-31.0)));
                $display($sin((45.0/180.0)*3.1415926535)); 
            end
        end
    end
    Cordic #()
    theCordicInst(clk,rst_n,en,32'h20000000,cosine,sine);
    */
endmodule

module cordic #(
    parameter integer DW = 32,
    parameter real K = 0.6
)(
    input wire clk,rst_n,en,
    input wire signed [DW-1:0] angle,
    output logic signed [DW-1:0] cosine,sine
);
    wire signed [DW-1:0] atan_table[0:29];
    logic signed [DW-1:0] x_start,y_start;
    logic signed [DW-1:0] x[0:30],y[0:30],z[0:30];
    wire [1:0] domain;

    assign atan_table[00]=32'b00100000000000000000000000000000;
    assign atan_table[01]=32'b00010010111001000000010100011101;
    assign atan_table[02]=32'b00001001111110110011100001011011;
    assign atan_table[03]=32'b00000101000100010001000111010100;
    assign atan_table[04]=32'b00000010100010110000110101000011;
    assign atan_table[05]=32'b00000001010001011101011111100001;
    assign atan_table[06]=32'b00000000101000101111011000011110;
    assign atan_table[07]=32'b00000000010100010111110001010101;
    assign atan_table[08]=32'b00000000001010001011111001010011;
    assign atan_table[09]=32'b00000000000101000101111100101110;
    assign atan_table[10]=32'b00000000000010100010111110011000;
    assign atan_table[11]=32'b00000000000001010001011111001100;
    assign atan_table[12]=32'b00000000000000101000101111100110;
    assign atan_table[13]=32'b00000000000000010100010111110011;
    assign atan_table[14]=32'b00000000000000001010001011111001;
    assign atan_table[15]=32'b00000000000000000101000101111100;
    assign atan_table[16]=32'b00000000000000000010100010111110;
    assign atan_table[17]=32'b00000000000000000001010001011111;
    assign atan_table[18]=32'b00000000000000000000101000101111;
    assign atan_table[19]=32'b00000000000000000000010100010111;
    assign atan_table[20]=32'b00000000000000000000001010001011;
    assign atan_table[21]=32'b00000000000000000000000101000101;
    assign atan_table[22]=32'b00000000000000000000000010100010;
    assign atan_table[23]=32'b00000000000000000000000001010001;
    assign atan_table[24]=32'b00000000000000000000000000101000;
    assign atan_table[25]=32'b00000000000000000000000000010100;
    assign atan_table[26]=32'b00000000000000000000000000001010;
    assign atan_table[27]=32'b00000000000000000000000000000101;
    assign atan_table[28]=32'b00000000000000000000000000000010;
    assign atan_table[29]=32'b00000000000000000000000000000001;

    assign x_start= integer'(K*(2.0**(DW-1.0)));
    assign y_start='0;
    assign domain=angle[31:30];

    // convert angle to -pi/2 ~ pi/2, xy start point changes too
    always_ff @( posedge clk ) begin
        if(~rst_n)
        begin
            x[0] <= '0;
            y[0] <= '0;
            z[0] <= '0;
        end
        else if(en)
        begin
            case(domain)
                2'b00,
                2'b11:
                begin
                    x[0] <=  x_start;
                    y[0] <=  y_start;
                    z[0] <= angle;
                end
                2'b01:
                begin
                    x[0] <= -y_start;
                    y[0] <=  x_start;
                    z[0] <= {2'b00,angle[29:0]};
                end
                2'b10:
                begin
                    x[0] <=  y_start;
                    y[0] <= -x_start;
                    z[0] <= {2'b11,angle[29:0]};
                end
            endcase
        end
    end
    generate
        for(genvar i=0;i<30;i=i+1)
        begin:xyz
            wire s=z[i][31];
            wire signed [DW-1:0] x_shr=x[i]>>>i;
            wire signed [DW-1:0] y_shr=y[i]>>>i;

            always_ff @( posedge clk ) begin
                if(~rst_n)
                begin
                    x[i+1] <= '0;
                    y[i+1] <= '0;
                    z[i+1] <= '0;
                end
                else if(en)
                begin
                    x[i+1] <= s ? x[i]+y_shr : x[i]-y_shr;
                    y[i+1] <= s ? y[i]-x_shr : y[i]+x_shr;
                    z[i+1] <= s ? z[i]+atan_table[i] : z[i]-atan_table[i];
                end
            end
        end
    endgenerate
    assign cosine=x[30];
    assign sine  =y[30];
endmodule

enter image description here

最佳答案

verilog 仿真中的

非阻塞分配始终在当前时钟周期分配数据。唯一的区别是它在所有阻塞分配完成后分配数据。

就您的情况而言,您有两个陈述:

always_ff @( posedge clk ) begin
     angle=angle+step;
end

always_ff @( posedge clk ) begin
     z[0] <= angle;

在“posege clk”处,您会发生两个事件:

  1. 立即阻止分配更新角度
  2. 非阻塞分配计划更新为 z[0] 并使用上面更新的角度值。
  3. 将值赋给z[0]

verilog 保证“阻塞”首先发生。因此,您的 z[0] 将遵循角度

如果将第一个分配更改为非阻塞

always_ff @( posedge clk ) begin
     angle<=angle+step;
end

将会发生以下情况:

  1. 非阻塞分配计划在所有阻塞分配之后更新至角度。它的值不会立即改变。
  2. 非阻塞分配计划更新为z[0],但它将使用尚未更新的角度值。
  3. 使用在阻塞分配区域中计算的值来更新角度z[0]的值。

现在,z[0] 包含 angle 的旧值,并且 angle 已更新为新值。这模拟了链式触发器的行为,这就是在所有状态设备中使用 nbas 的原因。

关于verilog - 非阻塞分配在 Vivado 仿真中立即分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68464649/

相关文章:

system-verilog - UVM:驱动程序和程序分配的非法组合警告

system-verilog - 关于 event.triggered 使用的困惑

python - 用于验证来自 Google 安全浏览 API 的更新的代码

algorithm - 验证从应用程序到 Web 服务的答案,反之亦然

verilog - 为什么有模块时在verilog中使用函数

verilog - 是否存在任何开源、完整的系统 verilog 语法?

system-verilog - 系统 verilog 断言中 -> 和 => 之间有什么区别?

jquery - 在 jQuery 中使用 $.ajax 时,如何故意在加载的文档中抛出错误?

verilog - 无法理解 D 触发器代码中的错误

verilog - 获取设计中的信号名称(使用 VPI 调用)