FPGA-RISC-V-CPU / hardware / src / io_circuits / uart_receiver.v
uart_receiver.v
Raw
module uart_receiver #(
    parameter CLOCK_FREQ = 125_000_000,
    parameter BAUD_RATE = 115_200)
(
    input clk,
    input reset,

    output [7:0] data_out,
    output data_out_valid,
    input data_out_ready,

    input serial_in
);
    // See diagram in the lab guide
    localparam SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE;
    localparam SAMPLE_TIME = SYMBOL_EDGE_TIME / 2;
    localparam CLOCK_COUNTER_WIDTH= $clog2(SYMBOL_EDGE_TIME);

    wire symbol_edge;
    wire sample;
    wire start;
    wire rx_running;

    reg [9:0] rx_shift;
    reg [3:0] bit_counter;
    reg [CLOCK_COUNTER_WIDTH-1:0] clock_counter;
    reg has_byte;

    //--|Signal Assignments|------------------------------------------------------

    // Goes high at every symbol edge
    /* verilator lint_off WIDTH */
    assign symbol_edge = clock_counter == (SYMBOL_EDGE_TIME - 1);
    /* lint_on */

    // Goes high halfway through each symbol
    /* verilator lint_off WIDTH */
    assign sample = clock_counter == SAMPLE_TIME;
    /* lint_on */

    // Goes high when it is time to start receiving a new character
    assign start = !serial_in && !rx_running;

    // Goes high while we are receiving a character
    assign rx_running = bit_counter != 4'd0;

    // Outputs
    assign data_out = rx_shift[8:1];
    assign data_out_valid = has_byte && !rx_running;

    //--|Counters|----------------------------------------------------------------

    // Counts cycles until a single symbol is done
    always @ (posedge clk) begin
        clock_counter <= (start || reset || symbol_edge) ? 0 : clock_counter + 1;
    end

    // Counts down from 10 bits for every character
    always @ (posedge clk) begin
        if (reset) begin
            bit_counter <= 0;
        end else if (start) begin
            bit_counter <= 10;
        end else if (symbol_edge && rx_running) begin
            bit_counter <= bit_counter - 1;
        end
    end

    //--|Shift Register|----------------------------------------------------------
    always @(posedge clk) begin
        if (sample && rx_running) rx_shift <= {serial_in, rx_shift[9:1]};
    end

    //--|Extra State For Ready/Valid|---------------------------------------------
    // This block and the has_byte signal aren't needed in the uart_transmitter
    always @ (posedge clk) begin
        if (reset) has_byte <= 1'b0;
        else if (bit_counter == 1 && symbol_edge) has_byte <= 1'b1;
        else if (data_out_ready) has_byte <= 1'b0;
    end
endmodule