Migen生成的Verilog总是重置在FSM中分配的信号

2024-06-25 23:30:24 发布

您现在位置:Python中文网/ 问答频道 /正文

在migen中,如果一个模块将一个值赋给有限状态机中的一个信号,这个有限状态机被实现为migen.genlib.fsm.FSM,那么生成的Verilog将向always块附加一个额外的赋值,以重置生成的寄存器。你知道吗

手动实现状态机而不是作为migen.genlib.fsm.FSM生成Verilog,其中重置赋值被放在if (sys_reset)块中。你知道吗

我的问题是,为什么这个赋值不在reset块中,并且在仍然使用FSM类的情况下可以阻止它。这是一个bug,还是暗示我的HDL设计不好?你知道吗

示例:

考虑一个具有两个按钮输入和一个LED输出的模块。一个按钮可以打开LED,一个按钮可以关闭LED。如果我要用FSM实现这一点,我可能会尝试:

from migen import *
from migen.fhdl import *

class FSMExample(Module):
    def __init__(self):
        # declare signals
        self.led = Signal()
        self.btn1 = Signal()
        self.btn2 = Signal()
        # define I/O
        self.ios = {self.led, self.btn1, self.btn2}
        self.fsm = FSM(reset_state="OFF")
        self.fsm.act("OFF",
            If(self.btn1, self.led.eq(1), NextState("ON"))
        )
        self.fsm.act("ON",
            If(self.btn2, self.led.eq(0), NextState("OFF"))
        )
        self.submodules += self.fsm

然而,这会生成(使用verilog.convert(FSMExample(),FSMExample().ios)以下verilog:

module top(
    input led,
    input btn1,
    input btn2,
    input sys_clk,
    input sys_rst
);

reg fsmexample0_led;
reg fsmexample0_btn1 = 1'd0;
reg fsmexample0_btn2 = 1'd0;
reg state = 1'd0;
reg next_state;

// synthesis translate_off
reg dummy_s;
initial dummy_s <= 1'd0;
// synthesis translate_on


// synthesis translate_off
reg dummy_d;
// synthesis translate_on
always @(*) begin
    fsmexample0_led <= 1'd0;
    next_state <= 1'd0;
    next_state <= state;
    case (state)
        1'd1: begin
            if (fsmexample0_btn2) begin
                fsmexample0_led <= 1'd0;
                next_state <= 1'd0;
            end
        end
        default: begin
            if (fsmexample0_btn1) begin
                fsmexample0_led <= 1'd1;
                next_state <= 1'd1;
            end
        end
    endcase
// synthesis translate_off
    dummy_d <= dummy_s;
// synthesis translate_on
end

always @(posedge sys_clk) begin
    state <= next_state;
    if (sys_rst) begin
        state <= 1'd0;
    end
end

endmodule

注意always块中的fsmexample0_led <= 1'd0;,即使在按下btn2之后也会重置LED。你知道吗

即使手动实现FSM也可以修复这种行为:

class FakeFSMExample(Module):
    def __init__(self):
        # declare signals
        self.led = Signal()
        self.btn1 = Signal()
        self.btn2 = Signal()
        self.state = Signal()
        self.next_state = Signal()
        # define I/O
        self.ios = {self.led, self.btn1, self.btn2}
        self.sync += self.state.eq(self.next_state)
        self.sync += If(~self.state,
                If(self.btn1, self.led.eq(1), self.next_state.eq(1))
            ).Elif(self.state,
                If(self.btn2, self.led.eq(0), self.next_state.eq(0))
            )

生成

module top(
    input led,
    input btn1,
    input btn2,
    input sys_clk,
    input sys_rst
);

reg fakefsmexample0_led = 1'd0;
reg fakefsmexample0_btn1 = 1'd0;
reg fakefsmexample0_btn2 = 1'd0;
reg fakefsmexample0_state = 1'd0;
reg fakefsmexample0_next_state = 1'd0;


always @(posedge sys_clk) begin
    fakefsmexample0_state <= fakefsmexample0_next_state;
    if ((~fakefsmexample0_state)) begin
        if (fakefsmexample0_btn1) begin
            fakefsmexample0_led <= 1'd1;
            fakefsmexample0_next_state <= 1'd1;
        end
    end else begin
        if (fakefsmexample0_state) begin
            if (fakefsmexample0_btn2) begin
                fakefsmexample0_led <= 1'd0;
                fakefsmexample0_next_state <= 1'd0;
            end
        end
    end
    if (sys_rst) begin
        fakefsmexample0_led <= 1'd0;
        fakefsmexample0_state <= 1'd0;
        fakefsmexample0_next_state <= 1'd0;
    end
end

endmodule

其中fakefsmexample0_led <= 1'd0根据需要住在if (sys_rst)内。你知道吗

编辑:稍微修改示例,在If语句中分配LED,使输出的Verilog实际产生不需要的行为)


Tags: selfinputledifsysregnextend