接着前文verilog中parameter的计算,用AI来分析一下。

与AI的对话:

提问:以下代码有什么问题吗?
    localparam fclk = 10000000;
    //单位ms
    localparam t = 80;
    localparam B_DDS = 32;
    localparam [63:0]Fcw = (2**B_DDS)*1000/(fclk*t);

    reg over = 0;
    reg [31:0] cnt = 0;
    always@(posedge CLK)begin
        {over,cnt} <= cnt+Fcw[31:0];
    end

AI回答:这段 Verilog 代码在逻辑设计和语法上存在几个比较隐蔽但致命的问题,特别是关于数据溢出和硬件实现可行性。
以下是详细的分析与修正建议:

  1. 核心计算溢出问题
    这是最严重的问题。在计算 Fcw 时,你使用了 ( 2 ∗ ∗ B _ D D S ) ∗ 1000 (2**B\_DDS)*1000 (2B_DDS)1000
    计算过程: 2 32 2^{32} 232 已经是 4,294,967,296,再乘以 1000,结果大约是 4.29 × 10 12 4.29 \times 10^{12} 4.29×1012
    Verilog 限制: 在 Verilog 中,整数字面量默认通常是 32 位。即使你赋值给一个 [63:0] 的位宽,中间计算过程如果没指定位宽,就会在 32 位溢出。
    结果: ( 2 ∗ ∗ 32 ) ∗ 1000 (2**32) * 1000 (232)1000 在 32 位运算下直接变成 0。这会导致你的 Fcw 最终计算结果为 0,累加器永远不会工作。
  2. 位宽匹配与赋值
    在 always 块中,你使用了:
    {over,cnt} <= cnt + Fcw[31:0];
    虽然这在语法上能通过,但将一个 64 位的参数 Fcw 截断为 32 位赋给累加器,配合上述的计算溢出,逻辑上基本是失效的。
  3. 本地参数计算的精度
    Verilog 的 localparam 在进行除法时是取整运算。
    f c l k = 10 7 fclk = 10^7 fclk=107
    t = 80 t = 80 t=80
    f c l k × t = 10 7 × 80 = 800 , 000 , 000 fclk \times t = 10^7 \times 80 = 800,000,000 fclk×t=107×80=800,000,000
    如果分子计算正确(处理了 64 位),结果如果不是整数,小数部分会丢失,导致计时不准。

老三点评
第一点说 ( 2 ∗ ∗ B _ D D S ) ∗ 1000 (2**B\_DDS)*1000 (2B_DDS)1000溢出了,计算结果是0,但是我用modelsim仿真,显示Fcw的值为5368。
在这里插入图片描述
第三点说计时不准,下面验证。

AI接着建议了修改方案:

如果你是想实现一个在 80ms 内完成 32 位累加器翻转的逻辑,建议按以下方式修改:


    // 明确指定 64 位常数,防止中间过程溢出
    localparam [63:0] FCLK_HZ = 10_000_000; 
    localparam [63:0] T_MS    = 80;
    localparam [63:0] B_DDS   = 32;

    // 重新调整计算顺序,先乘后除,并强制 64 位运算
    // 公式:(2^32 * 1000) / (fclk * t)
    localparam [63:0] Fcw = (64'd1 << B_DDS) * 64'd1000 / (FCLK_HZ * T_MS);

    reg [31:0] cnt = 0;
    reg over = 0;

    always @(posedge CLK) begin
        // 使用 33 位运算来捕获进位
        {over, cnt} <= cnt + Fcw[31:0];
    end

改进点说明:

  • 强制位宽: 使用 64’d1 << B_DDS 和 64’d1000 强制编译器进入 64 位运算模式。
  • 可读性: 使用 _ 分隔数字(如 10_000_000)提高代码可读性。

老三点评:这段程序经过上板验证,功能正常。
dds产生的计时确实有抖动,通过上板测试发现计时时钟个数 c n t 1 cnt1 cnt1在800104和800105之间跳动:
在这里插入图片描述
在这里插入图片描述

让AI写个testbench:
在这里插入图片描述
仿真结果:
在这里插入图片描述

最后附上完整代码:

`timescale 1ns / 1ps
module dds#(
    parameter WIDTH_CNT = 32
)(
    input clk,

    output [WIDTH_CNT-1:0]cnt_time,
    output pulse

    );

    // 明确指定 64 位常数,防止中间过程溢出
    localparam [63:0] FCLK_HZ = 10_000_000;
    localparam [63:0] T_MS    = 80;
    localparam [63:0] B_DDS   = 32;

    // 重新调整计算顺序,先乘后除,并强制 64 位运算
    // 公式:(2^32 * 1000) / (fclk * t)
    localparam [63:0] Fcw = (64'd1 << B_DDS) * 64'd1000 / (FCLK_HZ * T_MS);

    reg [31:0] cnt = 0;
    reg over = 0;

    always @(posedge clk) begin
        // 使用 33 位运算来捕获进位
        {over, cnt} <= cnt + Fcw[31:0];
    end

    assign pulse = over;

    wire rst_cnt;
    wire add_cnt;
    wire end_cnt;
	//用cnt1检测dds的抖动
    reg [31:0] cnt1 = 0;
    always@(posedge clk)begin
        if(rst_cnt)
            cnt1 <= 0;
        else if(add_cnt)
            if(end_cnt)
                cnt1 <= 0;
            else
                cnt1 <= cnt1 + 1;
    end
    assign rst_cnt = 0;
    assign add_cnt = 1;
    assign end_cnt = add_cnt && (over);

    assign cnt_time = cnt1;

endmodule

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