【问题标题】:Behavioral algorithms (GCD) in Verilog - possible?Verilog 中的行为算法 (GCD) - 可能吗?
【发布时间】:2014-05-31 00:21:59
【问题描述】:

我想为 GCD 计算编写一个模块,使用扩展的欧几里得算法。但主要问题是我完全不知道如何在不达到最低(RTL)级别的情况下做到这一点。我的意思是让 FSM 具有三种状态:

  1. 空闲(等待输入)
  2. 计算(需要多少时钟周期)
  3. 已完成(准备读取输出)。

但是,当我尝试将 FSM 和计算分成单独的进程时,如下所示:

module modinv(clk, reset, number, prime, finished, gcd, inverse_fail, inverse);

    input [31:0] number, prime;
    input wire clk, reset;

    output integer gcd, inverse;
    output reg finished, inverse_fail;

    parameter [2:0] IDLE = 3'b001, COMPUTING = 3'b010, END = 3'b100;
    reg [2:0] state, state_next;

    integer a, b, c, q, p, r;

    always @ (posedge clk, posedge reset)
    begin
        if (reset == 1)
            begin
                state <= IDLE;
            end
        else
            begin              
                state <= state_next;
            end
    end

    always @(state or b)
    begin
        finished <= 0;
        inverse_fail <= 0;

        case (state)
            IDLE:
                begin
                    a <= number;
                    b <= prime;
                    p <= 1;
                    r <= 0;
                    state_next <= COMPUTING;
                end
            COMPUTING:
                begin
                    c = a % b;
                    q = a / b;
                    a = b;
                    b = c;
                    r = p - q * r;
                    p = r;

                    if (b == 0)
                        begin
                            state_next <= END;
                        end
                    else
                        begin
                            state_next <= COMPUTING;
                        end
                end
            END:
                begin
                    gcd <= a;
                    inverse <= p;
                    finished <= 1;
                    if (gcd != 1)
                        begin
                            inverse_fail <= 1;
                        end
                end
        endcase
    end

endmodule

当我尝试将计算放在第二个进程中时,在 COMPUTING 状态的情况下,它只工作一次 - 在 verilog 中是正确的,因为在计算完成之前,状态不会改变,所以进程是' t 再次调用。

但是,当我将计算放在第一个进程中时,没有任何不丑的方法可以将计算限制为仅纠正 STATE,这会导致错误输出(一旦 FSM 处于 FINISHED 状态,输出为已经不正确 - 更进一步)。

所以,我的问题是 - 如何在不使用 FSM + 数据路径(低级 RTL)解决方案的情况下正确地做到这一点?

我现在的波形:

【问题讨论】:

  • 请展示你目前拥有的东西。尝试将always @ (state) 更改为always @*
  • 已更新代码和波形

标签: verilog hdl register-transfer-level


【解决方案1】:

您的设计中似乎缺少一些时钟元素。

根据我对您的设计的了解,您似乎期望一旦状态进入 COMPUTING,它应该继续迭代 ab 的值,直到 b 达到 0。但是 only 你实际上在时钟边沿计时的是状态变量,因此从一个状态到下一个状态没有 a 和 b 的记忆。如果您希望像 ab 这样的变量在一个时钟周期到下一个时钟周期之间具有内存,那么您还需要锁存这些变量:

我对你的程序做了一些修改,它可能不是 100% 正确,但你应该明白我的意思。看看这是否有意义,您如何在第二个块中执行组合逻辑,但是您在 posedge 上注册值,以便您可以在下一个时钟周期开始时使用它们。

module modinv(clk, reset, number, prime, finished, gcd, inverse_fail, inverse);

    input [31:0] number, prime;
    input wire clk, reset;

    output integer gcd, inverse;
    output reg finished, inverse_fail;

    parameter [2:0] IDLE = 3'b001, COMPUTING = 3'b010, END = 3'b100;
    reg [2:0] state, state_next;

    integer a, b, c, q, p, r;
    integer a_next, b_next, p_next, r_next;

    always @ (posedge clk, posedge reset)
    begin
        if (reset == 1)
            begin
                state <= IDLE;
                a <= 0;
                b <= 0;
                p <= 0;
                r <= 0;
            end
        else
            begin              
                state <= state_next;
                a     <= a_next;
                b     <= b_next;
                p     <= p_next;
                r     <= r_next;
            end
    end

    always @* //just use the auto-triggered '@*' operator
    begin
        finished <= 0;
        inverse_fail <= 0;

        case (state)
            IDLE:
                begin
                    a_next <= number;
                    b_next <= prime;
                    p_next <= 1;
                    r_next <= 0;
                    state_next <= COMPUTING;
                end
            COMPUTING:
                begin
                    c = a % b;
                    q = a / b;
                    a_next = b;
                    b_next = c;
                    r_next = p - q * r;
                    p_next = r;

                    if (b == 0)
                        begin
                            state_next <= END;
                        end
                    else
                        begin
                            state_next <= COMPUTING;
                        end
                end
            END:
                begin
                    gcd <= a;
                    inverse <= p;
                    finished <= 1;
                    if (gcd != 1)
                        begin
                            inverse_fail <= 1;
                        end
                end
        endcase
    end

endmodule

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 2018-05-02
    • 2014-02-23
    • 1970-01-01
    • 2013-02-09
    相关资源
    最近更新 更多