mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2024-09-07 18:12:20 +00:00
298 lines
8.7 KiB
Verilog
298 lines
8.7 KiB
Verilog
//======================================================================
|
|
//
|
|
// 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, Secworks Sweden AB
|
|
// SPDX-License-Identifier: BSD-2-Clause
|
|
//
|
|
// 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,
|
|
|
|
input wire rxd,
|
|
output wire txd,
|
|
|
|
input wire cs,
|
|
input wire we,
|
|
input wire [7 : 0] address,
|
|
/* verilator lint_off UNUSED */
|
|
input wire [31 : 0] write_data,
|
|
/* verilator lint_on UNUSED */
|
|
output wire [31 : 0] read_data,
|
|
output wire ready
|
|
);
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Internal constant and parameter definitions.
|
|
//----------------------------------------------------------------
|
|
localparam ADDR_BIT_RATE = 8'h10;
|
|
localparam ADDR_DATA_BITS = 8'h11;
|
|
localparam ADDR_STOP_BITS = 8'h12;
|
|
|
|
localparam ADDR_RX_STATUS = 8'h20;
|
|
localparam ADDR_RX_DATA = 8'h21;
|
|
localparam ADDR_RX_BYTES = 8'h22;
|
|
|
|
localparam ADDR_TX_STATUS = 8'h40;
|
|
localparam ADDR_TX_DATA = 8'h41;
|
|
|
|
// The default bit 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: 18 MHz, 62500 bps
|
|
// Divisor = 18E6 / 62500 = 288
|
|
// This also satisfies 1E6 % bps == 0 for the CH552 MCU used for USB-serial
|
|
localparam DEFAULT_BIT_RATE = 16'd288;
|
|
localparam DEFAULT_DATA_BITS = 4'h8;
|
|
localparam DEFAULT_STOP_BITS = 2'h1;
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Registers including update variables and write enable.
|
|
//----------------------------------------------------------------
|
|
reg [15 : 0] bit_rate_reg;
|
|
reg bit_rate_we;
|
|
|
|
reg [3 : 0] data_bits_reg;
|
|
reg data_bits_we;
|
|
|
|
reg [1 : 0] stop_bits_reg;
|
|
reg stop_bits_we;
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Wires.
|
|
//----------------------------------------------------------------
|
|
wire core_rxd_syn;
|
|
wire [7 : 0] core_rxd_data;
|
|
wire core_rxd_ack;
|
|
|
|
reg core_txd_syn;
|
|
reg [7 : 0] core_txd_data;
|
|
wire core_txd_ready;
|
|
|
|
wire fifo_out_syn;
|
|
wire [7 : 0] fifo_out_data;
|
|
reg fifo_out_ack;
|
|
wire [8 : 0] fifo_bytes;
|
|
|
|
reg [31 : 0] tmp_read_data;
|
|
reg tmp_ready;
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Concurrent connectivity for ports etc.
|
|
//----------------------------------------------------------------
|
|
assign read_data = tmp_read_data;
|
|
assign ready = tmp_ready;
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Module instantiations.
|
|
//----------------------------------------------------------------
|
|
uart_core core(
|
|
.clk(clk),
|
|
.reset_n(reset_n),
|
|
|
|
// Configuration parameters
|
|
.bit_rate(bit_rate_reg),
|
|
.data_bits(data_bits_reg),
|
|
.stop_bits(stop_bits_reg),
|
|
|
|
// External data interface
|
|
.rxd(rxd),
|
|
.txd(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_ready(core_txd_ready)
|
|
);
|
|
|
|
|
|
uart_fifo fifo(
|
|
.clk(clk),
|
|
.reset_n(reset_n),
|
|
|
|
.in_syn(core_rxd_syn),
|
|
.in_data(core_rxd_data),
|
|
.in_ack(core_rxd_ack),
|
|
|
|
.fifo_bytes(fifo_bytes),
|
|
|
|
.out_syn(fifo_out_syn),
|
|
.out_data(fifo_out_data),
|
|
.out_ack(fifo_out_ack)
|
|
);
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// reg_update
|
|
//
|
|
// Update functionality for all registers in the core.
|
|
// All registers are positive edge triggered with synchronous
|
|
// active low reset.
|
|
//----------------------------------------------------------------
|
|
always @ (posedge clk)
|
|
begin: reg_update
|
|
if (!reset_n) begin
|
|
bit_rate_reg <= DEFAULT_BIT_RATE;
|
|
data_bits_reg <= DEFAULT_DATA_BITS;
|
|
stop_bits_reg <= DEFAULT_STOP_BITS;
|
|
end
|
|
else begin
|
|
if (bit_rate_we) begin
|
|
bit_rate_reg <= write_data[15 : 0];
|
|
end
|
|
|
|
if (data_bits_we) begin
|
|
data_bits_reg <= write_data[3 : 0];
|
|
end
|
|
|
|
if (stop_bits_we) begin
|
|
stop_bits_reg <= write_data[1 : 0];
|
|
end
|
|
end
|
|
end // reg_update
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// api
|
|
//
|
|
// The core API that allows an internal host to control the
|
|
// core functionality.
|
|
//----------------------------------------------------------------
|
|
always @*
|
|
begin: api
|
|
// Default assignments.
|
|
bit_rate_we = 1'h0;
|
|
data_bits_we = 1'h0;
|
|
stop_bits_we = 1'h0;
|
|
core_txd_syn = 1'h0;
|
|
fifo_out_ack = 1'h0;
|
|
tmp_read_data = 32'h0;
|
|
tmp_ready = 1'h0;
|
|
|
|
core_txd_data = write_data[7 : 0];
|
|
|
|
if (cs) begin
|
|
tmp_ready = 1'h1;
|
|
|
|
if (we) begin
|
|
case (address)
|
|
ADDR_BIT_RATE: begin
|
|
bit_rate_we = 1;
|
|
end
|
|
|
|
ADDR_DATA_BITS: begin
|
|
data_bits_we = 1;
|
|
end
|
|
|
|
ADDR_STOP_BITS: begin
|
|
stop_bits_we = 1;
|
|
end
|
|
|
|
ADDR_TX_DATA: begin
|
|
if (core_txd_ready) begin
|
|
core_txd_syn = 1'h1;
|
|
end
|
|
end
|
|
|
|
default: begin
|
|
end
|
|
endcase // case (address)
|
|
end
|
|
|
|
else begin
|
|
case (address)
|
|
ADDR_BIT_RATE: begin
|
|
tmp_read_data = {16'h0, bit_rate_reg};
|
|
end
|
|
|
|
ADDR_DATA_BITS: begin
|
|
tmp_read_data = {28'h0, data_bits_reg};
|
|
end
|
|
|
|
ADDR_STOP_BITS: begin
|
|
tmp_read_data = {30'h0, stop_bits_reg};
|
|
end
|
|
|
|
ADDR_RX_STATUS: begin
|
|
tmp_read_data = {31'h0, fifo_out_syn};
|
|
end
|
|
|
|
ADDR_RX_DATA: begin
|
|
fifo_out_ack = 1'h1;
|
|
tmp_read_data = {24'h0, fifo_out_data};
|
|
end
|
|
|
|
ADDR_RX_BYTES: begin
|
|
tmp_read_data = {23'h0, fifo_bytes};
|
|
end
|
|
|
|
ADDR_TX_STATUS: begin
|
|
tmp_read_data = {31'h0, core_txd_ready};
|
|
end
|
|
|
|
default: begin
|
|
end
|
|
endcase // case (address)
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule // uart
|
|
|
|
//======================================================================
|
|
// EOF uart.v
|
|
//======================================================================
|