1
\$\begingroup\$

I have written an FSM Verilog code. For making transition from state S3 to S2 of the FSM , we wait for the signal b or 2 clock cycles, whichever happens first. Here are the design and tb codes.

module sample(input clk,rst,a,b, output reg x); reg [1:0] count,state,nxt_state; parameter[1:0] S0=2'b00; parameter[1:0] S1=2'b01; parameter[1:0] S2=2'b10; parameter[1:0] S3=2'b11; always@(posedge clk,posedge rst) if(rst) state<=S0; else begin state<=nxt_state; if(state==S3) count=count+1; end always@(*) begin case(state) S0: begin x=0; nxt_state= (a==1)? S1:S0;count=0; end S1: begin nxt_state= (b==1)? S3:S2; end S2: begin x=1; nxt_state=S0; end S3: begin nxt_state= (b==0 || count==1)? S2:S3; end default: begin x=0; count=0; nxt_state=S0; end endcase end endmodule 
module tb; reg clk,rst,a,b; wire x; sample dut(.*); initial begin $dumpfile("dump.vcd"); $dumpvars(0); end always #5 clk=~clk; initial begin clk=0; rst=1; a=0; b=1; #13 rst=0; #20 a=1; #5 a=0; #40 a=1; #20 b=0; #50 $finish; end endmodule 

The EDA Playground link is: https://edaplayground.com/x/m5iB

I am getting the correct functionality that x=1 after 2 cycles in state S3 if b!=0 in S3.

But, I don't understand why count value doesn't become 1 and 2 in the two cycles when we are in S3 state (waveform pic). Count value is incrementing by one cycle delay from what I had thought.

In S3, I wrote this condition: nxt_state= (b==0 || count==1)? S2:S3; thinking count value will increase in NBA region while comparison will happen in active region. So, first time we enter S3, count becomes 1 after comparison (but both happen in same time step so count=1 in this cycle only). In second cycle of S3, count=1 condition is matched on comparison and next state will be updated to S2, after this count becomes 2 (in same time step that is count=2 for second cycle in S3).

But the picture shows that the count is equal to 0 and 1 in the two cycles of state S3. So, my thinking for comparison was also not correct as it appears comparison is happening after NBA assignment of values. Then how is the correct functionality achieved here?

enter image description here

\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

The Verilog code does not adhere to the recommended good practices, and this leads to Verilog simulation race conditions. Race conditions result in unexpected behavior.

To model sequential logic for a counter, you must use nonblocking assignments (<=), but you are using blocking assignments (=). Also, you must not make assignments to the same signal (count) from separate procedural blocks (always or initial).

You should create a third always block for the counter, and remove assignments to count from the other two always blocks that you have. It might not be exactly what you need, but it gives you a cleaner starting point:

 always @(posedge clk, posedge rst) begin if (rst) begin state <= S0; end else begin state <= nxt_state; end end always @(posedge clk, posedge rst) begin if (rst) begin count <= 0; end else if (state == S0) begin count <= 0; end else if (state == S3) begin count <= count + 1; end end always @(*) begin case (state) S0: begin x=0; nxt_state = (a==1) ? S1 : S0; end S1: begin nxt_state = (b==1)? S3:S2; end S2: begin x=1; nxt_state=S0; end S3: begin nxt_state = (b==0 || count==1)? S2:S3; end default: begin x=0; nxt_state=S0; end endcase end 

There is another issue with the always @(*) block. You are trying to model combinational logic, but it retains state for the x signal because you do not assign to x in every branch of the case statement; there are no assignments to x in states S1 and S3. The code does not adhere to good practices. If you were to synthesize the logic, you would end up with a latch for x.

\$\endgroup\$
0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.