module demo_uart( Reset_n, Clk, // Interface to UART PHY (RS232 level converter) RXD_i, TXD_o, // Clk is divided by (Prescaler+1) to generate 16x the bitrate Prescaler_i, // Pulsed when RxData is valid RxValid_o, RxData_o, // Asserted when ready for a new Tx byte TxReady_o, // Pulsed when TxData is valid TxValid_i, TxData_i ); input Reset_n; input Clk; // Interface to UART PHY (RS232 level converter) input RXD_i; output TXD_o; // Clk is divided by (Prescaler+1) to generate 16x the bitrate input [15:0] Prescaler_i; // Pulsed when RxData is valid output RxValid_o; output [7:0] RxData_o; // Asserted when ready for a new Tx byte output TxReady_o; // Pulsed when TxData is valid input TxValid_i; input [7:0] TxData_i; //------------------------------------------------------------------------- // Local declarations //------------------------------------------------------------------------- reg TXD_o; reg RxValid_o; reg [7:0] RxData_o; reg TxReady_o; //------------------------------------------------------------------------- // Instantiation of sub-modules //------------------------------------------------------------------------- //--- Prescaler generating 16x bitrate clock ------------------------------ reg Clk_16x; reg [15:0] Prescaler; always @( negedge Reset_n or posedge Clk ) if ( ~Reset_n ) begin Prescaler <= 0; Clk_16x <= 0; end else begin if ( Prescaler == Prescaler_i ) begin Prescaler <= 0; Clk_16x <= 1; end else begin Prescaler <= Prescaler + 1; Clk_16x <= 0; end end //--- Transmitter logic --------------------------------------------------- reg [3:0] TxCounter; reg TxSendBit; always @( negedge Reset_n or posedge Clk ) if ( ~Reset_n ) begin TxCounter <= 0; TxSendBit <= 0; end else begin TxSendBit <= 0; if ( Clk_16x ) begin if ( TxCounter == 15 ) begin TxCounter <= 0; TxSendBit <= 1; end else TxCounter <= TxCounter + 1; end end reg [7:0] TxData_reg; reg [3:0] TxBitCnt; always @( negedge Reset_n or posedge Clk ) if ( ~Reset_n ) begin TXD_o <= 1; TxReady_o <= 1; TxData_reg <= 0; TxBitCnt <= 0; end else begin if ( TxReady_o ) begin if ( TxValid_i ) begin TxReady_o <= 0; TxData_reg <= TxData_i; TxBitCnt <= 0; end end else begin if ( TxSendBit ) begin // Only do anything on bit boundaries casez ( TxBitCnt ) 0: // Tx START bit TXD_o <= 0; 10: // Tx second STOP bit // Now we're done TxReady_o <= 1; default: // Tx data bit + first stop bit begin TXD_o <= TxData_reg[0]; TxData_reg <= { 1'b1, TxData_reg[7:1] }; end endcase TxBitCnt <= TxBitCnt+1; end end end //--- Receiver logic ------------------------------------------------------ reg RxHunt; reg [3:0] RxCounter; reg RxSampleBit; reg RxDone; always @( negedge Reset_n or posedge Clk ) if ( ~Reset_n ) begin RxCounter <= 0; RxSampleBit <= 0; RxHunt <= 1; end else begin RxSampleBit <= 0; if ( RxDone ) RxHunt <= 1; if ( Clk_16x ) begin if ( RxHunt ) begin if ( RXD_i == 0 ) begin // Receiving start bit! RxHunt <= 0; // Reset 16x bit counter RxCounter <= 0; end end else begin RxCounter <= RxCounter + 1; if ( RxCounter == 7 ) // In middle of Rx bit in next cycle RxSampleBit <= 1; end end end reg [3:0] RxBitCount; always @( negedge Reset_n or posedge Clk ) if ( ~Reset_n ) begin RxValid_o <= 0; RxData_o <= 'b0; RxBitCount <= 0; RxDone <= 0; end else begin RxValid_o <= 0; RxDone <= 0; if ( RxSampleBit ) begin RxBitCount <= RxBitCount + 1; casez ( RxBitCount ) 0: // START bit - just ignore it ; 9: // STOP bit - indicate we're ready again begin RxDone <= 1; RxBitCount <= 0; end default: // Rx Data bits begin RxData_o <= { RXD_i, RxData_o[7:1] }; if ( RxBitCount == 8 ) // Last data bit just received RxValid_o <= 1; end endcase end end endmodule