Search code examples
verilogfsm

Dealing with lots of outputs in a finite state machine verilog


So I'm trying to implement my first FSM, and I'm getting very confused.

The codes a bit long, so let me summarize: I start with declaring inputs and outputs Then state declarations (I have five plus three placeholders) Then Current state assignment, which is sequential

always @(posedge clk)
begin
    if (rst == 1'b1)
        Current_State <= MainGreen;
    else
        Current_State <= Next_state;
end

And then... I get lost. I originally just had one big ol' sequential circuit that assigned next_state and outputs, but this was messy/ probably had lots of errors.

What I have right now simply has next_state logic, but nothing to do with outputs:

always @*
begin
    Next_state = Current_State;
    case (Current_State)

        MainGreen:
        begin
            if (count && expired)
            begin
                Next_state = MainYel;
            end
        end

        MainYel:
        begin
            if (WR && expired)
                Next_state = AllRed;
            else if (expired)
                Next_state = SideGreen;
        end

        AllRed:
        begin
            if (expired)
                Next_state = SideGreen;
        end

        SideGreen:
        begin
            if(sensor && expired)
                Next_state = SideYel;
        end

        SideYel:
        begin
            if(expired)
                Next_state = MainGreen;
        end
    endcase
    end

I have about eight outputs based on state alone and four based on state and input. How should I assign them?


Solution

  • You're 90% of the way there. There are two ways to proceed (well probably more than that, but I'll give you what I think are two of the best options):

    First, do you have a lot of outputs that only get asserted for a small minority of the states? If so, I'd recommend something like this in your combinatorial always block:

    always @*
    begin
      // default output values
      output1 = 1'b0;
      output2 = 1'b0;
      output3 = 1'b0;
      ....
      case (Current_State)
        STATE1: 
        begin
          output2 = 1'b1;
          // calculate next state
          ...
        end
    
        STATE2: 
        begin
          output4 = 1'b1;
          // calculate next state
          ...
        end
        ...
      endcase
    end 
    

    This is probably the most efficient way to code your state machine since you don't need to define every output in every state. Now if you have each output active in a lot of different states, it might be easier for you to define those outputs in every state in your case statement.

    A final way, which I wouldn't recommend, is to derive the sm ouputs in separate assign statements. It will work just as well, but I think keeping the outputs together with the next state logic is much easier for code maintenance and a good habit to develop. It's one thing to hack out some code quickly for an assignment, it's another to develop code for a real product that may be getting updated several times over the life of a product, and maintainability is essential (something I had to learn on the job because no one taught it in university).