SystemVerilog "Lock up" on FPGA

I have a lock-up problem with my UART receiver project. For each character received I go through 4 states RX_IDLE, RX_GETSTART, RX_GETDATA and RX_STOP. The RX_IDLE state waits for the incoming signal to fall from high to low using my FallingEdgeDetector.

FallingEdgeDetector latches (stops running) once it detects a falling edge and I have to bring a reset input high to get it to look for another falling edge.

The attached image shows the “running” output of my FallingEdgeDetector completely flat-lining. I don’t understand how this is happening because the only time ‘running’ is set to 0 is when a falling edge is detected and the fallDetected output should be 1 at the same time. However, ‘fallDetected’ is 0 and so is ‘running’. They should always be the opposite to each other.

How could this be happening? I’ve tried using different output pins on my FGPA development board - including routing the ‘running’ output to one of the onboard LEDs. Same thing. It will receive sometimes tens or hundreds of characters and then it freezes.

I’ve tried to minimise the project as much as possible.

FallingEdgeDetector:

module FallingEdgeDetector( input logic clk, 
                            input logic rxIn,
                            input logic reset,
                            output logic fallDetected,
                            output logic running
                            );

logic rxLast;

initial begin
  running = 1;
  rxLast  = 0;
  fallDetected = 0;
end
  
always_ff @( posedge clk )
begin
  if( reset )
  begin
    running = 1;
    rxLast  = 0;
    fallDetected = 0;    
  end
  else   
  if( running )
  begin
    if( ( rxLast ) && ( ! rxIn ) )
    begin
      fallDetected = 1;
      running = 0;
    end
    
    rxLast = rxIn;
  end
end
                            
endmodule

Baud Tick Generator:

module UART_BaudRate_generator #(parameter longint BaudRate=19200) // Bits per second
(
  input  Clk,  
  output logic TickX8     // 8 ticks per baud cycle
);

localparam longint freqFPGA         = 50000000;             // 50MHz

longint BaudRateX8Clocks;

longint         currClock8Count;

initial 
begin

  if( BaudRate == 9600 )
  begin
    // Number of FPGA clock cycles requires for 1 baud period
    // BaudRateClocks   = freqFPGA / BaudRate;  
    BaudRateX8Clocks = 372;
  end

  TickX8 = 0;
  
  currClock8Count = 0;
end


always @(posedge Clk)
begin
 
  if( currClock8Count >= BaudRateX8Clocks )
  begin
    currClock8Count = 0;
    TickX8 = 1;
  end
  else
  begin
    TickX8 = 0;
  end

  currClock8Count ++;
end

endmodule

CharacterReceiver:

module CharacterReceiver( input  logic rxIn, 
                          input  logic baudTickX8,
                          input  logic clk, 
                          output byte  rxData, 
                          output logic ledBit1,
                          output logic ledBit2,
                          output logic ledBit3,
                          output logic ledBit4,
                          output logic ledBit5,
                          output logic ledBit6,
                          output logic ledBit7,
                          output logic ledBit8,
                          output logic ledBitStart,
                          output logic ledBitStop,
                          output logic ledPurpleIdle,
                          output logic ledPurpleStart,
                          output logic ledPurpleData,
                          output logic ledPurpleStop,
                          output logic ledPurpleDetected,
                          output logic ledPurpleDetectReset,
                          output logic detectorRunning
                          );


byte   unsigned bitsRemaining    = 0;
byte   unsigned currentChar      = 0;
byte   unsigned sampleCount;
byte   unsigned sampleSize       = 14;
byte   unsigned halfSampleSize;
byte   unsigned matchCount       = 0;

localparam byte detectResetCyclesMax = 50;

assign ledPurpleDetectReset = fallDetectorReset;
assign ledPurpleDetected = fallDetected;

initial 
begin
  halfSampleSize   = 8;

  currentChar <= 0;
  bitsRemaining <= 8;
  sampleCount <= 0;
  
  ledBit1 <= 0;
  ledBit2 <= 0;
  ledBit3 <= 0;
  ledBit4 <= 0;
  ledBit5 <= 0;
  ledBit6 <= 0;
  ledBit7 <= 0;
  ledBit8 <= 0;
  ledBitStart <= 0;
  ledBitStop  <= 0;
