From cddfd0587d9f80371dc661aca1c4744c29fb95f1 Mon Sep 17 00:00:00 2001 From: Graham Edgecombe Date: Wed, 6 Dec 2017 14:45:08 +0000 Subject: [PATCH] Add loopback UART --- top.sv | 28 +++++++++++ uart.sv | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 uart.sv diff --git a/top.sv b/top.sv index 3744046..6dcd137 100644 --- a/top.sv +++ b/top.sv @@ -3,6 +3,7 @@ `include "ram.sv" `include "rv32.sv" `include "sync.sv" +`include "uart.sv" module top ( input clk, @@ -47,6 +48,7 @@ module top ( ); logic pll_locked; + logic reset = ~pll_locked; sync sync ( .clk(pll_clk), @@ -101,4 +103,30 @@ module top ( if (leds_sel && mem_write_mask[0]) leds <= mem_write_value[7:0]; end + + logic uart_rx_received; + logic uart_tx_ready; + logic [7:0] uart_rx_byte; + + uart uart ( + .clk(pll_clk), + .reset(reset), + + /* serial port */ + .rx_in(uart_rx), + .tx_out(uart_tx), + + /* control in */ + .tx_transmit_in(uart_rx_received), + + /* data in */ + .tx_byte_in(uart_rx_byte), + + /* control out */ + .rx_received_out(uart_rx_received), + .tx_ready_out(uart_tx_ready), + + /* data out */ + .rx_byte_out(uart_rx_byte) + ); endmodule diff --git a/uart.sv b/uart.sv new file mode 100644 index 0000000..16de503 --- /dev/null +++ b/uart.sv @@ -0,0 +1,147 @@ +`ifndef UART +`define UART + +localparam UART_STATE_IDLE = 2'b00; +localparam UART_STATE_START = 2'b01; +localparam UART_STATE_DATA = 2'b10; +localparam UART_STATE_STOP = 2'b11; + +module uart #( + parameter CLK_FREQ = 36000000, + parameter BAUD_RATE = 9600 +) ( + input clk, + input reset, + + /* serial port */ + input rx_in, + output tx_out, + + /* control in */ + input tx_transmit_in, + + /* data in */ + input [7:0] tx_byte_in, + + /* control out */ + output rx_received_out, + output tx_ready_out, + + /* data out */ + output [7:0] rx_byte_out +); + localparam CLK_DIV = CLK_FREQ / BAUD_RATE; + + logic [11:0] rx_clk_div; + logic [11:0] tx_clk_div; + + logic [1:0] rx_state; + logic [1:0] tx_state; + + logic [2:0] rx_bit; + logic [2:0] tx_bit; + + logic [7:0] rx_pending_byte; + logic [7:0] tx_byte; + + initial begin + rx_state <= UART_STATE_IDLE; + tx_state <= UART_STATE_IDLE; + rx_received_out <= 0; + tx_out <= 1; + tx_ready_out <= 1; + end + + always @(posedge clk) begin + rx_received_out <= 0; + + if (rx_clk_div) + rx_clk_div <= rx_clk_div - 1; + + if (tx_clk_div) + tx_clk_div <= tx_clk_div - 1; + + case (rx_state) + UART_STATE_IDLE: begin + if (!rx_in) begin + rx_state <= UART_STATE_START; + rx_clk_div <= CLK_DIV / 2; + end + end + UART_STATE_START: begin + if (!rx_clk_div) begin + if (!rx_in) begin + rx_state <= UART_STATE_DATA; + rx_clk_div <= CLK_DIV; + rx_bit <= 7; + end else begin + rx_state <= UART_STATE_IDLE; + end + end + end + UART_STATE_DATA: begin + if (!rx_clk_div) begin + rx_state <= rx_bit ? UART_STATE_DATA : UART_STATE_STOP; + rx_clk_div <= CLK_DIV; + rx_bit <= rx_bit - 1; + rx_pending_byte <= {rx_in, rx_pending_byte[7:1]}; + end + end + UART_STATE_STOP: begin + if (!rx_clk_div) begin + rx_state <= UART_STATE_IDLE; + if (rx_in) begin + rx_received_out <= 1; + rx_byte_out <= rx_pending_byte; + end + end + end + endcase + + case (tx_state) + UART_STATE_IDLE: begin + if (tx_transmit_in) begin + tx_state <= UART_STATE_START; + tx_clk_div <= CLK_DIV; + tx_byte <= tx_byte_in; + tx_out <= 0; + tx_ready_out <= 0; + end + end + UART_STATE_START: begin + if (!tx_clk_div) begin + tx_state <= UART_STATE_DATA; + tx_clk_div <= CLK_DIV; + tx_bit <= 7; + tx_byte <= {1'b0, tx_byte[7:1]}; + tx_out <= tx_byte[0]; + end + end + UART_STATE_DATA: begin + if (!tx_clk_div) begin + tx_state <= tx_bit ? UART_STATE_DATA : UART_STATE_STOP; + tx_clk_div <= CLK_DIV; + tx_bit <= tx_bit - 1; + tx_byte <= {1'b0, tx_byte[7:1]}; + tx_out <= tx_bit ? tx_byte[0] : 1; + end + end + UART_STATE_STOP: begin + if (!tx_clk_div) begin + tx_state <= UART_STATE_IDLE; + tx_ready_out <= 1; + end + end + endcase + + if (reset) begin + rx_state <= UART_STATE_IDLE; + tx_state <= UART_STATE_IDLE; + rx_received_out <= 0; + tx_out <= 1; + tx_ready_out <= 1; + end + end +endmodule + +`endif