diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rtl/uart.v | 266 | ||||
-rw-r--r-- | src/rtl/uart_core.v | 586 |
2 files changed, 852 insertions, 0 deletions
diff --git a/src/rtl/uart.v b/src/rtl/uart.v new file mode 100644 index 0000000..abf3934 --- /dev/null +++ b/src/rtl/uart.v @@ -0,0 +1,266 @@ +//====================================================================== +// +// uart.v +// ------ +// Top level wrapper for the uart core. +// +// A simple universal asynchronous receiver/transmitter (UART) +// interface. The interface contains 16 byte wide transmit and +// receivea buffers and can handle start and stop bits. But in +// general is rather simple. The primary purpose is as host +// interface for the coretest design. The core also has a +// loopback mode to allow testing of a serial link. +// +// Note that the UART has a separate API interface to allow +// a control core to change settings such as speed. But the core +// has default values to allow it to start operating directly +// after reset. No config should be needed. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2014 SUNET +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//====================================================================== + +module uart( + input wire clk, + input wire reset_n, + + // External interface. + input wire rxd, + output wire txd, + + // Internal receive interface. + output wire rxd_syn, + output [7 : 0] rxd_data, + input wire rxd_ack, + + // Internal transmit interface. + input wire txd_syn, + input wire [7 : 0] txd_data, + output wire txd_ack, + + // API interface. + input wire cs, + input wire we, + input wire [3 : 0] address, + input wire [31 : 0] write_data, + output wire [31 : 0] read_data, + output wire error, + + // Debug output. + output wire [7 : 0] debug + ); + + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + // API addresses. + parameter ADDR_CORE_NAME0 = 4'h0; + parameter ADDR_CORE_NAME1 = 4'h1; + parameter ADDR_CORE_TYPE = 4'h2; + parameter ADDR_CORE_VERSION = 4'h3; + + // Core ID constants. + parameter CORE_NAME0 = 32'h75617274; // "uart" + parameter CORE_NAME1 = 32'h20202020; // " " + parameter CORE_TYPE = 32'h20202031; // " 1" + parameter CORE_VERSION = 32'h302e3031; // "0.01" + + // The default clock rate is based on target clock frequency + // divided by the bit rate times in order to hit the + // center of the bits. I.e. + // Clock: 50 MHz + // Bitrate: 19200 bps + // Divisor = 50*10E6 / 9600 = 5208 + parameter DEFAULT_CLK_RATE = 5208; + parameter DEFAULT_HALF_CLK_RATE = DEFAULT_CLK_RATE / 2; + + parameter DEFAULT_DATA_BITS = 8; + parameter DEFAULT_STOP_BITS = 1; + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + wire [15 : 0] bit_rate; + wire [1 : 0] stop_bits; + + wire core_rxd; + wire core_txd; + + wire core_rxd_syn; + wire [7 : 0] core_rxd_data; + wire core_rxd_ack; + + wire core_txd_syn; + wire [7 : 0] core_txd_data; + wire core_txd_ack; + + reg [31 : 0] tmp_read_data; + reg tmp_error; + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign txd = core_txd; + assign core_rxd = rxd; + + assign rxd_syn = core_rxd_syn; + assign rxd_data = core_rxd_data; + assign core_rxd_ack = rxd_ack; + + assign core_txd_syn = txd_syn; + assign core_txd_data = txd_data; + assign txd_ack = core_txd_ack; + + assign read_data = tmp_read_data; + assign error = tmp_error; + + assign debug = core_rxd_data; + + + //---------------------------------------------------------------- + // core + // + // Instantiation of the uart core. + //---------------------------------------------------------------- + uart_core core( + .clk(clk), + .reset_n(reset_n), + + // Configuration parameters + .bit_rate(bit_rate), + .stop_bits(stop_bits), + + // External data interface + .rxd(core_rxd), + .txd(core_txd), + + // Internal receive interface. + .rxd_syn(core_rxd_syn), + .rxd_data(core_rxd_data), + .rxd_ack(core_rxd_ack), + + // Internal transmit interface. + .txd_syn(core_txd_syn), + .txd_data(core_txd_data), + .txd_ack(core_txd_ack) + ); + + + //---------------------------------------------------------------- + // reg_update + // + // Update functionality for all registers in the core. + // All registers are positive edge triggered with synchronous + // active low reset. All registers have write enable. + //---------------------------------------------------------------- + always @ (posedge clk) + begin: reg_update + if (!reset_n) + begin + + end + else + begin + + end + end // reg_update + + + //---------------------------------------------------------------- + // api + // + // The core API that allows an internal host to control the + // core functionality. + //---------------------------------------------------------------- + always @* + begin: api + // Default assignments. + tmp_read_data = 32'h00000000; + tmp_error = 0; + + if (cs) + begin + if (we) + begin + // Write operations. + case (address) + + default: + begin + tmp_error = 1; + end + endcase // case (address) + end + else + begin + // Read operations. + case (address) + ADDR_CORE_NAME0: + begin + tmp_read_data = CORE_NAME0; + end + + ADDR_CORE_NAME1: + begin + tmp_read_data = CORE_NAME1; + end + + ADDR_CORE_TYPE: + begin + tmp_read_data = CORE_TYPE; + end + + ADDR_CORE_VERSION: + begin + tmp_read_data = CORE_VERSION; + end + + default: + begin + tmp_error = 1; + end + endcase // case (address) + end + end + end + +endmodule // uart + +//====================================================================== +// EOF uart.v +//====================================================================== diff --git a/src/rtl/uart_core.v b/src/rtl/uart_core.v new file mode 100644 index 0000000..5596958 --- /dev/null +++ b/src/rtl/uart_core.v @@ -0,0 +1,586 @@ +//====================================================================== +// +// uart_core.v +// ----------- +// A simple universal asynchronous receiver/transmitter (UART) +// interface. The interface contains 16 byte wide transmit and +// receivea buffers and can handle start and stop bits. But in +// general is rather simple. The primary purpose is as host +// interface for the coretest design. The core also has a +// loopback mode to allow testing of a serial link. +// +// Note that the UART has a separate API interface to allow +// a control core to change settings such as speed. But the core +// has default values to allow it to start operating directly +// after reset. No config should be needed. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2014 SUNET +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//====================================================================== + +module uart_core( + input wire clk, + input wire reset_n, + + // Configuration parameters + input wire [15 : 0] bit_rate, + input wire [1 : 0] stop_bits, + + // External data interface + input wire rxd, + output wire txd, + + // Internal receive interface. + output wire rxd_syn, + output [7 : 0] rxd_data, + input wire rxd_ack, + + // Internal transmit interface. + input wire txd_syn, + input wire [7 : 0] txd_data, + output wire txd_ack + ); + + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + // The default clock rate is based on target clock frequency + // divided by the bit rate times in order to hit the + // center of the bits. I.e. + // Clock: 50 MHz + // Bitrate: 19200 bps + // Divisor = 50*10E6 / 9600 = 5208 + parameter DEFAULT_CLK_RATE = 5208; + parameter DEFAULT_HALF_CLK_RATE = DEFAULT_CLK_RATE / 2; + + parameter DEFAULT_DATA_BITS = 8; + parameter DEFAULT_STOP_BITS = 1; + + parameter ERX_IDLE = 0; + parameter ERX_START = 1; + parameter ERX_BITS = 2; + parameter ERX_STOP = 3; + parameter ERX_SYN = 4; + + parameter ETX_IDLE = 0; + parameter ETX_ACK = 1; + parameter ETX_START = 2; + parameter ETX_BITS = 3; + parameter ETX_STOP = 4; + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + reg rxd_reg; + + reg [7 : 0] rxd_byte_reg; + reg rxd_byte_we; + + reg [4 : 0] rxd_bit_ctr_reg; + reg [4 : 0] rxd_bit_ctr_new; + reg rxd_bit_ctr_we; + reg rxd_bit_ctr_rst; + reg rxd_bit_ctr_inc; + + reg [15 : 0] rxd_bitrate_ctr_reg; + reg [15 : 0] rxd_bitrate_ctr_new; + reg rxd_bitrate_ctr_we; + reg rxd_bitrate_ctr_rst; + reg rxd_bitrate_ctr_inc; + + reg rxd_syn_reg; + reg rxd_syn_new; + reg rxd_syn_we; + + reg [2 : 0] erx_ctrl_reg; + reg [2 : 0] erx_ctrl_new; + reg erx_ctrl_we; + + reg txd_reg; + reg txd_new; + reg txd_we; + + reg [7 : 0] txd_byte_reg; + reg [7 : 0] txd_byte_new; + reg txd_byte_we; + + reg [4 : 0] txd_bit_ctr_reg; + reg [4 : 0] txd_bit_ctr_new; + reg txd_bit_ctr_we; + reg txd_bit_ctr_rst; + reg txd_bit_ctr_inc; + + reg [15 : 0] txd_bitrate_ctr_reg; + reg [15 : 0] txd_bitrate_ctr_new; + reg txd_bitrate_ctr_we; + reg txd_bitrate_ctr_rst; + reg txd_bitrate_ctr_inc; + + reg txd_ack_reg; + reg txd_ack_new; + reg txd_ack_we; + + reg [2 : 0] etx_ctrl_reg; + reg [2 : 0] etx_ctrl_new; + reg etx_ctrl_we; + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign txd = txd_reg; + assign rxd_syn = rxd_syn_reg; + assign rxd_data = rxd_byte_reg; + assign txd_ack = txd_ack_reg; + + + //---------------------------------------------------------------- + // reg_update + // + // Update functionality for all registers in the core. + // All registers are positive edge triggered with synchronous + // active low reset. All registers have write enable. + //---------------------------------------------------------------- + always @ (posedge clk) + begin: reg_update + if (!reset_n) + begin + rxd_reg <= 0; + rxd_byte_reg <= 8'h00; + rxd_bit_ctr_reg <= 4'h0; + rxd_bitrate_ctr_reg <= 16'h0000; + rxd_syn_reg <= 0; + erx_ctrl_reg <= ERX_IDLE; + + txd_reg <= 1; + txd_byte_reg <= 8'h00; + txd_bit_ctr_reg <= 4'h0; + txd_bitrate_ctr_reg <= 16'h0000; + txd_ack_reg <= 0; + etx_ctrl_reg <= ETX_IDLE; + end + else + begin + // We sample the rx input port every cycle. + rxd_reg <= rxd; + + // We shift the rxd bit into msb. + if (rxd_byte_we) + begin + rxd_byte_reg <= {rxd_reg, rxd_byte_reg[7 : 1]}; + end + + if (rxd_bit_ctr_we) + begin + rxd_bit_ctr_reg <= rxd_bit_ctr_new; + end + + if (rxd_bitrate_ctr_we) + begin + rxd_bitrate_ctr_reg <= rxd_bitrate_ctr_new; + end + + if (rxd_syn_we) + begin + rxd_syn_reg = rxd_syn_new; + end + + if (erx_ctrl_we) + begin + erx_ctrl_reg <= erx_ctrl_new; + end + + if (txd_we) + begin + txd_reg = txd_new; + end + + if (txd_byte_we) + begin + txd_byte_reg = txd_byte_new; + end + + if (txd_bit_ctr_we) + begin + txd_bit_ctr_reg <= txd_bit_ctr_new; + end + + if (txd_bitrate_ctr_we) + begin + txd_bitrate_ctr_reg <= txd_bitrate_ctr_new; + end + + if (txd_ack_we) + begin + txd_ack_reg = txd_ack_new; + end + + if (etx_ctrl_we) + begin + etx_ctrl_reg <= etx_ctrl_new; + end + end + end // reg_update + + + //---------------------------------------------------------------- + // rxd_bit_ctr + // + // Bit counter for receiving data on the external + // serial interface. + //---------------------------------------------------------------- + always @* + begin: rxd_bit_ctr + rxd_bit_ctr_new = 4'h0; + rxd_bit_ctr_we = 0; + + if (rxd_bit_ctr_rst) + begin + rxd_bit_ctr_new = 4'h0; + rxd_bit_ctr_we = 1; + end + + else if (rxd_bit_ctr_inc) + begin + rxd_bit_ctr_new = rxd_bit_ctr_reg + 4'b0001; + rxd_bit_ctr_we = 1; + end + end // rxd_bit_ctr + + + //---------------------------------------------------------------- + // rxd_bitrate_ctr + // + // Bitrate counter for receiving data on the external + // serial interface. + //---------------------------------------------------------------- + always @* + begin: rxd_bitrate_ctr + rxd_bitrate_ctr_new = 16'h0000; + rxd_bitrate_ctr_we = 0; + + if (rxd_bitrate_ctr_rst) + begin + rxd_bitrate_ctr_new = 16'h0000; + rxd_bitrate_ctr_we = 1; + end + + else if (rxd_bitrate_ctr_inc) + begin + rxd_bitrate_ctr_new = rxd_bitrate_ctr_reg + 16'h0001; + rxd_bitrate_ctr_we = 1; + end + end // rxd_bitrate_ctr + + + + //---------------------------------------------------------------- + // txd_bit_ctr + // + // Bit counter for transmitting data on the external + // serial interface. + //---------------------------------------------------------------- + always @* + begin: txd_bit_ctr + txd_bit_ctr_new = 4'h0; + txd_bit_ctr_we = 0; + + if (txd_bit_ctr_rst) + begin + txd_bit_ctr_new = 4'h0; + txd_bit_ctr_we = 1; + end + + else if (txd_bit_ctr_inc) + begin + txd_bit_ctr_new = txd_bit_ctr_reg + 4'b0001; + txd_bit_ctr_we = 1; + end + end // txd_bit_ctr + + + //---------------------------------------------------------------- + // txd_bitrate_ctr + // + // Bitrate counter for transmitting data on the external + // serial interface. + //---------------------------------------------------------------- + always @* + begin: txd_bitrate_ctr + txd_bitrate_ctr_new = 16'h0000; + txd_bitrate_ctr_we = 0; + + if (txd_bitrate_ctr_rst) + begin + txd_bitrate_ctr_new = 16'h0000; + txd_bitrate_ctr_we = 1; + end + + else if (txd_bitrate_ctr_inc) + begin + txd_bitrate_ctr_new = txd_bitrate_ctr_reg + 16'h0001; + txd_bitrate_ctr_we = 1; + end + end // txd_bitrate_ctr + + + //---------------------------------------------------------------- + // external_rx_engine + // + // Logic that implements the receive engine towards + // the external interface. Detects incoming data, collects it, + // if required checks parity and store correct data into + // the rx buffer. + //---------------------------------------------------------------- + always @* + begin: external_rx_engine + rxd_bit_ctr_rst = 0; + rxd_bit_ctr_inc = 0; + rxd_bitrate_ctr_rst = 0; + rxd_bitrate_ctr_inc = 0; + rxd_byte_we = 0; + rxd_syn_new = 0; + rxd_syn_we = 0; + erx_ctrl_new = ERX_IDLE; + erx_ctrl_we = 0; + + case (erx_ctrl_reg) + ERX_IDLE: + begin + if (!rxd_reg) + begin + // Possible start bit detected. + rxd_bitrate_ctr_rst = 1; + erx_ctrl_new = ERX_START; + erx_ctrl_we = 1; + end + end + + + ERX_START: + begin + rxd_bitrate_ctr_inc = 1; + if (rxd_reg) + begin + // Just a glitch. + erx_ctrl_new = ERX_IDLE; + erx_ctrl_we = 1; + end + else + begin + if (rxd_bitrate_ctr_reg == DEFAULT_HALF_CLK_RATE) + begin + // start bit assumed. We start sampling data. + rxd_bit_ctr_rst = 1; + rxd_bitrate_ctr_rst = 1; + erx_ctrl_new = ERX_BITS; + erx_ctrl_we = 1; + end + end + end + + + ERX_BITS: + begin + if (rxd_bitrate_ctr_reg < DEFAULT_CLK_RATE) + begin + rxd_bitrate_ctr_inc = 1; + end + else + begin + rxd_byte_we = 1; + rxd_bit_ctr_inc = 1; + rxd_bitrate_ctr_rst = 1; + if (rxd_bit_ctr_reg == DEFAULT_DATA_BITS - 1) + begin + erx_ctrl_new = ERX_STOP; + erx_ctrl_we = 1; + end + end + end + + + ERX_STOP: + begin + rxd_bitrate_ctr_inc = 1; + if (rxd_bitrate_ctr_reg == DEFAULT_CLK_RATE * DEFAULT_STOP_BITS) + begin + rxd_syn_new = 1; + rxd_syn_we = 1; + erx_ctrl_new = ERX_SYN; + erx_ctrl_we = 1; + end + end + + + ERX_SYN: + begin + if (rxd_ack) + begin + rxd_syn_new = 0; + rxd_syn_we = 1; + erx_ctrl_new = ERX_IDLE; + erx_ctrl_we = 1; + end + end + + + default: + begin + + end + endcase // case (erx_ctrl_reg) + end // external_rx_engine + + + //---------------------------------------------------------------- + // external_tx_engine + // + // Logic that implements the transmit engine towards + // the external interface. + //---------------------------------------------------------------- + always @* + begin: external_tx_engine + txd_new = 0; + txd_we = 0; + txd_byte_new = 0; + txd_byte_we = 0; + txd_bit_ctr_rst = 0; + txd_bit_ctr_inc = 0; + txd_bitrate_ctr_rst = 0; + txd_bitrate_ctr_inc = 0; + txd_ack_new = 0; + txd_ack_we = 0; + etx_ctrl_new = ETX_IDLE; + etx_ctrl_we = 0; + + case (etx_ctrl_reg) + ETX_IDLE: + begin + txd_new = 1; + txd_we = 1; + if (txd_syn) + begin + txd_byte_new = txd_data; + txd_byte_we = 1; + txd_ack_new = 1; + txd_ack_we = 1; + txd_bitrate_ctr_rst = 1; + etx_ctrl_new = ETX_ACK; + etx_ctrl_we = 1; + end + end + + + ETX_ACK: + begin + if (!txd_syn) + begin + txd_new = 0; + txd_we = 1; + txd_ack_new = 0; + txd_ack_we = 1; + etx_ctrl_new = ETX_START; + etx_ctrl_we = 1; + end + end + + ETX_START: + begin + if (txd_bitrate_ctr_reg == DEFAULT_CLK_RATE) + begin + txd_bit_ctr_rst = 1; + etx_ctrl_new = ETX_BITS; + etx_ctrl_we = 1; + end + else + begin + txd_bitrate_ctr_inc = 1; + end + end + + + ETX_BITS: + begin + if (txd_bitrate_ctr_reg < DEFAULT_CLK_RATE) + begin + txd_bitrate_ctr_inc = 1; + end + else + begin + txd_bitrate_ctr_rst = 1; + + if (txd_bit_ctr_reg == DEFAULT_DATA_BITS) + begin + txd_new = 1; + txd_we = 1; + etx_ctrl_new = ETX_STOP; + etx_ctrl_we = 1; + end + else + begin + txd_new = txd_byte_reg[txd_bit_ctr_reg]; + txd_we = 1; + txd_bit_ctr_inc = 1; + end + end + end + + + ETX_STOP: + begin + txd_bitrate_ctr_inc = 1; + if (txd_bitrate_ctr_reg == DEFAULT_CLK_RATE * DEFAULT_STOP_BITS) + begin + etx_ctrl_new = ETX_IDLE; + etx_ctrl_we = 1; + end + end + + + default: + begin + + end + endcase // case (etx_ctrl_reg) + end // external_tx_engine + +endmodule // uart + +//====================================================================== +// EOF uart.v +//====================================================================== |