module uart_rx ( input logic clk_i, input logic rstn_i, input logic rx_i, input logic [15:0] cfg_div_i, input logic cfg_en_i, input logic cfg_parity_en_i, input logic cfg_even_parity_i, output logic busy_o, output logic parity_error_o, output logic overrun_o, input logic err_clr_i, output logic [7:0] rx_data_o, output logic rx_valid_o, input logic rx_ready_i ); enum logic [2:0] {IDLE,START_BIT,DATA,PARITY,STOP_BIT} CS, NS; logic [7:0] reg_data; logic [2:0] reg_rx_sync; logic [2:0] reg_bit_count; logic parity_bit; logic [15:0] baud_cnt; logic baudgen_en; logic bit_done; logic start_bit; logic s_rx_fall; assign busy_o = (CS != IDLE); always_comb begin NS = CS; baudgen_en = 1'b0; start_bit = 1'b0; case(CS) IDLE: begin if (s_rx_fall) begin NS = START_BIT; baudgen_en = 1'b1; start_bit = 1'b1; end end START_BIT: begin baudgen_en = 1'b1; start_bit = 1'b1; if (bit_done) NS = DATA; end DATA: begin baudgen_en = 1'b1; if (bit_done) begin if (reg_bit_count == 3'h7) begin if (cfg_parity_en_i) NS = PARITY; else NS = STOP_BIT; end end end PARITY: begin baudgen_en = 1'b1; if (bit_done) begin NS = STOP_BIT; end end STOP_BIT: begin baudgen_en = 1'b1; if (bit_done) begin NS = IDLE; end end default: NS = IDLE; endcase end always_ff @(posedge clk_i or negedge rstn_i) begin if (rstn_i == 1'b0) begin CS <= IDLE; reg_data <= 8'hFF; reg_bit_count <= 'h0; parity_bit <= 1'b0; parity_error_o <= 1'b0; rx_valid_o <= 1'b0; overrun_o <= 1'b0; end else begin if(cfg_en_i) CS <= NS; else CS <= IDLE; rx_valid_o <= 0; case (CS) START_BIT: parity_bit <= ~cfg_even_parity_i; DATA: if (bit_done) begin parity_bit <= parity_bit ^ reg_rx_sync[2]; reg_data <= {reg_rx_sync[2],reg_data[7:1]}; if (reg_bit_count == 3'h7) reg_bit_count <= 'h0; else reg_bit_count <= reg_bit_count + 1; end PARITY: if (bit_done) if(parity_bit != reg_rx_sync[2]) parity_error_o <= 1'b1; else parity_error_o <= 1'b0; STOP_BIT: if (bit_done) begin rx_valid_o <= 1'b1; overrun_o <= ~rx_ready_i; end endcase end end assign s_rx_fall = ~reg_rx_sync[1] & reg_rx_sync[2]; always_ff @(posedge clk_i or negedge rstn_i) begin if (rstn_i == 1'b0) reg_rx_sync <= 3'b111; else begin if (cfg_en_i) reg_rx_sync <= {reg_rx_sync[1:0],rx_i}; else reg_rx_sync <= 3'b111; end end always_ff @(posedge clk_i or negedge rstn_i) begin if (rstn_i == 1'b0) begin baud_cnt <= 'h0; bit_done <= 1'b0; end else begin if(baudgen_en) begin if(!start_bit && (baud_cnt == cfg_div_i)) begin baud_cnt <= 'h0; bit_done <= 1'b1; end else if(start_bit && (baud_cnt == {1'b0,cfg_div_i[15:1]})) begin baud_cnt <= 'h0; bit_done <= 1'b1; end else begin baud_cnt <= baud_cnt + 1; bit_done <= 1'b0; end end else begin baud_cnt <= 'h0; bit_done <= 1'b0; end end end assign rx_data_o = reg_data; endmodule