Migen Generated Verilog всегда сбрасывает сигналы, которые назначены в FSM - PullRequest
0 голосов
/ 25 октября 2019

Внутри migen, если модуль присваивает значение Сигналу внутри конечного автомата, реализованного как migen.genlib.fsm.FSM, тогда сгенерированный Verilog добавит дополнительное назначение к блоку всегда для сброса сгенерированного регистра.

Реализация конечного автомата вручную, а не как migen.genlib.fsm.FSM создает Verilog, где вместо этого назначение сброса помещается в блок if (sys_reset).

Мой вопрос заключается в том, почему это назначение не находится в пределахдобавлен блок сброса, и его можно предотвратить, пока еще используется класс FSM. Это ошибка или намекает на плохой дизайн HDL с моей стороны?

Пример:

Рассмотрим модуль с двумя кнопочными входами и одним светодиодным выходом. Одна кнопка должна включить светодиод, а другая - выключить. Если бы я реализовал это с помощью 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

Обратите внимание на fsmexample0_led <= 1'd0; вблок Always, сбрасывающий светодиод даже после нажатия btn2.

Даже ручная реализация 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, чтобы выводимый Verilog фактически вызывал нежелательное поведение)

...