end


logic fallDetectorReset = 1;
logic fallDetected;

FallingEdgeDetector fallingDetector( clk, 
                                     rxIn,
                                     fallDetectorReset,
                                     fallDetected,
                                     detectorRunning );


//--------------------------------------------------------------------------------
// Receive States
//--------------------------------------------------------------------------------
typedef enum 
{
  RX_IDLE,
  RX_GETSTART,
  RX_GETDATA,
  RX_GETSTOP
  
} RECEIVESTATE;

RECEIVESTATE rxState = RX_IDLE;


//--------------------------------------------------------------------------------
// HandleRxGetStart
//--------------------------------------------------------------------------------
function void HandleRxGetStart;

  if( rxIn == 0 )
    matchCount ++;
  else
  if( rxIn == 1 )
  begin
    sampleCount = 0;
    rxState     = RX_IDLE;
    detectResetCycles = detectResetCyclesMax;
    fallDetectorReset = 1;
    matchCount  = 0;
  end    

  // We only want to count half of the baud samples to put us in the middle..
  //if( sampleCount < halfSampleSize ) 
  if( matchCount < halfSampleSize )
    return;

  // Start counting samples from the middle..
  sampleCount   = 0;
  matchCount    = 0;
  bitsRemaining = 8;
  
  ledBitStart   = 1;
  ledBitStop    = 0;
    
  rxState = RX_GETDATA;
  
endfunction


//--------------------------------------------------------------------------------
// HandleRxGetData
//--------------------------------------------------------------------------------
function void HandleRxGetData;

  bit bitVal;

  //  Wait sampleCount X8 ticks since the middle of the start bit.. or
  //  sampleCount X8 ticks since the last bit..
  if( sampleCount < sampleSize )
    return;

  // Reset count for next time..
  sampleCount = 0;
    
  unique case ( bitsRemaining )
    8: currentChar = currentChar | ( rxIn ? 8'h01 : 1'b0 );
    7: currentChar = currentChar | ( rxIn ? 8'h02 : 1'b0 );
    6: currentChar = currentChar | ( rxIn ? 8'h04 : 1'b0 );
    5: currentChar = currentChar | ( rxIn ? 8'h08 : 1'b0 );
    4: currentChar = currentChar | ( rxIn ? 8'h10 : 1'b0 );
    3: currentChar = currentChar | ( rxIn ? 8'h20 : 1'b0 );
    2: currentChar = currentChar | ( rxIn ? 8'h40 : 1'b0 );
    1: currentChar = currentChar | ( rxIn ? 8'h80 : 1'b0 );
    0: ;
  endcase

  unique case ( bitsRemaining )
    8: ledBit1 = rxIn;
    7: ledBit2 = rxIn;
    6: ledBit3 = rxIn;
    5: ledBit4 = rxIn;
    4: ledBit5 = rxIn;
    3: ledBit6 = rxIn;
    2: ledBit7 = rxIn;
    1: ledBit8 = rxIn;
    0: ;
  endcase

  bitsRemaining --;
  
  if( bitsRemaining <= 0 )
  begin
  
    // Ready for next time..
    bitsRemaining = 8;
  
    rxState = RX_GETSTOP;
  end
  
endfunction

//--------------------------------------------------------------------------------
// HandleRxGetStopBit
//--------------------------------------------------------------------------------
function void HandleRxGetStopBit;

  if( sampleCount < sampleSize ) 
    return;

  if( rxIn == 1 )
  begin
    ledBitStop  = 1;
    ledBitStart = 0;
  end

  // Reset count for next time..
  sampleCount = 0;

  detectResetCycles = detectResetCyclesMax;
  fallDetectorReset = 1;
  
  rxState = RX_IDLE;

endfunction

byte detectResetCycles = 0;

