go-board-code/uart_rx.v

101 lines
2.5 KiB
Verilog

module UART_RX (
input i_Clk,
input i_ReceiveBit,
output o_DataReady,
output [7:0] o_DataByte
);
parameter CLOCKS_PER_SECOND = 25000000;
parameter BAUD_RATE = 115200;
localparam integer CLOCKS_PER_BIT = CLOCKS_PER_SECOND / BAUD_RATE;
localparam integer HALF_CLOCKS_PER_BIT = (CLOCKS_PER_BIT - 1) / 2;
localparam IDLE = 0;
localparam VERIFY_START_BIT = 1;
localparam READ_DATA_BITS = 2;
localparam WAIT_FOR_STOP_BIT = 3;
localparam CLEANUP = 4;
// golang-style: lowercase is private, uppercase is public
reg [$clog2(CLEANUP)-1:0] r_currentState = IDLE;
reg r_dataReady = 0;
reg [$clog2(CLOCKS_PER_BIT)-1:0] r_clockCount = 0;
reg [$clog2(8)-1:0] r_bitIndex = 0;
reg [7:0] r_receivedByte = 0;
always @(posedge i_Clk) begin
case (r_currentState)
IDLE:
begin
r_dataReady <= 0;
r_clockCount <= 0;
r_bitIndex <= 0;
if (i_ReceiveBit == 0) begin
r_currentState <= VERIFY_START_BIT;
end
end
// Check the middle of the start bit to make sure it's still low
VERIFY_START_BIT:
begin
if (r_clockCount == HALF_CLOCKS_PER_BIT) begin
// still low, let's go
if (i_ReceiveBit == 0) begin
r_clockCount <= 0;
r_currentState <= READ_DATA_BITS;
end else begin
r_currentState <= IDLE;
end
end else begin
r_clockCount <= r_clockCount + 1;
end
end
// note that we are still in the halfway points of the signal at this
// point. we are sampling the very middles.
READ_DATA_BITS:
begin
if (r_clockCount < CLOCKS_PER_BIT - 1) begin
r_clockCount <= r_clockCount + 1;
end else begin
r_clockCount <= 0;
r_receivedByte[r_bitIndex] <= i_ReceiveBit;
if (r_bitIndex == 7) begin
r_bitIndex <= 0;
r_currentState <= WAIT_FOR_STOP_BIT;
end else begin
r_bitIndex <= r_bitIndex + 1;
end
end
end
WAIT_FOR_STOP_BIT:
begin
if (r_clockCount < CLOCKS_PER_BIT - 1) begin
r_clockCount <= r_clockCount + 1;
end else begin
r_dataReady <= 1;
r_clockCount <= 0;
r_currentState <= CLEANUP;
end
end
CLEANUP:
begin
r_currentState <= IDLE;
r_dataReady <= 0;
end
default:
begin
r_currentState <= IDLE;
end
endcase
end
assign o_DataByte = r_receivedByte;
assign o_DataReady = r_dataReady;
endmodule