blob: c25ded662700c6e679fb96026461caac913e9905 [file] [log] [blame]
module uart_rx (
clk_i,
rstn_i,
rx_i,
cfg_div_i,
cfg_en_i,
cfg_parity_en_i,
cfg_bits_i,
busy_o,
err_o,
err_clr_i,
rx_data_o,
rx_valid_o,
rx_ready_i
);
input wire clk_i;
input wire rstn_i;
input wire rx_i;
input wire [15:0] cfg_div_i;
input wire cfg_en_i;
input wire cfg_parity_en_i;
input wire [1:0] cfg_bits_i;
output wire busy_o;
output reg err_o;
input wire err_clr_i;
output wire [7:0] rx_data_o;
output reg rx_valid_o;
input wire rx_ready_i;
reg [2:0] CS;
reg [2:0] NS;
reg [7:0] reg_data;
reg [7:0] reg_data_next;
reg [2:0] reg_rx_sync;
reg [2:0] reg_bit_count;
reg [2:0] reg_bit_count_next;
reg [2:0] s_target_bits;
reg parity_bit;
reg parity_bit_next;
reg sampleData;
reg [15:0] baud_cnt;
reg baudgen_en;
reg bit_done;
reg start_bit;
reg set_error;
wire s_rx_fall;
assign busy_o = CS != 3'd0;
always @(*)
case (cfg_bits_i)
2'b00: s_target_bits = 3'h4;
2'b01: s_target_bits = 3'h5;
2'b10: s_target_bits = 3'h6;
2'b11: s_target_bits = 3'h7;
endcase
always @(*) begin
NS = CS;
sampleData = 1'b0;
reg_bit_count_next = reg_bit_count;
reg_data_next = reg_data;
rx_valid_o = 1'b0;
baudgen_en = 1'b0;
start_bit = 1'b0;
parity_bit_next = parity_bit;
set_error = 1'b0;
case (CS)
3'd0:
if (s_rx_fall) begin
NS = 3'd1;
baudgen_en = 1'b1;
start_bit = 1'b1;
end
3'd1: begin
parity_bit_next = 1'b0;
baudgen_en = 1'b1;
start_bit = 1'b1;
if (bit_done)
NS = 3'd2;
end
3'd2: begin
baudgen_en = 1'b1;
parity_bit_next = parity_bit ^ reg_rx_sync[2];
case (cfg_bits_i)
2'b00: reg_data_next = {3'b000, reg_rx_sync[2], reg_data[4:1]};
2'b01: reg_data_next = {2'b00, reg_rx_sync[2], reg_data[5:1]};
2'b10: reg_data_next = {1'b0, reg_rx_sync[2], reg_data[6:1]};
2'b11: reg_data_next = {reg_rx_sync[2], reg_data[7:1]};
endcase
if (bit_done) begin
sampleData = 1'b1;
if (reg_bit_count == s_target_bits) begin
reg_bit_count_next = 'h0;
NS = 3'd3;
end
else
reg_bit_count_next = reg_bit_count + 1;
end
end
3'd3: begin
baudgen_en = 1'b1;
rx_valid_o = 1'b1;
if (rx_ready_i)
if (cfg_parity_en_i)
NS = 3'd4;
else
NS = 3'd5;
end
3'd4: begin
baudgen_en = 1'b1;
if (bit_done) begin
if (parity_bit != reg_rx_sync[2])
set_error = 1'b1;
NS = 3'd5;
end
end
3'd5: begin
baudgen_en = 1'b1;
if (bit_done)
NS = 3'd0;
end
default: NS = 3'd0;
endcase
end
always @(posedge clk_i or negedge rstn_i)
if (rstn_i == 1'b0) begin
CS <= 3'd0;
reg_data <= 8'hff;
reg_bit_count <= 'h0;
parity_bit <= 1'b0;
end
else begin
if (bit_done)
parity_bit <= parity_bit_next;
if (sampleData)
reg_data <= reg_data_next;
reg_bit_count <= reg_bit_count_next;
if (cfg_en_i)
CS <= NS;
else
CS <= 3'd0;
end
assign s_rx_fall = ~reg_rx_sync[1] & reg_rx_sync[2];
always @(posedge clk_i or negedge rstn_i)
if (rstn_i == 1'b0)
reg_rx_sync <= 3'b111;
else if (cfg_en_i)
reg_rx_sync <= {reg_rx_sync[1:0], rx_i};
else
reg_rx_sync <= 3'b111;
always @(posedge clk_i or negedge rstn_i)
if (rstn_i == 1'b0) begin
baud_cnt <= 'h0;
bit_done <= 1'b0;
end
else 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
always @(posedge clk_i or negedge rstn_i)
if (rstn_i == 1'b0)
err_o <= 1'b0;
else if (err_clr_i)
err_o <= 1'b0;
else if (set_error)
err_o <= 1'b1;
assign rx_data_o = reg_data;
endmodule