EECS151 / fpga_labs_fa20 / lab5 / src / uart_transmitter.v
uart_transmitter.v
Raw
module uart_transmitter #(
    parameter CLOCK_FREQ = 125_000_000,
    parameter BAUD_RATE = 115_200)
(
    input clk,
    input reset,

    input [7:0] data_in,
    input data_in_valid,
    output data_in_ready,

    output serial_out
);
    // See diagram in the lab guide
    localparam  SYMBOL_EDGE_TIME    = CLOCK_FREQ / BAUD_RATE;
    localparam  CLOCK_COUNTER_WIDTH = $clog2(SYMBOL_EDGE_TIME);

    wire symbol_edge;
    wire start;
    wire tx_running;

    reg [CLOCK_COUNTER_WIDTH-1:0] clk_counter;
    reg [9:0] tx_shift;
    reg [3:0] bit_counter;

    /* verilator lint_off WIDTH */
    assign symbol_edge = (clk_counter == SYMBOL_EDGE_TIME - 1);
    /* lint_on */

    assign tx_running = (bit_counter != 4'd0);
    assign start = (data_in_valid & !tx_running);
    assign serial_out = (!tx_running) ? 1'd1 : tx_shift[0];
    assign data_in_ready = !tx_running;

    // Sync transmissions bandwidth
    always @(posedge clk) begin
        clk_counter <= (start || reset || symbol_edge) ? 0 : clk_counter + 1;
    end

    // Keep track of bits sent
    always @(posedge clk) begin 
        if (reset) bit_counter <= 0;
        else if (start) bit_counter <= 10;
        else if (symbol_edge && tx_running) bit_counter <= bit_counter - 1;
    end

    // Send data serially
    // Send LSB first for receiver to piece together
    always @(posedge clk) begin
        if (reset) tx_shift <= 0;
        else if (start) tx_shift <= {1'd1, data_in, 1'd0};
        else if (symbol_edge && tx_running) tx_shift <= {1'd0, tx_shift[9:1]};        
    end
   
endmodule