Verilog 使用无限循环扫描和更新输出信号是好的编程风格吗

Verilog 使用无限循环扫描和更新输出信号是好的编程风格吗,verilog,Verilog,我的代码如下: 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_

我的代码如下:

  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”信号能够根据状态机进行扫描和不断更新。首先,我尝试了always@*但因为它只有输出信号cState需要更新。所以该块只执行了一次,因为它没有在always@*块中修改的输入信号。所以我怀疑使用“infinite for loop”是否是件好事为了达到不断扫描和更新的目的,简短的回答是否定的;使用无限循环实现FSM不是一种好的方式

答案很长,这在很大程度上取决于情况。首先,如果该有限状态机纯粹用于仿真中的功能模型,并且永远不会为FPGA或ASIC合成;您可以使用无限循环来实现FSM。但是,您应该使用关键字
forever
来实现这些循环,而不是
for(i=0;i=i+1)
while(1)
。或者,如果它们是计时的,您可以使用
always@(posedge clk)
或类似的方法来触发它们(或者使用
forever begin@(posedge clk)
,如果是分叉过程或类似的花式过程)

然而,基于这个模块的头,似乎你想要制作一个可合成的FSM,在这种情况下,你需要做很多事情来修复你的代码。下面是一个简短的建议列表,可使您的代码可合成并具有更好的风格:

  • 作为一般规则,不要在模块内使用
    初始
    块。虽然它们有一些有限的用途(在FPGA合成中),但在使用它们之前,您应该充分了解这些用途。如果需要一个变量来呈现初始状态,请在存储该变量的元素中使用重置行(参见下一点)

  • 组合逻辑应放在
    always@*
    块中,顺序逻辑应放在
    always@(posedge clk[,negedge rstL])
    块中(重置是可选的)。在创建状态机时,我建议使用以下样式:

  • 不要在组合逻辑中使用延迟,如
    x=1'b0#10; x=1'b1。在
    initial
    块中,您可以像这样更改
    cState
    ,但实际上每个状态都应该有不同的逻辑

  • 您将
    sys\u REF\u REQ
    声明为输入输出,而它可能是一个输入

  • 不要在非时钟事件上触发逻辑,比如
    总是@(posedge sys\u REF\u REQ)
    。在可合成代码中,仅在时钟和重置上使用posedge和NEGDEDGE

这就是我现在看到的,但其他人可能会在评论中添加更多内容。祝你好运

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

case (state)
  INIT: begin
    ...
  end
  READ: begin
    ...
  end
endcase