Search code examples
veriloguart

Why can't I simulate my receiver code for UART?


I'm trying to simulate a uart receiver in a testbench using Verilog. I forced all the input bits, the clock and the reset, and I forced RsRx, the serial input of the receiver, in order to get the output rx_data, but rx_data is always

The baudgenerator worked well, but the receiver didn't. I think the problem is in the testbench because the code of the receiver is provided by ARM. Could anyone help me please?

module TEST_Uart() ;
reg HCLK=0 ;
reg HRESETn=0 ;
wire b_tick ;
wire rx_done ;
reg RsRx=1 ;
wire [7:0]rx_data ;
       initial 
        forever #1 HCLK = ~HCLK;
initial
begin
@(posedge HCLK);
HRESETn=1 ;
end
BAUDGEN uBAUDGEN(
    .clk(HCLK),
    .resetn(HRESETn),
    .baudtick(b_tick)
  );
  
  
 //UART receiver
      UART_RX uUART_RX(
        .clk(HCLK),
        .resetn(HRESETn),
        .b_tick(b_tick),
        .rx(RsRx),
        .rx_done(rx_done),
        .dout(rx_data[7:0])
      );
     
      task UART_WRITE_BYTE;
          input [7:0] i_Data;
          integer     ii;
          begin
             
            // Send Start Bit
           RsRx <= 1'b0;
           
             
             
            // Send Data Byte
            for (ii=0; ii<8; ii=ii+1)
              begin
                RsRx <= i_Data[ii];
     
              end
             
            // Send Stop Bit
            RsRx <= 1'b1;
           
           end
        endtask // UART_WRITE_BYTE
      
      
     initial
         begin
                      
           // Send a command to the UART (exercise Rx)
           @(posedge HCLK);
           UART_WRITE_BYTE(8'h3F);
           @(posedge HCLK);
                  
           // Check that the correct command was received
           if (rx_data == 8'h3F)
             $display("Test Passed - Correct Byte Received");
           else
             $display("Test Failed - Incorrect Byte Received");
         end
endendmodule

Solution

  • You need to add delays inside the UART_WRITE_BYTE task. Currently, RsRx seems to always be 1 when you run a simulation and you look at waveforms. This is because all your assignments occur at the same simulation time.

    You need to add delays between each assignment. For example, in the code below, I add a delay of 5 after each assignment:

    task UART_WRITE_BYTE;
        input [7:0] i_Data;
        integer     ii;
        begin
            // Send Start Bit
            RsRx <= 1'b0;
            #5;
    
            // Send Data Byte
            for (ii=0; ii<8; ii=ii+1)
            begin
                RsRx <= i_Data[ii];
                #5;
            end
    
            // Send Stop Bit
            RsRx <= 1'b1;
            #5;
        end
    endtask // UART_WRITE_BYTE
    

    I used 5 just to demonstrate the principle. The delay should really be related to the baud rate. You probably want to replace that fixed delay with code related to an edge of the b_tick signal, for example:

    @(posedge b_tick);