// 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