使用无限循环扫描和更新输出信号是一种好的编程风格吗 [英] is it good programming style to use infinite loop to scan and update output signal
问题描述
我的代码如下:
模块命令_FSM(sys_R_Wn,sys_ADSn,cState,sys_REF_REQ,sys_REF_ACK,sys_INIT_DONE,sys_CLK);输入 sys_R_Wn;输入 sys_CLK;输入 sys_ADSn;输出 [4:0] cState;输入 sys_INIT_DONE;输入 sys_REF_REQ;输出 sys_REF_ACK;线 sys_R_Wn;线 sys_ADSn;reg [4:0] cState;线 sys_INIT_DONE;线 sys_REF_REQ;reg sys_REF_ACK;reg mjet;整数 i;参数 c_idle=5'b10000;参数 c_AR=5'b10001;参数 c_tRFC=5'b10010;参数 c_rdata=5'b10011;参数 c_tDAL=5'b10100;参数 c_cl=5'b10101;参数 c_ACTIVE=5'b10110;参数 c_wdata=5'b10111;参数 c_REDA=5'b11000;参数 c_tRCD=5'b11001;参数 c_WRITEA=5'b11010;最初的开始cState=c_idle;结尾最初的开始for(i=0;;i=i+1)开始#2;如果 (sys_INIT_DONE==1'b1)if(~sys_REF_REQ &&~sys_ADSn)开始案例(cState)5'b10000:开始cState=c_ACTIVE;#10;结尾5'b10110:如果(sys_R_Wn)开始cState=c_tRCD;#10;cState=c_REDA;结尾别的开始cState=c_tRCD;#10;cState=c_WRITEA;结尾5'b11000:开始cState=c_cl;结尾5'b10101:开始cState=c_rdata;结尾5'b11010:开始cState=c_wdata;结尾5'b10111:开始cState=c_tDAL;结尾尾箱结尾结尾结尾总是@(posedge sys_REF_REQ)开始sys_REF_ACK=1;案例(cState)5'b10000:开始cState=c_AR;#50;cState=c_idle;结尾尾箱结尾结束模块
在这里,我希望根据状态机不断扫描和更新cState"信号.首先,我总是尝试@*,但因为它只有输出信号 cState 要更新.所以该块只执行一次,因为它没有输入在那个总是@* 块中被修改的信号.所以我怀疑使用无限循环"来实现连续扫描和更新的目的是好事
简短的回答是否定的;使用无限循环实现 FSM 不是一个好风格.
答案很长,这在很大程度上取决于.首先,如果这个 FSM 纯粹是用于仿真中的功能模型,而不是为 FPGA 或 ASIC 合成的;您可能会使用无限循环来实现 FSM.但是,您应该使用关键字 forever
来实现这些循环,而不是 for (i = 0; ; i = i + 1)
或 while (1)代码>.或者,如果它们被计时,你可以使用
always @(posedge clk)
或类似的来触发它们(或者使用 forever begin @(posedge clk)
如果它是一个分叉进程或类似的东西).
但是,根据此模块的标题,您似乎想要制作一个可综合的 FSM,在这种情况下,您需要做很多事情来修复您的代码.下面是一个简短的建议列表,可让您的代码具有可综合性并具有更好的风格:
作为一般规则,不要在模块内使用
initial
块.虽然它们的用途有限(在 FPGA 综合中),但在使用它们之前,您应该充分了解这些用途.如果您需要一个变量呈现初始状态,请在存储该变量的元素中使用重置行(请参阅下一点)组合逻辑应该放在
always @*
块中,顺序逻辑应该放在always @(posedge clk[, negedge rstL])
阻止(重置是可选的).在做状态机的时候,我推荐以下风格:
reg state, next_state;//保存状态的寄存器总是@(posedge clk, negedge rstL) 开始如果 (~rstL) 开始状态 <= INIT;//这里是你的起始状态
结尾否则开始状态 <= next_state;
结尾结束
//根据输入和当前状态确定下一个状态和输出值的逻辑总是@* 开始//默认值
[将您的输出放在此处并使用一些默认值]
next_state = 状态;//由于自循环很常见,我通常只是将下一个状态设置为当前状态
案例(状态)[你在每个州做什么的逻辑]
尾箱结尾
我发现这种形式是最好的,可以确保没有锁存器,并使综合工具对简单的寄存器块(always @(posedge clk)
块)感到满意.
- 为状态名称使用参数是一种很好的做法,但您应该在任何地方使用它们,即使是在 case 语句中,例如:
不要在你的组合逻辑中使用延迟,比如
x = 1'b0;#10;x = 1'b1;
.您可以在initial
块中像这样更改cState
,但实际上每个状态应该有不同的逻辑.当
sys_REF_REQ
应该是输入时,您将它声明为输入.不要在非时钟事物上触发逻辑,例如
总是@(posedge sys_REF_REQ)
.仅在可综合代码中对时钟和复位使用posedge 和negedge.
我现在看到的就是这些,但其他人可能会在评论中添加更多内容.祝你好运!
my code is as follows:
module command_FSM(sys_R_Wn,sys_ADSn,cState,sys_REF_REQ,sys_REF_ACK,sys_INIT_DONE,sys_CLK);
input sys_R_Wn;
input sys_CLK;
input sys_ADSn;
output [4:0] cState;
inout sys_INIT_DONE;
input sys_REF_REQ;
output sys_REF_ACK;
wire sys_R_Wn;
wire sys_ADSn;
reg [4:0] cState;
wire sys_INIT_DONE;
wire sys_REF_REQ;
reg sys_REF_ACK;
reg mjet;
integer i;
parameter c_idle=5'b10000;
parameter c_AR=5'b10001;
parameter c_tRFC=5'b10010;
parameter c_rdata=5'b10011;
parameter c_tDAL=5'b10100;
parameter c_cl=5'b10101;
parameter c_ACTIVE=5'b10110;
parameter c_wdata=5'b10111;
parameter c_REDA=5'b11000;
parameter c_tRCD=5'b11001;
parameter c_WRITEA=5'b11010;
initial
begin
cState=c_idle;
end
initial
begin
for(i=0;;i=i+1)
begin
#2;
if (sys_INIT_DONE==1'b1)
if(~sys_REF_REQ && ~sys_ADSn)
begin
case (cState)
5'b10000: begin
cState=c_ACTIVE;
#10;
end
5'b10110:
if(sys_R_Wn)
begin
cState=c_tRCD;
#10;
cState=c_REDA;
end
else
begin
cState=c_tRCD;
#10;
cState=c_WRITEA;
end
5'b11000: begin
cState=c_cl;
end
5'b10101: begin
cState=c_rdata;
end
5'b11010: begin
cState=c_wdata;
end
5'b10111: begin
cState=c_tDAL;
end
endcase
end
end
end
always @(posedge sys_REF_REQ)
begin
sys_REF_ACK=1;
case(cState)
5'b10000: begin
cState=c_AR;
#50;
cState=c_idle;
end
endcase
end
endmodule
here i want "cState" signal to be scanned and updated continuously based on statemachines.Firstly i tried always @* but as it had only output signal cState to be updated.So that block was executed only once because it had no input signal that was being modified in that always @* block.So my doubt is is it good thing to use "infinite for loop" to serve that purpose of scanning and updating continuously
The short answer is no; it is not good style to implement FSMs using an infinite loop.
The long answer is that it very much depends. Firstly, if this FSM is purely for a functional model in simulation and never to be synthesized for an FPGA or ASIC; you might use an infinite loop to implement an FSM. However, you should use the keyword forever
to implement these loops, not for (i = 0; ; i = i + 1)
or while (1)
. Or, if they are clocked, you can use an always @(posedge clk)
or the like to trigger them (or use forever begin @(posedge clk)
if its a forked process or something fancy like that).
However, based on the header of this module, it appears you want to make a synthesizable FSM, it which case, theres quite a lot you need to do to fix your code. Heres a short list of suggestions to make your code synthesizable and have better style:
As a general rule, do not use
initial
blocks inside an module. While they have a few limited uses (in FPGA synthesis), you should fully understand those uses before using them. If you need a variable to take on an initial state, use a reset line in the element storing that variable (see the next point)Combinational logic should be placed in an
always @*
block and sequential logic should be placed in analways @(posedge clk[, negedge rstL])
block (the reset is optional). When making a state machine, I recommend the following style:
reg state, next_state;
// The register that holds the state
always @(posedge clk, negedge rstL) begin
if (~rstL) begin
state <= INIT; // Your starting state here
end
else begin
state <= next_state;
end
end
// The logic that determines the next state and output values based on the inputs and current state
always @* begin
// Defaults
[ Place your outputs here with some default value ]
next_state = state; // As selfloops are common, I typically just set the next state to be the current state
case (state)
[ Your logic for what to do in each state here ]
endcase
end
This form I find to be the best to ensure no latches and makes the synthesis tools happy with simple register blocks (the always @(posedge clk)
block).
- Using parameters for state names is good practice, but you should use them everywhere, even in the case statement, like:
case (state)
INIT: begin
...
end
READ: begin
...
end
endcase
Do not use delays in your combinational logic like
x = 1'b0; #10; x = 1'b1;
. You changecState
like this in yourinitial
block but really should have different logic for each state.You declare
sys_REF_REQ
as an inout when it should probably be an input.Don't trigger logic on non-clock things, like
always @(posedge sys_REF_REQ)
. Only use posedge and negedge on clocks and resets within synthesizable code.
Thats all I see right now, but other might add more in the comments. Best of luck!
这篇关于使用无限循环扫描和更新输出信号是一种好的编程风格吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!