blob: 829895a8dca79224e006668e84536147eb4835b1 [file] [log] [blame]
// 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