这是真正的FSM吗?

发布于 2025-01-28 06:27:28 字数 3042 浏览 3 评论 0原文

我有一个关于FSM的概念问题,以及以下代码是否为真正的FSM。这是为了我自己的好奇心和对这个主题的理解。当我编写此代码时,我的印象是这是FSM,但现在我不确定。根据我完成的大量阅读,真正的FSM应仅由顺序状态过渡块组成,然后是一个或两个组合块来计算下一个状态和输出逻辑。

我当前的代码合成并在我的Basys3板上工作,所以我知道可能有一个论点“如果它不破产,请不要修复它”,但是现在我已经有一段时间了,因为我可能有不正确的理解关于如何在HDL中编写FSM。

我尝试使用上述格式至少尝试4或5种不同的方法来重写我的代码,但是我似乎在不推断闩锁的情况下无法获得它,这主要是由于使用计数器的使用,而PCKD_BCD需要记住这一事实。它的先前值。

有人可以向我解释为什么这种算法不适合真正的FSM,为什么它适合真正的FSM以及我的误解在哪里,或者如何将其重写为上述格式。

module double_dabble #
    (
    parameter NUM_BITS = 8
    )
    (
    input   wire                    i_clk,
    input   wire                    i_rst,
    input   wire    [NUM_BITS-1:0]  i_binary,
    output  wire    [15:0]          o_pckd_bcd
    );

localparam  s_IDLE      =   3'b000;
localparam  s_SHIFT     =   3'b001;
localparam  s_CHECK     =   3'b010;
localparam  s_ADD       =   3'b011;
localparam  s_DONE      =   3'b100;

reg     [2:0]           state;
reg     [NUM_BITS-1:0]  bin;
reg     [3:0]           count;
reg     [15:0]          pckd_bcd;
reg     [NUM_BITS-1:0]  input_reg;
reg     [15:0]          output_reg;

assign o_pckd_bcd   = output_reg;

always @(posedge i_clk) 
begin
    if(i_rst)
    begin
        state       <= s_IDLE;
        bin         <= 0;
        count       <= 0;
        pckd_bcd    <= 0;
        output_reg  <= 0;
        input_reg   <= 0;
    end

    else
    begin
        input_reg   <= i_binary;
        state       <= s_IDLE;

        // FSM
        case(state)
            s_IDLE :
            begin
                state       <= s_IDLE;
                bin         <= 0;
                count       <= 0;
                pckd_bcd    <= 0;
                if (input_reg!=i_binary)
                begin
                    bin     <= i_binary;
                    state   <= s_SHIFT;
                end
            end

            s_SHIFT :
            begin
                state       <= s_CHECK;
                bin         <= bin<<1;
                count       <= count+1;
                pckd_bcd    <= pckd_bcd<<1;
                pckd_bcd[0] <= bin[NUM_BITS-1];
            end

            s_CHECK :
            begin
                state   <=  s_ADD;
                if(count>=NUM_BITS)
                    state   <=  s_DONE;                                
            end

            s_ADD :
            begin
                state           <= s_SHIFT;
                pckd_bcd[15:12] <= add_three(pckd_bcd[15:12]);
                pckd_bcd[11:8]  <= add_three(pckd_bcd[11:8]);
                pckd_bcd[7:4]   <= add_three(pckd_bcd[7:4]);
                pckd_bcd[3:0]   <= add_three(pckd_bcd[3:0]);
            end

            s_DONE :
            begin
                state       <= s_IDLE;
                output_reg  <= pckd_bcd;
            end
        endcase
    end
end

function [3:0] add_three;
    input   [3:0] bcd;
    if (bcd > 4)
        add_three   = bcd +3;
    else
        add_three   = bcd;
endfunction

endmodule

I have a conceptual question about FSM's and whether or not the following code is a true FSM. This is for my own curiosity and understanding about the subject. When I wrote this code, I was under the impression that this was an FSM, but now I am not so sure. According to a lot of reading I have done, a TRUE FSM should only consist of a sequential state transition block, followed by either one or two combination blocks to calculate the next state and the output logic.

My current code synthesizes and works on my Basys3 board, so I understand there may be an argument for "if it ain't broke, don't fix it" but it's been bugging me for a while now that I may have an incorrect understanding about how to write an FSM in HDL.

I have tried at least 4 or 5 different ways to rewrite my code using the format mentioned above, but I can't seem to get it without inferring latches, mainly due to the use of a counter, and the fact that pckd_bcd needs to remember its previous value.

Could somebody please explain to me either why this algorithm isn't fit for a true FSM, why it is fit for a true FSM and where my misunderstanding is, or how to rewrite this into the format mentioned above.

module double_dabble #
    (
    parameter NUM_BITS = 8
    )
    (
    input   wire                    i_clk,
    input   wire                    i_rst,
    input   wire    [NUM_BITS-1:0]  i_binary,
    output  wire    [15:0]          o_pckd_bcd
    );

