282 lines
8.2 KiB
Verilog
282 lines
8.2 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_transmitter (clk, wb_rst_i, lcr, tf_push, wb_dat_i,
|
|
enable,stx_pad_o, tstate, tf_count, tx_reset, lsr_mask,
|
|
usart_t0,srx_pad_i,repeat_time,max_repeat_time,current_finish,
|
|
usart_mode,tx2rx_en);
|
|
|
|
input clk;
|
|
input wb_rst_i;
|
|
input [7:0] lcr;
|
|
input tf_push;
|
|
input [7:0] wb_dat_i;
|
|
input enable;
|
|
input tx_reset;
|
|
input lsr_mask;
|
|
input usart_mode;
|
|
input usart_t0,srx_pad_i;
|
|
input [2:0] repeat_time;
|
|
output current_finish;
|
|
output max_repeat_time;
|
|
|
|
output tx2rx_en;
|
|
reg tx2rx_en;
|
|
output stx_pad_o;
|
|
output [2:0] tstate;
|
|
output [`UART_FIFO_COUNTER_W-1:0] tf_count;
|
|
|
|
reg [2:0] tstate;
|
|
reg [4:0] counter;
|
|
reg [2:0] bit_counter;
|
|
reg [6:0] shift_out;
|
|
reg stx_o_tmp;
|
|
reg parity_xor;
|
|
reg tf_pop;
|
|
reg bit_out;
|
|
reg tx_error;
|
|
reg [2:0] error_time;
|
|
|
|
wire [`UART_FIFO_WIDTH-1:0] tf_data_in;
|
|
wire [`UART_FIFO_WIDTH-1:0] tf_data_out;
|
|
wire tf_push;
|
|
wire tf_overrun;
|
|
wire [`UART_FIFO_COUNTER_W-1:0]tf_count;
|
|
|
|
assign tf_data_in = wb_dat_i;
|
|
|
|
uart_tfifo fifo_tx(
|
|
.clk ( clk ),
|
|
.wb_rst_i( wb_rst_i ),
|
|
.data_in ( tf_data_in ),
|
|
.data_out( tf_data_out ),
|
|
.push ( tf_push ),
|
|
.pop ( tf_pop ),
|
|
.overrun ( tf_overrun ),
|
|
.count ( tf_count ),
|
|
.fifo_reset ( tx_reset),
|
|
.reset_status(lsr_mask )
|
|
);
|
|
|
|
parameter s_idle = 3'd0;
|
|
parameter s_send_start = 3'd1;
|
|
parameter s_send_byte = 3'd2;
|
|
parameter s_send_parity = 3'd3;
|
|
parameter s_send_stop = 3'd4;
|
|
parameter s_pop_byte = 3'd5;
|
|
parameter s_send_guard1 = 3'd6;
|
|
reg [7:0]tf_data_bak;
|
|
|
|
wire max_repeat_time = (error_time==(repeat_time+1'b1)) & usart_mode & usart_t0;
|
|
|
|
always @(posedge clk )
|
|
begin
|
|
if (wb_rst_i)
|
|
begin
|
|
tx_error <= 1'b0;
|
|
error_time <= 3'b0;
|
|
tstate <= s_idle;
|
|
stx_o_tmp <= 1'b1;
|
|
counter <= 5'b0;
|
|
shift_out <= 7'b0;
|
|
bit_out <= 1'b0;
|
|
parity_xor <= 1'b0;
|
|
tf_pop <= 1'b0;
|
|
bit_counter <= 3'b0;
|
|
tx2rx_en <= 1'b0;
|
|
tf_data_bak <= 8'h0;
|
|
end
|
|
else
|
|
if (enable)
|
|
begin
|
|
case (tstate)
|
|
s_idle :if ((~|tf_count)&(error_time==(repeat_time+1'b1)||~tx_error||~usart_mode))
|
|
begin
|
|
tstate <= s_idle;
|
|
stx_o_tmp <= 1'b1;
|
|
tx_error <= 1'b0;
|
|
end
|
|
else begin
|
|
tf_pop <= 1'b0;
|
|
stx_o_tmp <= 1'b1;
|
|
tstate <= s_pop_byte;
|
|
end
|
|
s_pop_byte : begin
|
|
|
|
if(tx_error&(error_time !=(repeat_time+1'b1)))
|
|
begin
|
|
tf_pop <= 1'b0;
|
|
case (lcr[1:0])
|
|
2'b00 : begin
|
|
bit_counter <= 3'b100;
|
|
parity_xor <= ^tf_data_bak[4:0];
|
|
end
|
|
2'b01 : begin
|
|
bit_counter <= 3'b101;
|
|
parity_xor <= ^tf_data_bak[5:0];
|
|
end
|
|
2'b10 : begin
|
|
bit_counter <= 3'b110;
|
|
parity_xor <= ^tf_data_bak[6:0];
|
|
end
|
|
2'b11 : begin
|
|
bit_counter <= 3'b111;
|
|
parity_xor <= ^tf_data_bak[7:0];
|
|
end
|
|
endcase
|
|
{shift_out[6:0], bit_out} <= tf_data_bak;
|
|
end
|
|
else begin
|
|
tf_pop <= 1'b1;
|
|
error_time <= 3'h0;
|
|
case (lcr[1:0])
|
|
2'b00 : begin
|
|
bit_counter <= 3'b100;
|
|
parity_xor <= ^tf_data_out[4:0];
|
|
end
|
|
2'b01 : begin
|
|
bit_counter <= 3'b101;
|
|
parity_xor <= ^tf_data_out[5:0];
|
|
end
|
|
2'b10 : begin
|
|
bit_counter <= 3'b110;
|
|
parity_xor <= ^tf_data_out[6:0];
|
|
end
|
|
2'b11 : begin
|
|
bit_counter <= 3'b111;
|
|
parity_xor <= ^tf_data_out[7:0];
|
|
end
|
|
endcase
|
|
{shift_out[6:0], bit_out} <= tf_data_out;
|
|
tf_data_bak <= tf_data_out;
|
|
end
|
|
tstate <= s_send_start;
|
|
end
|
|
s_send_start : begin
|
|
tf_pop <= 1'b0;
|
|
if (~|counter)
|
|
counter <= 5'b01111;
|
|
else if (counter == 5'b00001)
|
|
begin
|
|
counter <= 0;
|
|
tstate <= s_send_byte;
|
|
end
|
|
else
|
|
counter <= counter - 1'b1;
|
|
stx_o_tmp <= 1'b0;
|
|
end
|
|
s_send_byte : begin
|
|
if (~|counter)
|
|
counter <= 5'b01111;
|
|
else if (counter == 5'b00001)
|
|
begin
|
|
if (bit_counter > 3'b0) begin
|
|
bit_counter <= bit_counter - 1'b1;
|
|
{shift_out[5:0],bit_out } <= {shift_out[6:1], shift_out[0]};
|
|
tstate <= s_send_byte;
|
|
end
|
|
else
|
|
if (~lcr[`UART_LC_PE]) begin
|
|
tstate <= s_send_stop;
|
|
end
|
|
else begin
|
|
case ({lcr[`UART_LC_EP],lcr[`UART_LC_SP]})
|
|
2'b00: bit_out <= ~parity_xor;
|
|
2'b01: bit_out <= 1'b1;
|
|
2'b10: bit_out <= parity_xor;
|
|
2'b11: bit_out <= 1'b0;
|
|
endcase
|
|
tstate <= s_send_parity;
|
|
end
|
|
counter <= 0;
|
|
end
|
|
else counter <= counter - 1'b1;
|
|
stx_o_tmp <= bit_out;
|
|
end
|
|
s_send_parity : begin
|
|
if (~|counter) counter <= 5'b01111;
|
|
else if (counter == 5'b00001) begin
|
|
counter <= 4'b0;
|
|
tstate <= usart_mode ? s_send_guard1 : s_send_stop;
|
|
end
|
|
else counter <= counter - 1'b1;
|
|
stx_o_tmp <= bit_out;
|
|
end
|
|
s_send_stop : begin
|
|
if (~|counter) begin
|
|
if(usart_t0)
|
|
counter <= tx_error ? 5'b11101 : 5'b01101;
|
|
else
|
|
casex ({lcr[`UART_LC_SB],lcr[`UART_LC_BITS]})
|
|
3'b0xx: counter <= 5'b01101;
|
|
3'b100: counter <= 5'b10101;
|
|
default: counter <= 5'b11101;
|
|
endcase
|
|
end
|
|
else if (counter == 5'b00001) begin
|
|
counter <= 5'b0;
|
|
tx2rx_en<= 1'b0;
|
|
tstate <= s_idle;
|
|
end
|
|
else counter <= counter - 1'b1;
|
|
stx_o_tmp <= 1'b1;
|
|
end
|
|
s_send_guard1:begin
|
|
if (~|counter) begin
|
|
tx2rx_en <= 1'b1;
|
|
counter <= usart_t0 ? 5'b01111:5'b01101;
|
|
end
|
|
else if (counter == 5'b00001) begin
|
|
counter <= 5'b0;
|
|
tx_error <= !srx_pad_i;
|
|
error_time<= error_time + !srx_pad_i;
|
|
tx2rx_en <= usart_t0 ? 1'b1 : 1'b0;
|
|
tstate <= usart_t0 ? s_send_stop : s_idle;
|
|
end
|
|
else counter <= counter - 1'b1;
|
|
stx_o_tmp <= 1'b1;
|
|
end
|
|
default :
|
|
tstate <= s_idle;
|
|
endcase
|
|
end
|
|
else tf_pop <= 1'b0;
|
|
end
|
|
|
|
assign stx_pad_o = lcr[`UART_LC_BC] ? 1'b0 : stx_o_tmp;
|
|
assign current_finish = usart_mode ? ( (tstate==3'b0)&(tx_error & (error_time ==repeat_time+1'b1) |~tx_error) ) : 1'b1;
|
|
|
|
endmodule
|