//--------------------------------------------------------------------------------
// State machine for receiving
//--------------------------------------------------------------------------------
always_ff @( posedge clk )
begin
  ledPurpleIdle  = ( rxState == RX_IDLE ); 
  ledPurpleStart = ( rxState == RX_GETSTART ); 
  ledPurpleData  = ( rxState == RX_GETDATA ); 
  ledPurpleStop  = ( rxState == RX_GETSTOP );   
      
  if( rxState == RX_IDLE )
  begin
    if( fallDetectorReset )
    begin
      if( detectResetCycles > 0 )
      begin
        detectResetCycles --;
        // Leave the reset signal up for a number of clock cycles
      end
      else
      begin
        // Clear this now - only needs to be high for 1 clock cycle
        fallDetectorReset = 0;
      end
    end
    else
    if( fallDetected )
    begin
      ledBitStart = 0;
      ledBitStop  = 0;

      rxState = RX_GETSTART;
      
      // Don't include transition, get next time
    end
  end
  else  
  begin

    // Service state machine for receiving
    if( ( rxState != RX_IDLE ) && ( baudTickX8 ) )
    begin

      if( sampleCount < sampleSize )
        sampleCount ++;
      else
        sampleCount = 0;

      // WARNING!! If you don't add ALL cases, the wrong case will execute instead!!
      unique case( rxState )
        RX_IDLE         : ; // MUST have this!!
        RX_GETSTART     : HandleRxGetStart();
        RX_GETDATA      : HandleRxGetData();
        RX_GETSTOP      : HandleRxGetStopBit();
      endcase
      
    end
  end  
end  

endmodule

Testbench:

module SystemVerilogTest1( input  logic clk, 
                           input  logic i115,
                           output logic baudTickX8, 
                           output logic txActual,
                           output logic ledBit1,
                           output logic ledBit2,
                           output logic ledBit3,
                           output logic ledBit4,
                           output logic ledBit5,
                           output logic ledBit6,
                           output logic ledBit7,
                           output logic ledBit8,
                           output logic ledBitStart,
                           output logic ledBitStop,
                           output logic ledPurpleIdle,
                           output logic ledPurpleStart,
                           output logic ledPurpleData,
                           output logic ledPurpleStop,
                           output logic ledPurpleDetected,
                           output logic ledPurpleDetectReset,
                           output logic detectorRunning


 );

byte  rxByte;

parameter longint baudRate = 9600;

UART_BaudRate_generator #(baudRate) BaudGen1(
    .Clk( clk ),
    .TickX8( baudTickX8 ),
    );

  
CharacterReceiver    charReceiver( i115, baudTickX8, clk, 
                          rxByte, 
                          ledBit1,
                          ledBit2,
                          ledBit3,
                          ledBit4,
                          ledBit5,
                          ledBit6,
                          ledBit7,
                          ledBit8,
                          ledBitStart,
                          ledBitStop,
                          ledPurpleIdle,
                          ledPurpleStart,
                          ledPurpleData,
                          ledPurpleStop,
                          ledPurpleDetected,
                          ledPurpleDetectReset,
                          detectorRunning

 );   

endmodule

Your code/tb is too complex to debug and analyze for accuracy.

I suggest that you look at the requirements and the architecture.
Take a look at my FREE BOOK: Component Design by Example … A Step-by-Step Process Using VHDL with UART as Vehicle.
See how that architecture matches yours. Look at the clocks and the 16x clocks and tin timing.

https://verificationacademy.com/forums/announcements/free-book-component-design-example-…-step-step-process-using-vhdl-uart-vehicle

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr

  • SVA Handbook 4th Edition, 2016 ISBN 978-1518681448
  • A Pragmatic Approach to VMM Adoption 2006 ISBN 0-9705394-9-5
  • Using PSL/SUGAR for Formal and Dynamic Verification 2nd Edition, 2004, ISBN 0-9705394-6-0
  • Real Chip Design and Verification Using Verilog and VHDL, 2002 isbn 978-1539769712
  • Component Design by Example ", 2001 ISBN 0-9705394-0-1
  • VHDL Coding Styles and Methodologies, 2nd Edition, 1999 ISBN 0-7923-8474-1
  • VHDL Answers to Frequently Asked Questions, 2nd Edition ISBN 0-7923-8115

  1. SVA Alternative for Complex Assertions
    Verification Horizons - March 2018 Issue | Verification Academy
  2. SVA: Package for dynamic and range delays and repeats | Verification Academy
  3. SVA in a UVM Class-based Environment
    SVA in a UVM Class-based Environment | Verification Horizons | Verification Academy