Search code examples
hardwareverilogfpgaxilinx

What to do when a latch cannot be avoided?


I know that latches are frowned upon in hardware and in Verilog coding. But, I sometimes come across cases where I cannot avoid a latch. For example, in these two cases:

always @ (*)
begin
    random_next = random; //default state stays the same
    count_next_r = count_r;
        
        random_next = {random[28:0], feedback}; //**shift left the xor'd every posedge clock
        

    if (count_r == 30) //if all 30 bits are shifted into register
    begin
        count_next_r = 0;
        random_done = random; //assign the random number to output after 13 shifts
    end
    else
    
        count_next_r = count_r + 1;

Here the random_done is a latch. I cannot see any other way of writing this. I only want the random_done to have data after 30 shifts of random. If I implement it this way, I am warned of a latch and it does not work properly.

Similarly, in the code below:

always @ (*)
begin
    state_next = state_reg; //default state stays the same
    count_next = count_reg;
    sel_next = sel;
    case(state_reg)
        idle:
            begin
                //DISPLAY HI HERE
                sel_next = 2'b00;
                if(start)
                begin
                    count_next = random_done; //get the random number from LFSR module
                    state_next = starting;
                end
            end
        starting:
            begin
                if(count_next == 750000000) // **750M equals a delay of 15 seconds. 8191 for simulation
                begin                           //and starting from 'rand' ensures a random delay
                    outled = 1'b1; //turn on the led 
                    state_next = time_it; //go to next state
                end
                
                else
                begin
                    count_next = count_reg + 1; 
                    outled = 1'b0;
                end
            end     
        time_it:
            begin
                    sel_next = 2'b01; //start the timer
                    state_next = done;                  
            end
                
        done:
            begin
                if(stop)
                    begin
                        sel_next = 2'b10; //stop the timer
                        outled = 1'b0;
                    end
                
            end
            
        endcase
        

From the above code the problematic section is this:

done:
    begin
        if(stop)
            begin
                sel_next = 2'b10; //stop the timer
                outled = 1'b0;
            end

Here outled is detected as a latch and during implementation I am warned of this. I simply want the led to go low when the stop bit is pressed.

How can I avoid these latches?


Solution

  • Why not assign random_done to a register.

    Create a counter and have it count down from thirty, then if it is zero assign the register random_done the new random value.

    reg [4:0] counter; 
    
    always@(posedge clk) begin
      if(rst) begin
        counter <= 5'd30;
      end
      else begin
        if(counter == 0) begin
          counter <= 5'd30;
        else begin
          counter <= counter - 1;
        end
    end
    
    wire count_done;
    
    assign count_done = (counter == 0);
    
    reg [size-1:0] random_done
    
    always@(posedge clk) begin
      ...
      if(count_done) random_done <= random;
      ...
    end
    

    To me this code looks a bit jumbled up, it does not look like you are describing hardware. Remember that Verilog ia an HDL Hardware Description Language. When emphasis on description.

    Split the logic for each register in its own always block.

    However first draw an RTL schematic of what you are trying to do. If you can not draw an RTL schematic of what you want to design, your design will most likely not be good hardware.