aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rtl/uart.v266
-rw-r--r--src/rtl/uart_core.v586
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
+//======================================================================