Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Cannot identify inferring latches in code

sims0702

Newbie level 4
Joined
Apr 12, 2024
Messages
6
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
90
Hey,
I was wondering if I could get some help on the following issue.

I am getting latches for the registers shown in the picture and I can't figurer out why that is the case. It is a uart_rx module with an FSM. When determining the next state logic it is telling me that I am receiving inferring latches. Could I get some help on what the issue could be? (line 76-78 is inside of the SIDLE state by the way)

Thanks in advance!

Error Message:
1712908054036.png


module code:

Code:
`timescale 1ns / 1ps


module uart_receiver #(
  parameter   CLK_FREQ      = 125_000_000,
  parameter   BAUD_RATE     = 115_200,
  // Example: 125 MHz Clock / 115200 baud UART -> CLKS_PER_BIT = 1085
  parameter   CLKS_PER_BIT  = CLK_FREQ / BAUD_RATE
)
(
  input wire        iClk, iRst,
  input wire        iRxSerial,
  output wire [7:0] oRxByte,
  output wire       oRxDone
);


    // states (5)
    localparam SIDLE = 3'b000;
    localparam RXSTART = 3'b001;
    localparam RXDATA = 3'b010;
    localparam RXSAMPLE = 3'b011;
    localparam RXSTOP = 3'b100;
    localparam SDONE = 3'b101;

    //4: registers + state register
    reg[2:0] rBitCountCurrent, wBitCountNext;
    reg rDataCurrent1, rDataCurrent2;
    reg [2:0] rCurrentState, wNextState;
    reg [$clog2(CLKS_PER_BIT - 1):  0] rCntClockCurrent, wCntClockNext;
    reg [7:0] rBufferCurrent, wBufferNext;

    always @(posedge iClk) begin
            // double reg to for metastability issue.
            rDataCurrent1 <= iRxSerial;
            rDataCurrent2 <= rDataCurrent1;
        if (iRst) begin
            rBitCountCurrent <= 0;
            rCurrentState <= SIDLE;
            rCntClockCurrent <= 0;
            rBufferCurrent <=0 ;
        end
        else begin
            rBitCountCurrent <= wBitCountNext;
            rCurrentState <= wNextState;
            rCntClockCurrent <= wCntClockNext;
            rBufferCurrent <=wBufferNext;
        end
    end

    // next state logic
// next state logic
always @(*) begin
    case (rCurrentState)
        SIDLE: begin
            if (rDataCurrent2 == 0) begin
                wNextState = RXSTART;
                wBitCountNext = 0;
                wCntClockNext = 0;
                wBufferNext = 0;   
            end
            else begin
                wNextState = SIDLE;
                wBitCountNext = 0;
                wCntClockNext = 0;
                wBufferNext = 0;
            end
        end

        RXSTART: begin
            wBufferNext = rBufferCurrent;
            wBitCountNext = 0;
            if (rCntClockCurrent == CLKS_PER_BIT - 3) begin
                wNextState = RXDATA;
                wCntClockNext = 0;
            end
            else begin
                wNextState = RXSTART;
                wCntClockNext = rCntClockCurrent + 1;
            end
        end

        RXDATA: begin

            if (rCntClockCurrent == (CLKS_PER_BIT - 1) /2 ) begin // sample data
                wNextState = RXSAMPLE;
                wCntClockNext = rCntClockCurrent + 1;
                wBitCountNext = rBitCountCurrent;
                wBufferNext = rBufferCurrent;

            end
            else if (
                rCntClockCurrent == CLKS_PER_BIT - 1 && rBitCountCurrent == 7
                ) begin // byte transferred
                wNextState = RXSTOP;
                wCntClockNext = 0;
                wBitCountNext = rBitCountCurrent; // should it be incremented? not sure!
                wBufferNext = rBufferCurrent;

            end
            else if (
                rCntClockCurrent == CLKS_PER_BIT - 1
            ) begin // cycles per bit reached
                wNextState <= RXDATA;
                wBitCountNext <= rBitCountCurrent + 1;
                wCntClockNext <= 0;
                wBufferNext = rBufferCurrent;

            end
            else begin  // just counting, no case reached.
                wNextState <= RXDATA;
                wBitCountNext <= rBitCountCurrent;
                wCntClockNext <= rCntClockCurrent + 1;
                wBufferNext = rBufferCurrent;
            end
        end

        RXSAMPLE: begin
            wCntClockNext <= rCntClockCurrent + 1;
            wBitCountNext <= rBitCountCurrent;
            wNextState <= RXDATA;
            wBufferNext <= {rDataCurrent2, rBufferCurrent[7:1]}; // LSB is at end (right most side)
        end

        RXSTOP: begin
            wBitCountNext <= rBitCountCurrent;
            wBufferNext <= rBufferCurrent;

            if (rCntClockCurrent == CLKS_PER_BIT - 1) begin
                wNextState <= SDONE;
                wCntClockNext <= rCntClockCurrent;
            end
            else begin
                wNextState <= RXSTOP;
                wCntClockNext <= rCntClockCurrent + 1;
            end
        end

        SDONE: begin
            wBitCountNext <= 0;
            wCntClockNext <= 0;
            wBufferNext <= rBufferCurrent;
            wNextState <= SIDLE;
        end

        default: begin
            wBitCountNext <= 0;
            wCntClockNext <= 0;
            wBufferNext <= rBufferCurrent;
            wNextState <= SIDLE;
        end
    endcase
end


 


    // output logic
    assign oRxByte = rDataCurrent2;
    assign oRxDone = (rCurrentState == SDONE) ? 1 : 0;


endmodule
--- Updated ---

addition: These are all the synthesis error messages, in case there's a related error message
[IP_Flow 19-3571] IP 'design_1_Debounce_Switch_0_0' is restricted:
* Module reference is stale and needs refreshing.
[Synth 8-589] replacing case/wildcard equality operator !== with logical equality operator != ["/home/sims0702/cdd_lab_2/cdd_lab_2.srcs/sources_1/imports/Downloads/Debounce_Switch.v":19]
[Common 17-576] 'use_project_ipc' is deprecated. This option is deprecated and no longer used.
[Constraints 18-5210] No constraints selected for write.
Resolution: This message can indicate that there are no constraints for the design, or it can indicate that the used_in flags are set such that the constraints are ignored. This later case is used when running synth_design to not write synthesis constraints to the resulting checkpoint. Instead, project constraints are read when the synthesized design is opened.
design_1_uart_top_0_0_synth_1[IP_Flow 19-3571] IP 'design_1_uart_top_0_0' is restricted:
* Module reference is stale and needs refreshing.
[Synth 8-327] inferring latch for variable 'FSM_sequential_wNextState_reg' ["/home/sims0702/cdd_lab_2/cdd_lab_2.srcs/sources_1/new/uart_receiver.v":76]
[Synth 8-327] inferring latch for variable 'FSM_onehot_wNextState_reg' ["/home/sims0702/cdd_lab_2/cdd_lab_2.srcs/sources_1/new/uart_receiver.v":76]
[Synth 8-327] inferring latch for variable 'FSM_onehot_wNextState_reg' ["/home/sims0702/cdd_lab_2/cdd_lab_2.srcs/sources_1/new/uart_receiver.v":76]
[Synth 8-327] inferring latch for variable 'wBufferNext_reg' ["/home/sims0702/cdd_lab_2/cdd_lab_2.srcs/sources_1/new/uart_receiver.v":79]
[Synth 8-327] inferring latch for variable 'wCntClockNext_reg' ["/home/sims0702/cdd_lab_2/cdd_lab_2.srcs/sources_1/new/uart_receiver.v":78]
[Synth 8-327] inferring latch for variable 'wBitCountNext_reg' ["/home/sims0702/cdd_lab_2/cdd_lab_2.srcs/sources_1/new/uart_receiver.v":77]
[Common 17-576] 'use_project_ipc' is deprecated. This option is deprecated and no longer used.
[Constraints 18-5210] No constraints selected for write.
Resolution: This message can indicate that there are no constraints for the design, or it can indicate that the used_in flags are set such that the constraints are ignored. This later case is used when running synth_design to not write synthesis constraints to the resulting checkpoint. Instead, project constraints are read when the synthesized design is opened.
 
Last edited:
Altough I cannot say exactly where the latch is located looking at your code, I think you just have too much logic inside always(*) block.

When you have this much assincronous logic (and lots of case inside the block), latches happens almost naturally. I think that, in general, designers should minimize the use of assyncronous logic and use syncronous logic instead. (NOTE: this is a design philosophy from my side and not a formal Verilog consideration)

What I mean is: most of the logic you described inside "always (*)" block should be rethough and rewritten into the "always (posedge iClk)" block. The state machine itself should be syncronous, not assyncronous. Something like:
Code:
always @(posedge iClk)
begin
  case (CurrentState)
    SIDLE: //insert code
    RXSTART: //insert code
    RXDATA: //insert code
    (... other states)
  endcase
end

Each state should indicate the next state as CurrentState <= (NextStateYouWant). It is a faster and more secure way to code. This way, you do not need to worry to much about "double reg for instability issues" you described, and you will not have latches.
--- Updated ---

Also, not sure if related to latches or not, but it is a bad practice to have non-blocking assignments ( <= ) inside always(*) blocks.
 
Last edited:
fix the assignment operators and the latches should go away.
Hey, yes I did that as I saw the issue after posting, but no luck. to be more specific from in the SDONE state, I made the assignments from non-blocking to blocking is what I mean.
 
Solved... For some strange reason it works now. I had changed the non-blocking assignments yesterday as well but it was still showing me latches, now not anymore..
 
I have an additional question if possible,
The uart module isn't working as expected. This is what it looks like inside of a simulation for the transmission of byte. This looks normal to me, so I was wondering where the issue could be and was hoping to get some help on that if possible.
1712993144635.png


Here, this is what I actually receive and send from jupyter notebooks for a 12 byte string.
1712993329960.png


I have attached the whole project in a zip file too if that helps.
Thanks in advance!
 

Attachments

  • cdd_lab2_zipped.zip
    1.9 MB · Views: 18
Transmission looks normal, sending 0x56, but baud rate isn't 115k. Don't know how you have set up the simulation.
Should I simulate it with a baud rate 115.2k in the testbench or ?
I'll show you the simulation below. the simulation is also included inside of the project files in zip as attachment.

Code:
`timescale 1ns / 1ps