localparam  s_IDLE      =   3'b000;
localparam  s_SHIFT     =   3'b001;
localparam  s_CHECK     =   3'b010;
localparam  s_ADD       =   3'b011;
localparam  s_DONE      =   3'b100;

reg     [2:0]           state;
reg     [NUM_BITS-1:0]  bin;
reg     [3:0]           count;
reg     [15:0]          pckd_bcd;
reg     [NUM_BITS-1:0]  input_reg;
reg     [15:0]          output_reg;

assign o_pckd_bcd   = output_reg;

always @(posedge i_clk) 
begin
    if(i_rst)
    begin
        state       <= s_IDLE;
        bin         <= 0;
        count       <= 0;
        pckd_bcd    <= 0;
        output_reg  <= 0;
        input_reg   <= 0;
    end

    else
    begin
        input_reg   <= i_binary;
        state       <= s_IDLE;

        // FSM
        case(state)
            s_IDLE :
            begin
                state       <= s_IDLE;
                bin         <= 0;
                count       <= 0;
                pckd_bcd    <= 0;
                if (input_reg!=i_binary)
                begin
                    bin     <= i_binary;
                    state   <= s_SHIFT;
                end
            end

            s_SHIFT :
            begin
                state       <= s_CHECK;
                bin         <= bin<<1;
                count       <= count+1;
                pckd_bcd    <= pckd_bcd<<1;
                pckd_bcd[0] <= bin[NUM_BITS-1];
            end

            s_CHECK :
            begin
                state   <=  s_ADD;
                if(count>=NUM_BITS)
                    state   <=  s_DONE;                                
            end

            s_ADD :
            begin
                state           <= s_SHIFT;
                pckd_bcd[15:12] <= add_three(pckd_bcd[15:12]);
                pckd_bcd[11:8]  <= add_three(pckd_bcd[11:8]);
                pckd_bcd[7:4]   <= add_three(pckd_bcd[7:4]);
                pckd_bcd[3:0]   <= add_three(pckd_bcd[3:0]);
            end

            s_DONE :
            begin
                state       <= s_IDLE;
                output_reg  <= pckd_bcd;
            end
        endcase
    end
end

function [3:0] add_three;
    input   [3:0] bcd;
    if (bcd > 4)
        add_three   = bcd +3;
    else
        add_three   = bcd;
endfunction

endmodule

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

九歌凝 2025-02-04 06:27:28

通常,您的代码看起来像实现FSM。您有证据表明该设计正在按照董事会的需求工作。

您选择的编码样式(一个始终块)是有效的Verilog方法。另一种常见的FSM编码样式涉及两个始终块:一个顺序和一个组合。 here there FSM不得使用两个始终块中的块。

我在代码中确实注意到的一件事是,您正在同时对state信号进行多个非阻止分配。那是不寻常的。

例如,就在case语句之前,您有:

    state       <= s_IDLE;

然后,在indle case-item中,您具有相同的代码:

            state       <= s_IDLE;

我建议尝试通过添加来清理该码默认 <代码>案例语句。 默认在您的FSM中(如FSM)(如您的FSM)时,也是一个很好的编码练习。您仅定义了8个可能的状态中的5个(state是3位寄存器)。

多个非阻止分配的另一个示例是:

        s_CHECK :
        begin
            state   <=  s_ADD;
            if(count>=NUM_BITS)
                state   <=  s_DONE;                                
        end

将其编码更好地编码为:

        s_CHECK :
        begin
            state <= (count>=NUM_BITS) ? s_DONE : s_ADD;
        end

遵循建议的编码实践会产生更可预测的仿真和综合结果。

In general, your code looks like it implements an FSM. You have evidence that the design is working as desired on your board.

The coding style you have chosen (one always block) is a valid Verilog approach. Another common FSM coding style involves two always blocks: one sequential and one combinational. See here for an example. It is not mandatory for an FSM to use two always blocks in Verilog.

One thing that I do notice in your code is that you are making multiple nonblocking assignments to the state signal at the same time. That is unusual.

For example, right before the case statement, you have:

    state       <= s_IDLE;

Then, in the IDLE case-item, you have the same code:

            state       <= s_IDLE;

I recommend trying to clean that up by adding a default to the case statement. A default is also a good coding practice when you have some undefined states, as in your FSM. You have only defined 5 of the 8 possible states (state is a 3-bit register).

Another example of multiple nonblocking assignments is:

        s_CHECK :
        begin
            state   <=  s_ADD;
            if(count>=NUM_BITS)
                state   <=  s_DONE;                                
        end

That would be better coded as:

        s_CHECK :
        begin
            state <= (count>=NUM_BITS) ? s_DONE : s_ADD;
        end

Following recommended coding practices yields more predictable simulation and synthesis results.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文