`timescale 1ns/1ps
// 8E1 teaching example. CLK_FREQ / BAUD_RATE must be at least 2.
// tx_start is a one-clock request, accepted only while tx_ready is high.
module uart_tx_example #(
    parameter integer CLK_FREQ = 50_000_000,
    parameter integer BAUD_RATE = 115_200
) (
    input logic clk, rst_n,
    input logic tx_start,
    input logic [7:0] tx_data,
    output logic tx_ready,
    output logic tx_out
);
    localparam integer BIT_CYCLES = CLK_FREQ / BAUD_RATE;
    localparam integer CW = (BIT_CYCLES > 1) ? $clog2(BIT_CYCLES) : 1;
    logic [CW-1:0] count;
    logic [10:0] frame;
    logic [3:0] bit_index;
    logic busy;
    assign tx_ready = !busy;
    assign tx_out = busy ? frame[0] : 1'b1;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            count <= '0;
            frame <= '1;
            bit_index <= '0;
            busy <= 1'b0;
        end else if (!busy) begin
            if (tx_start) begin
                // Capture data and parity together, on ANY system clock.
                frame <= {1'b1, ^tx_data, tx_data, 1'b0};
                count <= '0;
                bit_index <= '0;
                busy <= 1'b1;
            end
        end else if (count == BIT_CYCLES - 1) begin
            count <= '0;
            if (bit_index == 10) busy <= 1'b0;
            else begin
                frame <= {1'b1, frame[10:1]};
                bit_index <= bit_index + 1'b1;
            end
        end else count <= count + 1'b1;
    end
endmodule
