// uart_tx.v
//
// Byte-at-a-time UART transmitter. 8N1, no flow control.
// Default 115200 baud from a 50 MHz clock (divisor = 434, ~0.06% error).
//
// Handshake: assert `start` for one clk with `data` valid. The byte is
// captured on that edge; `busy` then goes high until the stop bit
// completes. Hold off further `start` pulses while `busy` is high.

module uart_tx #(
    parameter integer CLK_HZ   = 50_000_000,
    parameter integer BAUD     = 115_200
)(
    input  wire       clk,
    input  wire       rst_n,
    input  wire       start,
    input  wire [7:0] data,
    output reg        tx,
    output reg        busy
);

    localparam integer DIV = (CLK_HZ + BAUD/2) / BAUD;
    localparam integer DW  = $clog2(DIV);

    localparam [3:0] S_IDLE  = 4'd0,
                     S_START = 4'd1,
                     S_D0    = 4'd2, S_D1 = 4'd3, S_D2 = 4'd4, S_D3 = 4'd5,
                     S_D4    = 4'd6, S_D5 = 4'd7, S_D6 = 4'd8, S_D7 = 4'd9,
                     S_STOP  = 4'd10;

    reg [3:0]      state;
    reg [DW-1:0]   tick;
    reg [7:0]      shift;

    wire tick_done = (tick == DIV-1);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= S_IDLE;
            tick  <= 0;
            shift <= 8'd0;
            tx    <= 1'b1;
            busy  <= 1'b0;
        end else begin
            case (state)
                S_IDLE: begin
                    tx   <= 1'b1;
                    busy <= 1'b0;
                    tick <= 0;
                    if (start) begin
                        shift <= data;
                        state <= S_START;
                        busy  <= 1'b1;
                        tx    <= 1'b0;  // start bit asserted immediately
                    end
                end
                default: begin
                    if (tick_done) begin
                        tick <= 0;
                        case (state)
                            S_START: begin tx <= shift[0]; state <= S_D0; end
                            S_D0:    begin tx <= shift[1]; state <= S_D1; end
                            S_D1:    begin tx <= shift[2]; state <= S_D2; end
                            S_D2:    begin tx <= shift[3]; state <= S_D3; end
                            S_D3:    begin tx <= shift[4]; state <= S_D4; end
                            S_D4:    begin tx <= shift[5]; state <= S_D5; end
                            S_D5:    begin tx <= shift[6]; state <= S_D6; end
                            S_D6:    begin tx <= shift[7]; state <= S_D7; end
                            S_D7:    begin tx <= 1'b1;     state <= S_STOP; end
                            S_STOP:  begin state <= S_IDLE; busy <= 1'b0; end
                            default: state <= S_IDLE;
                        endcase
                    end else begin
                        tick <= tick + 1'b1;
                    end
                end
            endcase
        end
    end

endmodule
