Внутри 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 фактически вызывал нежелательное поведение)