0
\$\begingroup\$

All the two/three process block modeling style(the recommended style) examples for FSM have logic for nextstate that is a function of current state and inputs. The outputs in these examples also take specific values depending on current state and optionally inputs.

Ex :

always_ff@(posedge clk) begin
   if(rst) currentState<=IDLE;
   else    currentState<=nextState;
end

always_comb begin
     nextState = 'x;
     case(currentState)
           IDLE  : if(in1)           nextState = CALC1;
                   else              nextState = IDLE;
           CALC1 : if(in1)           nextState = CALC2;
                   else if(in2)      nextState = IDLE;
                   else              nextState = CALC1;
           ......

     endcase

end

always_comb begin
    out1 = '0;
    out2 = '0;
    case(currentState)
        CALC1 : out1 = 1'b1;
        CALC2 : out2 = 1'b1;
    endcase
end

Consider an example for an FSM for a memory BIST. I want my FSM to be in state1 while my address is less than 1000, change to state2 when it reaches the value of 1000. I want the address to keep incrementing from 0 to 1000 while in state1 and start decrementing when in state2. Furthermore I want my FSM to be in state0 for 500 cycles just after reset.

always_comb begin
    nextState = 'x;
    case(currentState)
         state0 : if(resetCount<500)  nextState = state1;
                  else                nextState = state0;
         state1 : if(addr<1000)       nextState = state2;
                  else                nextState = state1;
         state2 : if(addr>0)          nextState = state3;
                  else                nextState = state2;
         ....
    endcase
end

always_ff@(posedge clk) begin
      ...
      case(currentState)
           state0 : addr<='0;
           state1 : addr<=add+'d1;
           state2 : addr<=add-'d1;
           ...
      endcase
end

always_ff@(posedge clk) begin
    ...
    if(currentState=='0) resetCount<=restCount+'d1;
    else                 resetCount<='0;
end


The next state and output calculation is not straight forward. If I keep adding signals like data/control signals, these dependencies will increase.

For a case such as this, is it still recommended that we follow 2/3 process block FSM and remove all the extraneous logic(Ex : the reset counter) from the module where FSM is coded? I can move the reset counter outside of the FSM module and have a signal indicate to the FSM when counter reaches 500, and generate a signal from FSM that indicates to the counter outside the FSM to count or not depending on state.

But isn't it extra effort just to keep it in 2 processes?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The next state and output calculation is not straight forward. If I keep adding signals like data/control signals, these dependencies will increase.

Well, that is a typical problem.

or a case such as this, is it still recommended that we follow 2/3 process block FSM and remove all the extraneous logic(Ex : the reset counter) from the module where FSM is coded?

Well, you didn't really write a FSM if there's external factors that aren't actually input that change states. You'd want to integrate these timers in the FSM, so that it's logically self-contained – and can be tested as such.

The problem really is that it's usually pretty hard to reason about what your design does if you don't keep your state machines clean.

"Extra Effort" is usually worth it if it means that you can still understand your design in a week or a year. Most code is "write once, read many times", and keeping your state machine cleaner (even if that means investing more in formalism) is usually a good idea – all the commercial projects I've worked with that did hardware design had a clear review process, and the ability of a reviewer to quickly grasp what you're doing is not "a good thing", but a requirement for your code being accepted!

What's even more important: it's super easy to screw these things up. Keeping separation as far as possible between system components makes this easier for you, in the long run. The little extra "mechanical" effort will mean nothing.

I see these kind of approaches in a lot of beginner coders for any language, by the way: Because they feel that the writing code part is the hard one, they try to reduce the code in favor of taking seemingly elegant shortcuts. As soon as they're more used to their language and tools, they come back and regret what they've done – not the writing of code is the hard part, the designing a correct system is hard. And system design is easier for humans with patterns they understand.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.