module uart_tx ( input logic clk_i, input logic rstn_i, output logic tx_o, output logic busy_o, input logic cfg_en_i, input logic [15:0] cfg_div_i, input logic cfg_parity_en_i, input logic cfg_even_parity_i, input logic [1:0] cfg_bits_i, input logic cfg_stop_bits_i, input logic [7:0] tx_data_i, input logic tx_valid_i, output logic tx_ready_o ); enum logic [2:0] {IDLE,START_BIT,DATA,PARITY,STOP_BIT_FIRST,STOP_BIT_LAST} CS,NS; logic [7:0] reg_data; logic [2:0] reg_bit_count; logic [2:0] s_target_bits; logic parity_bit; logic [15:0] baud_cnt; logic baudgen_en; logic bit_done; assign busy_o = (CS != IDLE); always_comb begin 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 end always_comb begin NS = CS; tx_o = 1'b1; tx_ready_o = 1'b0; baudgen_en = 1'b0; case(CS) IDLE: begin if (cfg_en_i) tx_ready_o = 1'b1; if (tx_valid_i) begin NS = START_BIT; end end START_BIT: begin tx_o = 1'b0; baudgen_en = 1'b1; if (bit_done) NS = DATA; end DATA: begin tx_o = reg_data[0]; baudgen_en = 1'b1; if (bit_done) begin if (reg_bit_count == s_target_bits) begin if (cfg_parity_en_i) begin NS = PARITY; end else begin NS = STOP_BIT_FIRST; end end end end PARITY: begin tx_o = parity_bit; baudgen_en = 1'b1; if (bit_done) NS = STOP_BIT_FIRST; end STOP_BIT_FIRST: begin tx_o = 1'b1; baudgen_en = 1'b1; if (bit_done) begin if (cfg_stop_bits_i) NS = STOP_BIT_LAST; else NS = IDLE; end end STOP_BIT_LAST: begin tx_o = 1'b1; baudgen_en = 1'b1; if (bit_done) begin NS = IDLE; end end default: NS = IDLE; endcase end always_ff @(posedge clk_i or negedge rstn_i) begin if (rstn_i == 1'b0) begin CS <= IDLE; reg_data <= 8'hFF; reg_bit_count <= 'h0; parity_bit <= 1'b0; end else begin if(cfg_en_i) CS <= NS; else CS <= IDLE; case (CS) IDLE: if (tx_valid_i) reg_data <= tx_data_i; START_BIT: parity_bit <= ~cfg_even_parity_i; DATA: if (bit_done) begin parity_bit <= parity_bit ^ reg_data[0]; if (reg_bit_count == s_target_bits) reg_bit_count <= 'h0; else begin reg_bit_count <= reg_bit_count + 1; reg_data <= {1'b1,reg_data[7:1]}; end end endcase end end always_ff @(posedge clk_i or negedge rstn_i) begin if (rstn_i == 1'b0) begin baud_cnt <= 'h0; bit_done <= 1'b0; end else begin if(baudgen_en) begin if(baud_cnt == cfg_div_i) 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 end end endmodule