我的 uart_rx 模块中不断收到 BufferNext 的“推断锁存器”错误

问题描述 投票:0回答:3

我一直收到

BufferNext
寄存器的错误,我不知道为什么;任何帮助表示赞赏。这是模块的代码:

`timescale 1ns / 1ps

module uart_rx #(
  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
);

  localparam sIDLE              = 3'b000;
  localparam sSTART_DETECT      = 3'b001;
  localparam sRX_DATA_RECEIVE   = 3'b010;
  localparam sRX_END_DETECT     = 3'b011;
  localparam sRX_DONE           = 3'b100;

// Double-register the input wire to prevent metastability issues
  reg rRx1, rRx2;
  
  reg [7:0] RxSerialBuffer, BufferNext;

// -> FSM state
  reg [2:0] rFSM_Current, wFSM_Next; 
  
  // -> counter to keep track of the clock cycles
  reg [$clog2(CLKS_PER_BIT):0]   rCnt_Current, wCnt_Next;
    
  // -> counter to keep track of sent bits
  // (between 0 and 7)
  reg [6:0] rBit_Current, wBit_Next;

  

always @(posedge iClk)
  begin
    rRx1 <= iRxSerial;
    rRx2 <= rRx1;
    
    if (iRst==1)
          begin
            rFSM_Current <= sIDLE;
            rCnt_Current <= 0;
            rBit_Current <= 0;
            RxSerialBuffer <= 0;
            BufferNext <= 0;
          end
    else
          begin
            rFSM_Current <= wFSM_Next;
            rCnt_Current <= wCnt_Next;
            rBit_Current <= wBit_Next;
            BufferNext <= BufferNext;
            RxSerialBuffer <= BufferNext;
          end 
  end
  
  always @(*)
  begin
      case(rFSM_Current)
      
          sIDLE: begin
                     wCnt_Next = 0;
                     wBit_Next = 0;
                     
                     if(iRxSerial == 0) 
                         begin
                            wFSM_Next = sSTART_DETECT;
                            BufferNext <= 0;
                         end
                        
                     else 
                         begin
                            wFSM_Next = sIDLE;
                            BufferNext <= BufferNext;
                         end
                 end
                 
          sSTART_DETECT: begin
                     wBit_Next = 0;
                     
                      if (rCnt_Current < (CLKS_PER_BIT - 1) )
                        begin
                          wFSM_Next = sSTART_DETECT;
                          wCnt_Next = rCnt_Current + 1;
                          BufferNext <= BufferNext;
                        end
                      else
                        begin
                          wFSM_Next = sRX_DATA_RECEIVE;
                          wCnt_Next = 0;
                          BufferNext <= BufferNext;
                          end
                       end
                       
          sRX_DATA_RECEIVE: begin
                 if (rCnt_Current < (CLKS_PER_BIT - 1) )
                begin
               
                  if(rCnt_Current >= (CLKS_PER_BIT - 1)/2)
                      begin
                       BufferNext[rBit_Current] <= iRxSerial;
                      end
                  
                  else
                      begin
                        BufferNext[rBit_Current] <= BufferNext[rBit_Current];
                      end
                  
                  
                  wFSM_Next = sRX_DATA_RECEIVE;
                  wCnt_Next = rCnt_Current + 1;
                  wBit_Next = rBit_Current;
                end
              else
                begin
                  wCnt_Next = 0;
                  
                  if (rBit_Current != 7)
                    begin
                      wFSM_Next = sRX_DATA_RECEIVE;
                      wBit_Next = rBit_Current + 1;
                    end
                  else
                    begin
                      wFSM_Next = sRX_END_DETECT;
                      wBit_Next = 0;
                    end
                    
                  BufferNext <= BufferNext;
                    
                end
             end
             
         sRX_END_DETECT: begin
              wBit_Next = 0;
               
              if (rCnt_Current < (CLKS_PER_BIT - 1) )
                begin
                  wFSM_Next = sRX_END_DETECT;
                  wCnt_Next = rCnt_Current + 1;
                end
              else
                begin
                  wFSM_Next = sRX_DONE;
                  wCnt_Next = 0;
                end
                
              BufferNext <= BufferNext;
            end 
            
        sRX_DONE: begin
              wBit_Next = 0;
              wCnt_Next = 0;
              BufferNext <= BufferNext;
              wFSM_Next = sIDLE;
            end
           
           
          default :
            begin
              wFSM_Next = sIDLE;
              wCnt_Next = 0;
              wBit_Next = 0;
              BufferNext <= BufferNext;

            end 
    
      endcase
      
   end

assign oRxByte = RxSerialBuffer;

assign oRxDone = (rFSM_Current == sRX_DONE) ? 1 : 0;
   
endmodule

据我所知,要摆脱闩锁,应该确保每个

if
都有一个
else
,以及每个
case
语句都有一个
default
案例。据我所知,这不应该是问题所在,因为我确实为每个 if 添加了一个 else,并为每个
default
添加了一个
case
,并在其中的每一个中显式地为 BufferNext 分配了一个值(有时它只是 BufferNext <= BufferNext just for the sake of explicitly assigning something to BufferNext). The objective here would be to get rid of that latch.

verilog uart vivado
3个回答
0
投票

问题是:

BufferNext <= BufferNext;

您必须通过以下方式更改它:

RxSerialBuffer <= BufferNext;

这一行的问题在于它没有为 BufferNext 寄存器分配任何新值。相反,它只是将寄存器的现有值分配给自己,这是多余的并且可能导致错误。这一行应该从 always 块中删除,因为它没有做任何有用的事情。


0
投票

一个问题是您从 2

BufferNext
块分配给相同的信号 (
always
)。您应该只分配给来自一个
always
块的信号。我的猜测是你不想在第一个
BufferNext
块中分配给
always

意外锁存的另一个潜在来源是分配给信号的单个bit

BufferNext[rBit_Current] <= ...

确保在

sRX_DATA_RECEIVE
状态下分配所有8位。


0
投票

latch的原因是这样的:

  default :
    begin
      wFSM_Next = sIDLE;
      wCnt_Next = 0;
      wBit_Next = 0;
      BufferNext = BufferNext;

    end 

关于组合逻辑的反馈

BufferNext
.
你要求它保持它的价值。

正如另一个答案所指出的,在组合过程和推断寄存器的时钟过程中驱动

BufferNext
存在一个严重的问题。

典型的状态机样式只有

BufferNext
组合,它将作为一个名为
Buffer
的寄存器的输入。

另一个问题是在组合过程中使用非阻塞赋值。这可能会导致模拟和综合不匹配。
使用:

BufferNext = <RHS>;    

而不是:

BufferNext <= <RHS>;    

在组合过程中(如

case
声明)

© www.soinside.com 2019 - 2024. All rights reserved.