module uart_rx_TB ();
 
  // We downscale the values in the simulation
  // this will give CLKS_PER_BIT = 100 / 10 = 10
  localparam CLK_FREQ_inst  = 100;
  localparam BAUD_RATE_inst = 10;
 
  // inputs (define as reg)
  reg         rClk = 0;
  reg         rRst = 0;
  reg         rTxStart = 0;
  reg [7:0]   rTxByte = 0;
 
  // outputs (define as wire)
  wire        wTxSerial;
  wire        wTxDone;
 
  wire [7:0]  wRxByte;
  wire        wRxDone;
 
  // instantiate module under test
  uart_tx #( .CLK_FREQ(CLK_FREQ_inst), .BAUD_RATE(BAUD_RATE_inst) )
  UART_TX_INST
    (.iClk(rClk),
     .iRst(rRst),
     .iTxStart(rTxStart),
     .iTxByte(rTxByte),
     .oTxSerial(wTxSerial),
     .oTxDone(wTxDone)
     );
    
  // instantiate module under test
  uart_receiver #( .CLK_FREQ(CLK_FREQ_inst), .BAUD_RATE(BAUD_RATE_inst) )
  UART_RX_INST
    (.iClk(rClk),
     .iRst(rRst),
     .iRxSerial(wTxSerial),
     .oRxByte(wRxByte),
     .oRxDone(wRxDone)
     );

  // define the clock
  localparam T  = 4;
  always
    #(T/2) rClk <= !rClk;
 
  // input stimulus
  initial
    begin
    
      // circuit is reset
      rTxStart = 0;
      rTxByte = 8'h56;
      rRst = 1;
      #(5*T);
      
      // disable rRst
      rRst = 0;
      #(5*T);
      
      // assert rTxStart to send a frame (only 1 clock cycle!)
      rTxStart = 1;
      #(T);
      rTxStart = 0;
      rTxByte = 8'h00;
      
      // let the counter run for 150 clock cycles
      #(110*T);
 
      $stop;        //stop simulation 
          
    end
  
endmodule
 

LaTeX Commands Quick-Menu:

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top