Add loopback UART

This commit is contained in:
Graham Edgecombe 2017-12-06 14:45:08 +00:00
parent 3d26eb67ed
commit cddfd0587d
2 changed files with 175 additions and 0 deletions

28
top.sv
View file

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

147
uart.sv Normal file
View file

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