mirror of
https://github.com/supleed2/ELEC50003-P1-CW.git
synced 2024-12-23 22:15:50 +00:00
273 lines
8.1 KiB
Verilog
273 lines
8.1 KiB
Verilog
/*
|
|
Source: https://github.com/hildebrandmw/de10lite-hdl/blob/master/components/uart/hdl/uart.v
|
|
Description: Very simple UART tx/rx module. Requires a streaming interface,
|
|
provides no buffering for input or output data.
|
|
*/
|
|
|
|
module uart
|
|
#( parameter CLK_FREQ = 50_000_000,
|
|
parameter BAUD = 115_200
|
|
)
|
|
( input clk,
|
|
input reset,
|
|
|
|
// Receiving
|
|
input rx, // Received serial stream
|
|
output reg [7:0] rx_data, // Deserialized byte.
|
|
output rx_valid, // Asserted when rx_data is valid
|
|
|
|
// Transmitting
|
|
output reg tx, // Transmitted serial stream
|
|
input [7:0] tx_data, // Deserialized byte to transmit.
|
|
input tx_transmit, // Start Signal. No effect if tx_ready = 0
|
|
output reg tx_ready // Asserted when ready to accept data
|
|
);
|
|
|
|
///////////////////////////////
|
|
// Functionality Description //
|
|
///////////////////////////////
|
|
|
|
/*
|
|
RECEIVING: Module receives a serial stream through the port rx.
|
|
When a byte has been successfully received, the received data will be
|
|
available on the output port rx_data and the output port rx_valid will be
|
|
asserted for 1 clock cycle.
|
|
|
|
Validity of output data is not guaranteed if rx_valid is not 1. If this
|
|
is important for you, you may modify this design to register the output.
|
|
|
|
TRANSMITTING: When input port tx_transmit is 1 (asserted), module will
|
|
store the data on the input port tx_data and serialize through the output
|
|
port tx.
|
|
|
|
Module will only save and transmit the data at tx_data if the signal
|
|
tx_ready is asserted when tx_transmit is asserted. This module will not
|
|
buffer input data. While transmitting, tx_ready is deasserted and the
|
|
input port tx_transmit will have no effect.
|
|
|
|
Once tx_ready is deasserted, data at port tx_data is not used and need
|
|
not be stable.
|
|
*/
|
|
|
|
/////////////////////////
|
|
// Signal Declarations //
|
|
/////////////////////////
|
|
|
|
// ---------------------- //
|
|
// -- Local Parameters -- //
|
|
// ---------------------- //
|
|
|
|
// Number of synchronization stages to avoid metastability
|
|
localparam SYNC_STAGES = 2;
|
|
|
|
// Over Sampling Factor
|
|
localparam OSF = 16;
|
|
|
|
// Compute count to generate local clock enable
|
|
localparam CLK_DIV_COUNT = CLK_FREQ / (OSF * BAUD);
|
|
|
|
// ---------------------------- //
|
|
// -- Clock Dividing Counter -- //
|
|
// ---------------------------- //
|
|
|
|
reg [15:0] count;
|
|
reg enable; // Local Clock Enable
|
|
|
|
// -- RX Synchronizer --
|
|
reg [SYNC_STAGES-1:0] rx_sync;
|
|
reg rx_internal;
|
|
|
|
// ---------------- //
|
|
// -- RX Signals -- //
|
|
// ---------------- //
|
|
|
|
// State Machine Assignments
|
|
localparam RX_WAIT = 0;
|
|
localparam RX_CHECK_START = 1;
|
|
localparam RX_RECEIVING = 2;
|
|
localparam RX_WAIT_FOR_STOP = 3;
|
|
|
|
localparam RX_INITIAL_STATE = RX_WAIT;
|
|
reg [1:0] rx_state = RX_INITIAL_STATE;
|
|
|
|
reg [4:0] rx_count; // Counts Over-sampling clock enables
|
|
reg [2:0] rx_sampleCount; // Counts number of bits received
|
|
|
|
// These last two signals are used to make sure the "rx_valid" signal
|
|
// is only asserted for one clock cycle.
|
|
|
|
reg rx_validInternal, rx_validLast;
|
|
|
|
// -----------------//
|
|
// -- TX Signals -- //
|
|
// -----------------//
|
|
|
|
// State Machine Assignments
|
|
localparam TX_WAIT = 0;
|
|
localparam TX_TRANSMITTING = 1;
|
|
|
|
localparam TX_INITIAL_STATE = TX_WAIT;
|
|
reg tx_state = TX_INITIAL_STATE;
|
|
|
|
reg [9:0] tx_dataBuffer; // Capture Register for transmitted data
|
|
reg [4:0] tx_count; // Counts over-sampling clock
|
|
reg [3:0] tx_sampleCount; // Number of Bits Sent
|
|
|
|
/////////////////////
|
|
// Implementations //
|
|
/////////////////////
|
|
|
|
// ---------------------------- //
|
|
// -- Misc Synchronous Logic -- //
|
|
// ---------------------------- //
|
|
|
|
always @(posedge clk) begin
|
|
|
|
// Clock Divider
|
|
if (reset) begin
|
|
count <= 0;
|
|
enable <= 0;
|
|
end else if (count == CLK_DIV_COUNT - 1) begin
|
|
count <= 0;
|
|
enable <= 1;
|
|
end else begin
|
|
count <= count + 1;
|
|
enable <= 0;
|
|
end
|
|
|
|
// RX Synchronizer
|
|
if (enable) begin
|
|
{rx_sync,rx_internal} <= {rx, rx_sync};
|
|
end
|
|
|
|
// Pulse Shortener for rx_valid signal
|
|
rx_validLast <= rx_validInternal;
|
|
end
|
|
|
|
// Pulse Shortner for rx_valid signal
|
|
assign rx_valid = rx_validInternal & ~rx_validLast;
|
|
|
|
|
|
// ---------------------- //
|
|
// -- RX State Machine -- //
|
|
// ---------------------- //
|
|
|
|
always @(posedge clk) begin
|
|
if (reset) begin
|
|
rx_state <= RX_INITIAL_STATE;
|
|
rx_validInternal <= 0;
|
|
end else if (enable) begin
|
|
case (rx_state)
|
|
|
|
// Wait for the start bit. (RX = 0)
|
|
|
|
RX_WAIT: begin
|
|
rx_validInternal <= 0;
|
|
if (rx_internal == 0) begin
|
|
rx_state <= RX_CHECK_START;
|
|
rx_count <= 1;
|
|
end
|
|
end
|
|
|
|
// Aligh with center of transmitted bit
|
|
|
|
RX_CHECK_START: begin
|
|
|
|
// Check if RX is still 0
|
|
if (rx_count == (OSF >> 1) - 1 && rx_internal == 0) begin
|
|
rx_state <= RX_RECEIVING;
|
|
rx_count <= 0;
|
|
rx_sampleCount <= 0;
|
|
|
|
// Faulty Start Bit
|
|
end else if (rx_count == (OSF >> 1) - 1 && rx_internal == 1) begin
|
|
rx_state <= RX_WAIT;
|
|
|
|
// Default Option: Count local clocks
|
|
end else begin
|
|
rx_count <= rx_count + 1;
|
|
end
|
|
end
|
|
|
|
// Sample in middle of received bit. Shift data into rx_data
|
|
RX_RECEIVING: begin
|
|
if (rx_count == OSF - 1) begin
|
|
rx_count <= 0;
|
|
rx_data <= {rx_internal, rx_data[7:1]};
|
|
rx_sampleCount <= rx_sampleCount + 1;
|
|
|
|
// Check if this is the last bit of data
|
|
if (rx_sampleCount == 7) begin
|
|
rx_state <= RX_WAIT_FOR_STOP;
|
|
end
|
|
end else begin
|
|
rx_count <= rx_count + 1;
|
|
end
|
|
end
|
|
|
|
// Wait until stop bit is received
|
|
// Not the best logic in the world, but it works.
|
|
RX_WAIT_FOR_STOP: begin
|
|
if (rx_internal == 1'b1) begin
|
|
rx_state <= RX_WAIT;
|
|
rx_validInternal <= 1;
|
|
end
|
|
end
|
|
|
|
// In case something goes horribly wrong.
|
|
default: begin
|
|
rx_state <= RX_INITIAL_STATE;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// ---------------------- //
|
|
// -- TX State Machine -- //
|
|
// ---------------------- //
|
|
|
|
always @(posedge clk) begin
|
|
if (reset) begin
|
|
tx_state <= TX_INITIAL_STATE;
|
|
tx <= 1;
|
|
end else begin
|
|
case (tx_state)
|
|
// Wait for start signal.
|
|
// Register transmitted data and deassert ready.
|
|
TX_WAIT: begin
|
|
tx <= 1;
|
|
if (tx_transmit) begin
|
|
tx_dataBuffer <= {1'b1, tx_data, 1'b0};
|
|
tx_count <= 0;
|
|
tx_sampleCount <= 0;
|
|
tx_ready <= 0;
|
|
tx_state <= TX_TRANSMITTING;
|
|
end else begin
|
|
tx_ready <= 1;
|
|
end
|
|
end
|
|
|
|
// Shift Out Data
|
|
TX_TRANSMITTING: begin
|
|
if (enable) begin
|
|
if (tx_count == OSF - 1) begin
|
|
tx_count <= 0;
|
|
tx_sampleCount <= tx_sampleCount + 1;
|
|
tx <= tx_dataBuffer[0];
|
|
tx_dataBuffer <= {1'b1, tx_dataBuffer[9:1]};
|
|
if (tx_sampleCount == 9) begin
|
|
tx_state <= TX_WAIT;
|
|
end
|
|
end else begin
|
|
tx_count <= tx_count + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
default: begin
|
|
tx_state <= TX_WAIT;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
endmodule |