-1

in my Verilog code, the ns value does not get assigned to any of the values in the next state logic. As I coded the next state logic to assign a value to the ns state variable whenever there is a transition in the ps.

Here is the FSM code snippet

    // State registers
    always@(posedge clk, negedge rst) begin
        if(!rst) ps <= S1;
        else ps <= ns;
    end
    assign present_state = ps;
    assign next_state = ns;
     
     // Next state logic
    always@(ps, start) begin
        case(ps)
            S1: ns = start ? S2 : S1;
            S2: ns = S3;
            S3: ns = S1;
            //default : ns = S1;
        endcase
    end

Here is the tb code snippet

    initial begin 
        #0 rst = 0; start = 0;
        #2 rst = 1;
        #10 a = 3; b = 4;
        #10 start = 1;

Finally the waveform output fsm_ns_notransition

My intention is for the ps <= ns to seamlessly transtion from S1 to S2 to S3 back to S1 and so forth, however for some reason despite the always_comb next state logic block, the state change of ps at t=0, does not assign the ns to a valid state ? Resulting in all further ps <= ns assignments to be always 'x states

Is there a flaw in this logic ?

A swift help is much appreciated

Thanks

  • this looks a bit strange. According to your V95 code fragment the value of ns should have changed soon after ps was updated. There is something else going on and you need to provide the full reproducer. BTW, why don't you use system verilog if you have it in tags. – Serge Apr 11 '21 at 14:23

2 Answers2

-1

I could be wrong, but I think you have an accidentally implied latch from ns to ns. Since you commented out the default, when ps isn't any of {S1, S2, S3}, ns gets latched back into itself. The order these blocks are processed at simulation start can change, so that could be why ns starts out as X.

Since ns starts as X, that explains why that X propegates to ps on the first rising clock edge not in reset; From there, ps won't match (since you used case instead of casex), and both will stay X like you see here.

I think the easiest way to fix this would be make ns not a latch by specifying the default in the case statement.

(Using always_ff and always_comb can let the compiler help warn you about things like this)

noah
  • 32
  • 2
-1

thanks for the responses, I have figured out the reason why. Its the ternary operator ()? x:y; colon, that was not enclosed properly, leading the compiler to wrongly infer that the ternary operator ()? x:y; colon is the case ... endcase colon. I resolved this issue by just using the if else statements to avoid ambiguity. I suppose that the ternary operators ()? x:y; could be use in a case statement if properly written and enclosed, but I just went with an if else statement to avoid ambiguity.

     // Next state logic
    always@(ps, start) begin
        case(ps)
            //S1: begin ns = (start ? S2 : S1); end  // old code
            S1: begin if(start) ns = S2; else ns = S1; end // new code
            S2: ns = S3;
            S3: ns = S4;
            S4: ns = S1;
            //default : ns = S1;
        endcase
    end