Search code examples
verilogcountersystem-veriloghdlfsm

Reduction operator does not work properly


I have a FSM design that uses a counter to count up inside a particular state and stay there until the expression &counteryields TRUE, however when it finishes (gets 1111...111 - checking via simulator) &counter never goes HIGH and stucks on that state like an infinite loop. How to overcome this issue? I will provide my buggy part of the code. I'm quite new in verilog so hopefully it is an easy-to-catch problem.

reg [2:0] State, NextState;
reg [20:0] counter;
reg EN;

//State register 
always @(posedge Clk) begin 
    if(Rst) begin
        counter <= 0;
        State <= S0;
    end
    else begin
        State <= NextState;
        counter <= EN ? counter + 1 : 0;
    end
end

//Next State Logic
always @(State, COL)
    case(State)
        S0: begin 
            NextState <= S1;
            EN <= 0;
        end
        S1: begin 
            if(ROW) begin
                if(COL) begin 
                    if(&counter[18:0]) begin // <--- THIS EXP. NEVER GETS 1
                        PrevCOL <= COL;
                        NextState <= S3;
                        EN <= 0;
                    end
                    else begin
                        EN <= 1;
                        NextState <= S1;
                    end
                end
                else
                    NextState <= S2;
            end
            else
                NextState <= S0;
        end
        S2:  NextState <= S1;
        S3: begin
            if(PrevCOL == COL) begin
                if(&counter) begin // <-------- THIS EXPRESSION NEVER GETS 1
                    NextState <= S4;
                    EN <= 0;
                    case(ROW)
                        8: 
                            case(COL)
                                8: ID <= I0;
                                4: ID <= I1;
                                2: ID <= I2;
                                1: ID <= I3;
                            endcase
                        4:
                            case(COL)
                                8: ID <= I4;
                                4: ID <= I5;
                                2: ID <= I6;
                                1: ID <= I7;
                            endcase
                        2:
                            case(COL)
                                8: ID <= I8;
                                4: ID <= I9;
                                2: ID <= I10;
                                1: ID <= I11;
                            endcase
                        1:
                            case(COL)
                                8: ID <= I12;
                                4: ID <= I13;
                                2: ID <= I14;
                                1: ID <= I15;
                            endcase
                    endcase
                end
                else begin
                    NextState <= S3;
                    EN <= 1;
                end
            end
            else
                NextState <= S0;
        end
        S4: NextState <= S0;
    endcase

Buggy area is indicated with the comment. Why its not working?

Thank you!


Solution

  • For combinatorial logic, avoid writing sensitivity list by yourself. You should substitute this:

    always @(State, COL)
    

    With

    always @(*)
    

    You can also use always_comb. Basically, your second always block does not execute when counter is incrementing. It only executes when State or COL signals change.

    Secondly you should not use nonblocking assignment (<=) in combinatorial logic. Substitute all of them in your second "always" block with blocking assignments(=).