module uart_tx #(parameter DATA_WIDTH = 8, FIFO_DEPTH = 1) ( input clk, input rstn, input baud16, input tx_write, input [DATA_WIDTH-1:0] tx_data, input lcr_sps, input lcr_stp2, input lcr_eps, input lcr_pen, input tx_clear, output tx_full, output tx_empty, output tx_busy, output reg tx_complete, input tx_dma_en, input tx_dma_clr, output reg tx_dma_req, output reg uart_txd ); parameter UART_IDLE = 3'h0; parameter UART_START = 3'h1; parameter UART_DATA = 3'h2; parameter UART_PARITY = 3'h3; parameter UART_STOP = 3'h4; reg [2:0] tx_state; reg [DATA_WIDTH-1:0] tx_shift_reg; reg tx_parity; reg [3:0] tx_baud_cnt; reg tx_bit; reg [$clog2(DATA_WIDTH)-1:0] tx_data_cnt; reg tx_stop_cnt; wire fifo_rden = !tx_empty && (!tx_busy || tx_state == UART_STOP && tx_stop_cnt == 0 && tx_bit); wire [DATA_WIDTH-1:0] fifo_out; wire tx_stop = tx_empty && !tx_busy; sync_fifo #(.WIDTH(DATA_WIDTH), .DEPTH(FIFO_DEPTH), .SHOWAEAD(1)) tx_fifo( .clk (clk ), .rstn (rstn ), .wren (tx_write ), .rden (fifo_rden), .din (tx_data ), .dout (fifo_out ), .full (tx_full ), .empty(tx_empty ) ); assign tx_busy = tx_state != UART_IDLE; always @(posedge clk or negedge rstn) begin if (!rstn) begin tx_state <= UART_IDLE; end else begin case (tx_state) UART_IDLE: if (fifo_rden) tx_state <= UART_START; UART_START: if (tx_bit) tx_state <= UART_DATA; UART_DATA: if (tx_bit && tx_data_cnt == 0) tx_state <= lcr_pen ? UART_PARITY : UART_STOP; UART_PARITY: if (tx_bit) tx_state <= UART_STOP; UART_STOP: if (tx_bit && tx_stop_cnt == 0) tx_state <= tx_empty ? UART_IDLE : UART_START; endcase end end always @(posedge clk or negedge rstn) begin if (!rstn) begin tx_shift_reg <= 0; end else if (fifo_rden) begin tx_shift_reg <= fifo_out; end else if (tx_bit && tx_state == UART_DATA) begin tx_shift_reg <= { tx_shift_reg[0], tx_shift_reg[DATA_WIDTH-1:1] }; end end always @(posedge clk) begin if (tx_state == UART_START) begin tx_parity <= !lcr_eps; end else if (tx_state == UART_DATA && tx_bit && !lcr_sps) begin tx_parity <= tx_parity ^ tx_shift_reg[0]; end end always @(posedge clk) begin if (tx_state == UART_START) begin tx_data_cnt <= DATA_WIDTH - 1; end else if (tx_state == UART_DATA && tx_bit) begin tx_data_cnt <= tx_data_cnt - 1; end end always @(posedge clk) begin if (tx_state == UART_START) begin tx_stop_cnt <= lcr_stp2; end else if (tx_state == UART_STOP && tx_bit) begin tx_stop_cnt <= tx_stop_cnt - 1; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin tx_baud_cnt <= 0; end else if (tx_stop) begin tx_baud_cnt <= 0; end else if (baud16) begin tx_baud_cnt <= tx_baud_cnt + 1; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin tx_bit <= 1'b0; end else if (baud16 && tx_baud_cnt == 15) begin tx_bit <= 1'b1; end else begin tx_bit <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin tx_complete <= 1'b0; end else if (tx_state == UART_STOP && tx_bit && tx_stop_cnt == 0 && tx_empty) begin tx_complete <= 1'b1; end else if (tx_clear || !tx_empty) begin tx_complete <= 1'b0; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin tx_dma_req <= 1'b0; end else if (!tx_dma_en || tx_dma_clr) begin tx_dma_req <= 1'b0; end else if (!tx_full) begin tx_dma_req <= 1'b1; end end always @(posedge clk or negedge rstn) begin if (!rstn) begin uart_txd <= 1'b1; end else begin case (tx_state) UART_IDLE: uart_txd <= 1'b1; UART_START: uart_txd <= 1'b0; UART_DATA: uart_txd <= tx_shift_reg[0]; UART_PARITY: uart_txd <= tx_parity; UART_STOP: uart_txd <= 1'b1; endcase end end endmodule