|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // Description: UART Receive Module | 
|  | // | 
|  |  | 
|  | module uart_rx ( | 
|  | input           clk_i, | 
|  | input           rst_ni, | 
|  |  | 
|  | input           rx_enable, | 
|  | input           tick_baud_x16, | 
|  | input           parity_enable, | 
|  | input           parity_odd, | 
|  |  | 
|  | output logic    tick_baud, | 
|  | output logic    rx_valid, | 
|  | output [7:0]    rx_data, | 
|  | output logic    idle, | 
|  | output          frame_err, | 
|  | output          rx_parity_err, | 
|  |  | 
|  | input           rx | 
|  | ); | 
|  |  | 
|  | logic            rx_valid_q; | 
|  | logic   [10:0]   sreg_q, sreg_d; | 
|  | logic    [3:0]   bit_cnt_q, bit_cnt_d; | 
|  | logic    [3:0]   baud_div_q, baud_div_d; | 
|  | logic            tick_baud_d, tick_baud_q; | 
|  | logic            idle_d, idle_q; | 
|  |  | 
|  | assign tick_baud = tick_baud_q; | 
|  | assign idle      = idle_q; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | sreg_q      <= 11'h0; | 
|  | bit_cnt_q   <= 4'h0; | 
|  | baud_div_q  <= 4'h0; | 
|  | tick_baud_q <= 1'b0; | 
|  | idle_q      <= 1'b1; | 
|  | end else begin | 
|  | sreg_q      <= sreg_d; | 
|  | bit_cnt_q   <= bit_cnt_d; | 
|  | baud_div_q  <= baud_div_d; | 
|  | tick_baud_q <= tick_baud_d; | 
|  | idle_q      <= idle_d; | 
|  | end | 
|  | end | 
|  |  | 
|  | always_comb begin | 
|  | if (!rx_enable) begin | 
|  | sreg_d      = 11'h0; | 
|  | bit_cnt_d   = 4'h0; | 
|  | baud_div_d  = 4'h0; | 
|  | tick_baud_d = 1'b0; | 
|  | idle_d      = 1'b1; | 
|  | end else begin | 
|  | tick_baud_d = 1'b0; | 
|  | sreg_d      = sreg_q; | 
|  | bit_cnt_d   = bit_cnt_q; | 
|  | baud_div_d  = baud_div_q; | 
|  | idle_d      = idle_q; | 
|  | if (tick_baud_x16) begin | 
|  | {tick_baud_d, baud_div_d} = {1'b0,baud_div_q} + 5'h1; | 
|  | end | 
|  |  | 
|  | if (idle_q && !rx) begin | 
|  | // start of char, sample in the middle of the bit time | 
|  | baud_div_d  = 4'd8; | 
|  | tick_baud_d = 1'b0; | 
|  | bit_cnt_d   = (parity_enable ? 4'd11 : 4'd10); | 
|  | sreg_d      = 11'h0; | 
|  | idle_d      = 1'b0; | 
|  | end else if (!idle_q && tick_baud_q) begin | 
|  | if ((bit_cnt_q == (parity_enable ? 4'd11 : 4'd10)) && rx) begin | 
|  | // must have been a glitch on the input, start bit is not set | 
|  | // in the middle of the bit time, abort | 
|  | idle_d    = 1'b1; | 
|  | bit_cnt_d = 4'h0; | 
|  | end else begin | 
|  | sreg_d    = {rx, sreg_q[10:1]}; | 
|  | bit_cnt_d = bit_cnt_q - 4'h1; | 
|  | idle_d    = (bit_cnt_q == 4'h1); | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) rx_valid_q <= 1'b0; | 
|  | else         rx_valid_q <= tick_baud_q & (bit_cnt_q == 4'h1); | 
|  |  | 
|  | end | 
|  |  | 
|  | assign rx_valid      = rx_valid_q; | 
|  | assign rx_data       = parity_enable ? sreg_q[8:1] : sreg_q[9:2]; | 
|  | //    (rx_parity     = sreg_q[9]) | 
|  | assign frame_err     = rx_valid_q & ~sreg_q[10]; | 
|  | assign rx_parity_err = parity_enable & rx_valid_q & | 
|  | (^{sreg_q[9:1],parity_odd}); | 
|  |  | 
|  | endmodule |