module uart_rx #(parameter DATA_WIDTH = 8, FIFO_DEPTH = 4) ( input clk, input rstn, input baud16, input uart_rxd, input lcr_sps, input lcr_stp2, input lcr_eps, input lcr_pen, input rx_read, input rx_clear, output rx_full, output rx_empty, output [DATA_WIDTH-1:0] rx_data, output reg rx_idle, input rx_dma_en, input rx_dma_clr, output reg rx_dma_req, output reg framing_error, output reg parity_error, output reg break_error, output reg overrun_error ); parameter UART_IDLE = 3'h0; parameter UART_START = 3'h1; parameter UART_DATA = 3'h2; parameter UART_PARITY = 3'h3; parameter UART_STOP = 3'h4; parameter BAUD_CNT = 16; parameter SAMPLE_CNT = 3; reg [2:0] rx_state; reg [SAMPLE_CNT+1:0] rx_in; // 2 extra bits for synchronization reg [1:0] rx_val; reg [3:0] rx_baud_cnt; reg rx_bit; reg rx_parity; reg [$clog2(DATA_WIDTH):0] rx_data_cnt; reg [DATA_WIDTH-1:0] rx_shift_reg; reg rx_idle_en; wire rx_lo = rx_val <= 1; wire rx_hi = !rx_lo; wire rx_sample = baud16 && rx_baud_cnt == BAUD_CNT / 2 + 1; // Where to sample rx input wire fifo_wren = rx_state == UART_STOP && rx_sample; sync_fifo #(.WIDTH(DATA_WIDTH), .DEPTH(FIFO_DEPTH), .SHOWAEAD(1)) rx_fifo( .clk (clk ), .rstn (rstn ), .wren (fifo_wren ), .rden (rx_read ), .din (rx_shift_reg), .dout (rx_data ), .full (rx_full ), .empty(rx_empty ) ); always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_in <= {SAMPLE_CNT+1{1'b1}}; end else if (baud16) begin rx_in <= { rx_in[SAMPLE_CNT:0], uart_rxd }; end end integer i; always @(*) begin rx_val = 0; for (i = 2; i < SAMPLE_CNT + 2; i = i + 1) rx_val = rx_val + rx_in[i]; end always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_bit <= 1'b0; end else if (baud16 && rx_baud_cnt == 15) begin rx_bit <= 1'b1; end else begin rx_bit <= 1'b0; end end always @(posedge clk) begin if (rx_state == UART_START) begin rx_data_cnt <= DATA_WIDTH - 1; end else if (rx_bit) begin if (rx_state == UART_DATA && rx_data_cnt == 0) begin rx_data_cnt <= DATA_WIDTH + 1 + lcr_pen + lcr_stp2; end else begin rx_data_cnt <= rx_data_cnt - 1; end end end always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_shift_reg <= 0; end else if (rx_state == UART_DATA && rx_sample) begin rx_shift_reg <= { rx_hi, rx_shift_reg[DATA_WIDTH-1:1] }; end end always @(posedge clk) begin if (rx_state == UART_START) begin rx_parity <= !lcr_eps; end else if (rx_state == UART_DATA && rx_bit && !lcr_sps) begin rx_parity <= rx_parity ^ rx_shift_reg[7]; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_baud_cnt <= 0; end else if (rx_state == UART_IDLE && rx_lo) begin rx_baud_cnt <= SAMPLE_CNT - 1; end else if (baud16) begin rx_baud_cnt <= rx_baud_cnt + 1; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_idle_en <= 1'b0; end else if (!rx_empty) begin rx_idle_en <= 1'b1; end else if (rx_clear) begin rx_idle_en <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_idle <= 1'b0; end else if (rx_state == UART_IDLE && rx_data_cnt == 0 && rx_bit && rx_idle_en) begin rx_idle <= 1'b1; end else if (rx_clear) begin rx_idle <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin framing_error <= 1'b0; end else if (rx_state == UART_STOP && rx_sample && rx_lo) begin framing_error <= 1'b1; end else if (rx_clear) begin framing_error <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin parity_error <= 1'b0; end else if (rx_state == UART_PARITY && rx_sample && rx_parity != rx_hi) begin parity_error <= 1'b1; end else if (rx_clear) begin parity_error <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin break_error <= 1'b0; end else if (rx_state == UART_STOP && rx_sample && rx_lo && rx_shift_reg == 0) begin break_error <= 1'b1; end else if (rx_clear) begin break_error <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin overrun_error <= 1'b0; end else if (fifo_wren && rx_full) begin overrun_error <= 1'b1; end else if (rx_clear) begin overrun_error <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_dma_req <= 1'b0; end else if (!rx_dma_en || rx_dma_clr) begin rx_dma_req <= 1'b0; end else if (!rx_empty) begin rx_dma_req <= 1'b1; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin rx_state <= UART_IDLE; end else begin case (rx_state) UART_IDLE: if (rx_lo) rx_state <= UART_START; UART_START: if (rx_bit && rx_baud_cnt == 0) rx_state <= UART_DATA; UART_DATA: if (rx_bit && rx_data_cnt == 0) rx_state <= lcr_pen ? UART_PARITY : UART_STOP; UART_PARITY: if (rx_bit) rx_state <= UART_STOP; UART_STOP: if (rx_sample && rx_hi) rx_state <= UART_IDLE; endcase end end endmodule