使用无限循环扫描和更新输出信号是否是好的编程风格
is it good programming style to use infinite loop to scan and update output signal
我的代码如下:
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
这里我希望 "cState" 信号基于 statemachines.Firstly 被连续扫描和更新我一直尝试 @* 但是因为它只有输出信号 cState 是 updated.So 那个块是只执行一次,因为它没有被修改的输入信号总是@* block.So 我怀疑使用 "infinite for loop" 来服务于连续扫描和更新的目的是否是一件好事
简短的回答是否定的;使用无限循环实现 FSM 不是好的风格。
长答案是这在很大程度上取决于。首先,如果此 FSM 纯粹用于仿真中的功能模型,并且永远不会为 FPGA 或 ASIC 进行综合;您可以使用无限循环来实现 FSM。但是,您应该使用关键字 forever
来实现这些循环,而不是 for (i = 0; ; i = i + 1)
或 while (1)
。或者,如果它们是计时的,您可以使用 always @(posedge clk)
等来触发它们(或者如果它是分叉进程或类似的东西,则使用 forever begin @(posedge clk)
)。
但是,根据该模块的 header,您似乎想要制作一个可综合的 FSM,在这种情况下,您需要做很多工作来修复您的代码。以下是使您的代码可综合并具有更好风格的简短建议列表:
作为一般规则,不要在模块内使用 initial
块。虽然它们有一些有限的用途(在 FPGA 综合中),但您应该在使用它们之前充分了解这些用途。如果您需要一个变量进入初始状态,请在存储该变量的元素中使用重置行(请参阅下一点)
组合逻辑应放在always @*
块中,时序逻辑应放在always @(posedge clk[, negedge rstL])
块中(复位是可选的)。制作状态机时,我推荐如下样式:
reg state, next_state;</p>
<p>// The register that holds the state
always @(posedge clk, negedge rstL) begin
if (~rstL) begin
state <= INIT; // Your starting state here<br>
end
else begin
state <= next_state;<br>
end
end</p>
<p>// The logic that determines the next state and output values based on the inputs and current state
always @* begin
// Defaults<br>
[ Place your outputs here with some default value ]</p>
<p>next_state = state; // As selfloops are common, I typically just set the next state to be the current state</p>
<p>case (state)
[ Your logic for what to do in each state here ]<br>
endcase
end
</pre>
我发现这种形式是确保没有锁存器并使综合工具对简单寄存器块(always @(posedge clk)
块)满意的最佳形式。
- 为状态名称使用参数是一种很好的做法,但您应该在任何地方都使用它们,即使在 case 语句中也是如此,例如:
case (state)
INIT: begin
...
end
READ: begin
...
end
endcase
不要像 x = 1'b0; #10; x = 1'b1;
那样在组合逻辑中使用延迟。您在 initial
块中像这样更改 cState
但实际上每个状态应该有不同的逻辑。
您将 sys_REF_REQ
声明为 inout,而它可能应该是输入。
不要在 non-clock 事物上触发逻辑,例如 always @(posedge sys_REF_REQ)
。仅在可综合代码内的时钟和复位上使用 posedge 和 negedge。
这就是我现在看到的全部内容,但其他人可能会在评论中添加更多内容。祝你好运!
我的代码如下:
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
这里我希望 "cState" 信号基于 statemachines.Firstly 被连续扫描和更新我一直尝试 @* 但是因为它只有输出信号 cState 是 updated.So 那个块是只执行一次,因为它没有被修改的输入信号总是@* block.So 我怀疑使用 "infinite for loop" 来服务于连续扫描和更新的目的是否是一件好事
简短的回答是否定的;使用无限循环实现 FSM 不是好的风格。
长答案是这在很大程度上取决于。首先,如果此 FSM 纯粹用于仿真中的功能模型,并且永远不会为 FPGA 或 ASIC 进行综合;您可以使用无限循环来实现 FSM。但是,您应该使用关键字 forever
来实现这些循环,而不是 for (i = 0; ; i = i + 1)
或 while (1)
。或者,如果它们是计时的,您可以使用 always @(posedge clk)
等来触发它们(或者如果它是分叉进程或类似的东西,则使用 forever begin @(posedge clk)
)。
但是,根据该模块的 header,您似乎想要制作一个可综合的 FSM,在这种情况下,您需要做很多工作来修复您的代码。以下是使您的代码可综合并具有更好风格的简短建议列表:
作为一般规则,不要在模块内使用
initial
块。虽然它们有一些有限的用途(在 FPGA 综合中),但您应该在使用它们之前充分了解这些用途。如果您需要一个变量进入初始状态,请在存储该变量的元素中使用重置行(请参阅下一点)组合逻辑应放在
always @*
块中,时序逻辑应放在always @(posedge clk[, negedge rstL])
块中(复位是可选的)。制作状态机时,我推荐如下样式:
reg state, next_state;</p> <p>// The register that holds the state always @(posedge clk, negedge rstL) begin if (~rstL) begin state <= INIT; // Your starting state here<br> end else begin state <= next_state;<br> end end</p> <p>// The logic that determines the next state and output values based on the inputs and current state always @* begin // Defaults<br> [ Place your outputs here with some default value ]</p> <p>next_state = state; // As selfloops are common, I typically just set the next state to be the current state</p> <p>case (state) [ Your logic for what to do in each state here ]<br> endcase end </pre>
我发现这种形式是确保没有锁存器并使综合工具对简单寄存器块(
always @(posedge clk)
块)满意的最佳形式。
- 为状态名称使用参数是一种很好的做法,但您应该在任何地方都使用它们,即使在 case 语句中也是如此,例如:
case (state)
INIT: begin
...
end
READ: begin
...
end
endcase
不要像
x = 1'b0; #10; x = 1'b1;
那样在组合逻辑中使用延迟。您在initial
块中像这样更改cState
但实际上每个状态应该有不同的逻辑。您将
sys_REF_REQ
声明为 inout,而它可能应该是输入。不要在 non-clock 事物上触发逻辑,例如
always @(posedge sys_REF_REQ)
。仅在可综合代码内的时钟和复位上使用 posedge 和 negedge。
这就是我现在看到的全部内容,但其他人可能会在评论中添加更多内容。祝你好运!