Files
ciciec2026_loongson/rtl/ip/APB_UART/URT/uart_receiver.v
2026-04-12 22:20:18 +08:00

289 lines
11 KiB
Verilog

/*------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Copyright (c) 2016, Loongson Technology Corporation Limited.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of Loongson Technology Corporation Limited nor the names of
its contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL LOONGSON TECHNOLOGY CORPORATION LIMITED BE LIABLE
TO ANY PARTY FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
`include "uart_defines.h"
module uart_receiver (clk, wb_rst_i, lcr, rf_pop, srx_pad_i, enable,
counter_t, rf_count, rf_data_out, rf_error_bit,
rf_overrun, rx_reset, lsr_mask, rstate, rf_push_pulse);
input clk;
input wb_rst_i;
input [7:0] lcr;
input rf_pop;
input srx_pad_i;
input enable;
input rx_reset;
input lsr_mask;
output [9:0] counter_t;
output [`UART_FIFO_COUNTER_W-1:0] rf_count;
output [`UART_FIFO_REC_WIDTH-1:0] rf_data_out;
output rf_overrun;
output rf_error_bit;
output [3:0] rstate;
output rf_push_pulse;
reg [3:0] rstate;
reg [3:0] rcounter16;
reg [2:0] rbit_counter;
reg [7:0] rshift;
reg rparity;
reg rparity_error;
reg rframing_error;
reg rbit_in;
reg rparity_xor;
reg [7:0] counter_b;
reg rf_push_q;
reg [`UART_FIFO_REC_WIDTH-1:0] rf_data_in;
wire[`UART_FIFO_REC_WIDTH-1:0] rf_data_out;
wire rf_push_pulse;
reg rf_push;
wire rf_pop;
wire rf_overrun;
wire[`UART_FIFO_COUNTER_W-1:0] rf_count;
wire rf_error_bit;
wire break_error = (counter_b == 0);
uart_rfifo #(`UART_FIFO_REC_WIDTH) fifo_rx(
.clk ( clk ),
.wb_rst_i ( wb_rst_i ),
.data_in ( rf_data_in ),
.data_out ( rf_data_out ),
.push ( rf_push_pulse),
.pop ( rf_pop ),
.overrun ( rf_overrun ),
.count ( rf_count ),
.error_bit ( rf_error_bit ),
.fifo_reset ( rx_reset ),
.reset_status( lsr_mask )
);
wire rcounter16_eq_7 = (rcounter16 == 4'd7);
wire rcounter16_eq_0 = (rcounter16 == 4'd0);
wire rcounter16_eq_1 = (rcounter16 == 4'd1);
wire [3:0] rcounter16_minus_1 = rcounter16 - 1'b1;
parameter sr_idle = 4'd0;
parameter sr_rec_start = 4'd1;
parameter sr_rec_bit = 4'd2;
parameter sr_rec_parity = 4'd3;
parameter sr_rec_stop = 4'd4;
parameter sr_check_parity = 4'd5;
parameter sr_rec_prepare = 4'd6;
parameter sr_end_bit = 4'd7;
parameter sr_ca_lc_parity = 4'd8;
parameter sr_wait1 = 4'd9;
parameter sr_push = 4'd10;
always @(posedge clk ) begin
if (wb_rst_i) begin
rstate <= sr_idle;
rbit_in <= 1'b0;
rcounter16 <= 0;
rbit_counter <= 0;
rparity_xor <= 1'b0;
rframing_error <= 1'b0;
rparity_error <= 1'b0;
rparity <= 1'b0;
rshift <= 0;
rf_push <= 1'b0;
rf_data_in <= 0;
end
else if (enable) begin
case (rstate)
sr_idle : begin
rf_push <= 1'b0;
rf_data_in <= 0;
rcounter16 <= 4'b1110;
if (srx_pad_i==1'b0 & ~break_error) begin
rstate <= sr_rec_start;
end
end
sr_rec_start : begin
rf_push <= 1'b0;
if (rcounter16_eq_7)
if (srx_pad_i==1'b1)
rstate <= sr_idle;
else
rstate <= sr_rec_prepare;
else rstate<=rstate;
rcounter16 <= rcounter16_minus_1;
end
sr_rec_prepare: begin
case (lcr[1:0])
2'b00 : rbit_counter <= 3'b100;
2'b01 : rbit_counter <= 3'b101;
2'b10 : rbit_counter <= 3'b110;
2'b11 : rbit_counter <= 3'b111;
endcase
if (rcounter16_eq_0) begin
rstate <= sr_rec_bit;
rcounter16 <= 4'b1110;
rshift <= 0;
end
else
rstate <= sr_rec_prepare;
rcounter16 <= rcounter16_minus_1;
end
sr_rec_bit : begin
if (rcounter16_eq_0) rstate <= sr_end_bit;
if (rcounter16_eq_7)
case (lcr[1:0])
2'b00 : rshift[4:0] <= {srx_pad_i, rshift[4:1]};
2'b01 : rshift[5:0] <= {srx_pad_i, rshift[5:1]};
2'b10 : rshift[6:0] <= {srx_pad_i, rshift[6:1]};
2'b11 : rshift[7:0] <= {srx_pad_i, rshift[7:1]};
endcase
rcounter16 <= rcounter16_minus_1;
end
sr_end_bit : begin
if (rbit_counter==3'b0)
if (lcr[`UART_LC_PE])
rstate <= sr_rec_parity;
else begin
rstate <= sr_rec_stop;
rparity_error<= 1'b0;
end
else begin
rstate <= sr_rec_bit;
rbit_counter <= rbit_counter - 1'b1;
end
rcounter16 <= 4'b1110;
end
sr_rec_parity : begin
if (rcounter16_eq_7) begin
rparity <= srx_pad_i;
rstate <= sr_ca_lc_parity;
end
rcounter16 <= rcounter16_minus_1;
end
sr_ca_lc_parity:begin
rcounter16 <= rcounter16_minus_1;
rparity_xor <= ^{rshift,rparity};
rstate <= sr_check_parity;
end
sr_check_parity: begin
case ({lcr[`UART_LC_EP],lcr[`UART_LC_SP]})
2'b00: rparity_error <= rparity_xor == 0;
2'b01: rparity_error <= ~rparity;
2'b10: rparity_error <= rparity_xor == 1;
2'b11: rparity_error <= rparity;
endcase
rcounter16 <= rcounter16_minus_1;
rstate <= sr_wait1;
end
sr_wait1 :
if (rcounter16_eq_0) begin
rstate <= sr_rec_stop;
rcounter16 <= 4'b1110;
end
else rcounter16 <= rcounter16_minus_1;
sr_rec_stop : begin
if (rcounter16_eq_7) begin
rframing_error <= !srx_pad_i;
rstate <= sr_push;
end
rcounter16 <= rcounter16_minus_1;
end
sr_push : begin
if(srx_pad_i | break_error) begin
if(break_error)
rf_data_in <= {8'b0, 3'b100};
else
rf_data_in <= {rshift, 1'b0, rparity_error, rframing_error};
rf_push <= 1'b1;
rstate <= sr_idle;
end
else if(~rframing_error) begin
rf_data_in <= {rshift, 1'b0, rparity_error, rframing_error};
rf_push <= 1'b1;
rcounter16 <= 4'b1110;
rstate <= sr_rec_start;
end
end
default : rstate <= sr_idle;
endcase
end
end
always @ (posedge clk ) begin
if(wb_rst_i) rf_push_q <= 0;
else rf_push_q <= rf_push;
end
assign rf_push_pulse = rf_push & ~rf_push_q;
reg [9:0] toc_value;
always @(lcr)
case (lcr[3:0])
4'b0000 : toc_value = 447;
4'b0100 : toc_value = 479;
4'b0001, 4'b1000 : toc_value = 511;
4'b1100 : toc_value = 543;
4'b0010, 4'b0101, 4'b1001 : toc_value = 575;
4'b0011, 4'b0110, 4'b1010, 4'b1101 : toc_value = 639;
4'b0111, 4'b1011, 4'b1110 : toc_value = 703;
4'b1111 : toc_value = 767;
endcase
wire [7:0] brc_value;
assign brc_value = toc_value[9:2];
always @(posedge clk ) begin
if (wb_rst_i) counter_b <= 8'd159;
else if (srx_pad_i) counter_b <= brc_value;
else if (enable & counter_b != 8'b0)
counter_b <= counter_b - 1;
end
reg [9:0] counter_t;
always @(posedge clk ) begin
if (wb_rst_i) counter_t <= 10'd639;
else if(rf_push_pulse || rf_pop || rf_count == 0)
counter_t <= toc_value;
else if (enable && counter_t != 10'b0)
counter_t <= counter_t - 1;
end
endmodule