//////////////////////////////////////////////////////////////////////
//// This file is part of the "UART 16550 compatible" project ////
//// http://www.opencores.org/cores/uart16550/ ////
//// Documentation related to this project: ////
//// - http://www.opencores.org/cores/uart16550/ ////
//// Projects compatibility: ////
//// 16550D uart (mostly supported) ////
//// Overview (main Features): ////
//// Registers of the uart 16550 core ////
//// Known problems (limits): ////
//// Inserts 1 wait state in all WISHBONE transfers ////
//// Nothing or verification. ////
//// - gorban@opencores.org ////
//// - Igor Mohor (igorm@opencores.org) ////
//// Created: 2001/05/12 ////
//// Last Updated: (See log for the revision history ////
//////////////////////////////////////////////////////////////////////
//// Copyright (C) 2000, 2001 Authors ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//////////////////////////////////////////////////////////////////////
// Revision 1.42 2004/11/22 09:21:59 igorm
// Timeout interrupt should be generated only when there is at least ony
// character in the fifo.
// Revision 1.41 2004/05/21 11:44:41 tadejm
// Added synchronizer flops for RX input.
// Revision 1.40 2003/06/11 16:37:47 gorban
// This fixes errors in some cases when data is being read and put to the FIFO at the same time. Patch is submitted by Scott Furman. Update is very recommended.
// Revision 1.39 2002/07/29 21:16:18 gorban
// The uart_defines.v file is included again in sources.
// Revision 1.38 2002/07/22 23:02:23 gorban
// * Possible loss of sync and bad reception of stop bit on slow baud rates fixed.
// Problem reported by Kenny.Tung.
// * Bad (or lack of ) loopback handling fixed. Reported by Cherry Withers.
// * Made FIFO's as general inferrable memory where possible.
// So on FPGA they should be inferred as RAM (Distributed RAM on Xilinx).
// This saves about 1/3 of the Slice count and reduces P&R and synthesis times.
// * Added optional baudrate output (baud_o).
// This is identical to BAUDOUT* signal on 16550 chip.
// It outputs 16xbit_clock_rate - the divided clock.
// It's disabled by default. Define UART_HAS_BAUDRATE_OUTPUT to use.
// Revision 1.37 2001/12/27 13:24:09 mohor
// lsr[7] was not showing overrun errors.
// Revision 1.36 2001/12/20 13:25:46 mohor
// rx push changed to be only one cycle wide.
// Revision 1.35 2001/12/19 08:03:34 mohor
// Revision 1.34 2001/12/19 07:33:54 mohor
// Synplicity was having troubles with the comment.
// Revision 1.33 2001/12/17 10:14:43 mohor
// Things related to msr register changed. After THRE IRQ occurs, and one
// character is written to the transmit fifo, the detection of the THRE bit in the
// LSR is delayed for one character time.
// Revision 1.32 2001/12/14 13:19:24 mohor
// Revision 1.31 2001/12/14 10:06:58 mohor
// After reset modem status register MSR should be reset.
// Revision 1.30 2001/12/13 10:09:13 mohor
// thre irq should be cleared only when being source of interrupt.
// Revision 1.29 2001/12/12 09:05:46 mohor
// LSR status bit 0 was not cleared correctly in case of reseting the FCR (rx fifo).
// Revision 1.28 2001/12/10 19:52:41 gorban
// Scratch register added
// Revision 1.27 2001/12/06 14:51:04 gorban
// Bug in LSR[0] is fixed.
// All WISHBONE signals are now sampled, so another wait-state is introduced on all transfers.
// Revision 1.26 2001/12/03 21:44:29 gorban
// Updated specification documentation.
// Added full 32-bit data bus interface, now as default.
// Address is 5-bit wide in 32-bit data bus mode.
// Added wb_sel_i input to the core. It's used in the 32-bit mode.
// Added debug interface with two 32-bit read-only registers in 32-bit mode.
// Bits 5 and 6 of LSR are now only cleared on TX FIFO write.
// My small test bench is modified to work with 32-bit mode.
// Revision 1.25 2001/11/28 19:36:39 gorban
// Fixed: timeout and break didn't pay attention to current data format when counting time
// Revision 1.24 2001/11/26 21:38:54 gorban
// Break condition wasn't handled correctly at all.
// LSR bits could lose their values.
// LSR value after reset was wrong.
// Timing of THRE interrupt signal corrected.
// LSR bit 0 timing corrected.
// Revision 1.23 2001/11/12 21:57:29 gorban
// Revision 1.22 2001/11/12 15:02:28 mohor
// Revision 1.21 2001/11/12 14:57:27 mohor
// ti_int_pnd error fixed.
// Revision 1.20 2001/11/12 14:50:27 mohor
// Revision 1.19 2001/11/10 12:43:21 gorban
// Logic Synthesis bugs fixed. Some other minor changes
// Revision 1.18 2001/11/08 14:54:23 mohor
// Comments in Slovene language deleted, few small fixes for better work of
// old tools. IRQs need to be fix.
// Revision 1.17 2001/11/07 17:51:52 gorban
// Heavily rewritten interrupt and LSR subsystems.
// Many bugs hopefully squashed.
// Revision 1.16 2001/11/02 09:55:16 mohor
// Revision 1.15 2001/10/31 15:19:22 gorban
// Fixes to break and timeout conditions
// Revision 1.14 2001/10/29 17:00:46 gorban
// fixed parity sending and tx_fifo resets over- and underrun
// Revision 1.13 2001/10/20 09:58:40 gorban
// Revision 1.12 2001/10/19 16:21:40 gorban
// Changes data_out to be synchronous again as it should have been.
// Revision 1.11 2001/10/18 20:35:45 gorban
// Revision 1.10 2001/08/24 21:01:12 mohor
// Things connected to parity changed.
// Clock devider changed.
// Revision 1.9 2001/08/23 16:05:05 mohor
// WISHBONE read cycle bug fixed,
// OE indicator (Overrun Error) bug fixed.
// PE indicator (Parity Error) bug fixed.
// Register read bug fixed.
// Revision 1.10 2001/06/23 11:21:48 gorban
// DL made 16-bit long. Fixed transmission/reception bugs.
// Revision 1.9 2001/05/31 20:08:01 gorban
// FIFO changes and other corrections.
// Revision 1.8 2001/05/29 20:05:04 gorban
// Fixed some bugs and synthesis problems.
// Revision 1.7 2001/05/27 17:37:49 gorban
// Fixed many bugs. Updated spec. Changed FIFO files structure. See CHANGES.txt file.
// Revision 1.6 2001/05/21 19:12:02 gorban
// Corrected some Linter messages.
// Revision 1.5 2001/05/17 18:34:18 gorban
// First 'stable' release. Should be sythesizable now. Also added new header.
// Revision 1.0 2001-05-17 21:27:11+02 jacob
module uart_regs(clk, wb_rst_i, wb_addr_i, wb_dat_i, wb_dat_o, wb_we_i, wb_re_i,
modem_inputs, stx_pad_o, srx_pad_i, rts_pad_o, dtr_pad_o, int_o, baud_o)
input [(3 - 1):0] wb_addr_i;
input [3:0] modem_inputs;
wire [(11 - 1):0] rf_data_out;
wire [(5 - 1):0] rf_count;
wire [(5 - 1):0] tf_count;
wire serial_in = (loopback ? serial_out : srx_pad);
reg [3:0] delayed_modem_signals;
defparam i_uart_sync_flops.width = 1;
defparam i_uart_sync_flops.init_value = 1'b1;
assign lsr[7:0] = {lsr7r, lsr6r, lsr5r, lsr4r, lsr3r, lsr2r, lsr1r,
assign {cts_pad_i, dsr_pad_i, ri_pad_i, dcd_pad_i} = modem_inputs;
assign {cts, dsr, ri, dcd} = (~{cts_pad_i, dsr_pad_i, ri_pad_i,
assign {cts_c, dsr_c, ri_c, dcd_c} = (loopback ? {mcr[1], mcr[0],
mcr[2], mcr[3]} : {cts_pad_i, dsr_pad_i, ri_pad_i, dcd_pad_i});
assign loopback = mcr[4];
assign rts_pad_o = mcr[1];
assign dtr_pad_o = mcr[0];
assign stx_pad_o = (loopback ? 1'b1 : serial_out);
assign lsr_mask_condition = ((wb_re_i && (wb_addr_i == 3'd5)) && (!dlab)
assign iir_read = ((wb_re_i && (wb_addr_i == 3'd2)) && (!dlab));
assign msr_read = ((wb_re_i && (wb_addr_i == 3'd6)) && (!dlab));
assign fifo_read = ((wb_re_i && (wb_addr_i == 3'b0)) && (!dlab));
assign fifo_write = ((wb_we_i && (wb_addr_i == 3'b0)) && (!dlab));
assign lsr_mask = (lsr_mask_condition && (~lsr_mask_d));
assign lsr0 = ((rf_count == 0) && rf_push_pulse);
assign lsr1 = rf_overrun;
assign lsr2 = rf_data_out[1];
assign lsr3 = rf_data_out[0];
assign lsr4 = rf_data_out[2];
assign lsr5 = (tf_count != 5'b01111);
assign lsr6 = (((tf_count == 5'b0) && thre_set_en) && (tstate == 0));
assign lsr7 = (rf_error_bit | rf_overrun);
assign thre_set_en = (~(|block_cnt));
assign rls_int = (ier[2] && (((lsr[1] || lsr[2]) || lsr[3]) || lsr[4]));
assign rda_int = (ier[0] && (rf_count >= {1'b0, trigger_level}));
assign thre_int = (ier[1] && lsr[5]);
assign ms_int = (ier[3] && (|msr[3:0]));
assign ti_int = ((ier[0] && (counter_t == 10'b0)) && (|rf_count));
assign rda_int_rise = (rda_int & (~rda_int_d));
assign rls_int_rise = (rls_int & (~rls_int_d));
assign thre_int_rise = (thre_int & (~thre_int_d));
assign ms_int_rise = (ms_int & (~ms_int_d));
assign ti_int_rise = (ti_int & (~ti_int_d));
uart_transmitter transmitter(clk, wb_rst_i, lcr, tf_push, wb_dat_i,
enable, serial_out, tstate, tf_count, tx_reset, lsr_mask);
uart_sync_flops i_uart_sync_flops(
.async_dat_i (srx_pad_i),
uart_receiver receiver(clk, wb_rst_i, lcr, rf_pop, serial_in, enable,
counter_t, rf_count, rf_data_out, rf_error_bit, rf_overrun,
rx_reset, lsr_mask, rstate, rf_push_pulse);
always @(dl or dlab or ier or iir or scratch or lcr or lsr or msr or
rf_data_out or wb_addr_i or wb_re_i) begin
wb_dat_o = (dlab ? dl[7:0] : rf_data_out[10:3]);
wb_dat_o = (dlab ? dl[15:8] : ier);
wb_dat_o = {4'b1100, iir};
always @(posedge clk or posedge wb_rst_i) begin
else if ((wb_re_i && (wb_addr_i == 3'b0)) && (!dlab)) begin
always @(posedge clk or posedge wb_rst_i) begin
lsr_mask_d <= #(1) lsr_mask_condition;
always @(posedge clk or posedge wb_rst_i) begin
else if (msi_reset) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
else if (wb_we_i && (wb_addr_i == 3'd3)) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
else if (wb_we_i && (wb_addr_i == 3'b1)) begin
dl[15:8] <= #(1) wb_dat_i;
ier <= #(1) wb_dat_i[3:0];
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
else if (wb_we_i && (wb_addr_i == 3'd2)) begin
fcr <= #(1) wb_dat_i[7:6];
rx_reset <= #(1) wb_dat_i[1];
tx_reset <= #(1) wb_dat_i[2];
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
else if (wb_we_i && (wb_addr_i == 3'd4)) begin
mcr <= #(1) wb_dat_i[4:0];
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
else if (wb_we_i && (wb_addr_i == 3'd7)) begin
scratch <= #(1) wb_dat_i;
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
else if (wb_we_i && (wb_addr_i == 3'b0)) begin
dl[7:0] <= #(1) wb_dat_i;
always @(fcr) case (fcr[1:0])
always @(posedge clk or posedge wb_rst_i) begin
delayed_modem_signals[3:0] <= #(1) 0;
msr[3:0] <= #(1) (msi_reset ? 4'b0 : (msr[3:0] | ({dcd, ri, dsr,
cts} ^ delayed_modem_signals[3:0])));
msr[7:4] <= #(1) {dcd_c, ri_c, dsr_c, cts_c};
delayed_modem_signals[3:0] <= #(1) {dcd, ri, dsr, cts};
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
lsr0r <= #(1) (((((rf_count == 1) && rf_pop) && (!rf_push_pulse)) ||
rx_reset) ? 0 : (lsr0r || (lsr0 && (~lsr0_d))));
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
lsr1r <= #(1) (lsr_mask ? 0 : (lsr1r || (lsr1 && (~lsr1_d))));
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
lsr2r <= #(1) (lsr_mask ? 0 : (lsr2r || (lsr2 && (~lsr2_d))));
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
lsr3r <= #(1) (lsr_mask ? 0 : (lsr3r || (lsr3 && (~lsr3_d))));
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
lsr4r <= #(1) (lsr_mask ? 0 : (lsr4r || (lsr4 && (~lsr4_d))));
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
lsr6r <= #(1) (fifo_write ? 0 : (lsr6r || (lsr6 && (~lsr6_d))));
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
lsr7r <= #(1) (lsr_mask ? 0 : (lsr7r || (lsr7 && (~lsr7_d))));
always @(posedge clk or posedge wb_rst_i) begin
else if (start_dlc | (~(|dlc))) begin
always @(posedge clk or posedge wb_rst_i) begin
else if ((|dl) & (~(|dlc))) begin
always @(lcr) case (lcr[3:0])
4'd3, 4'd6, 4'd10, 4'b1101:
always @(posedge clk or posedge wb_rst_i) begin
else if (lsr5r & fifo_write) begin
block_cnt <= #(1) block_value;
else if (enable & (block_cnt != 8'b0)) begin
block_cnt <= #(1) (block_cnt - 1);
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
rls_int_d <= #(1) rls_int;
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
rda_int_d <= #(1) rda_int;
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
thre_int_d <= #(1) thre_int;
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
rls_int_pnd <= #(1) (lsr_mask ? 0 : (rls_int_rise ? 1 : (rls_int_pnd
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
rda_int_pnd <= #(1) (((rf_count == {1'b0, trigger_level}) && fifo_read
) ? 0 : (rda_int_rise ? 1 : (rda_int_pnd && ier[0])));
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
thre_int_pnd <= #(1) ((fifo_write || ((iir_read & (~iir[0])) & (
iir[3:1] == 3'b1))) ? 0 : (thre_int_rise ? 1 : (thre_int_pnd
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
ms_int_pnd <= #(1) (msr_read ? 0 : (ms_int_rise ? 1 : (ms_int_pnd &&
always @(posedge clk or posedge wb_rst_i) if (wb_rst_i) begin
ti_int_pnd <= #(1) (fifo_read ? 0 : (ti_int_rise ? 1 : (ti_int_pnd &&
always @(posedge clk or posedge wb_rst_i) begin
int_o <= #(1) (rls_int_pnd ? (~lsr_mask) : (rda_int_pnd ? 1 : (
ti_int_pnd ? (~fifo_read) : (thre_int_pnd ? (!(fifo_write &
iir_read)) : (ms_int_pnd ? (~msr_read) : 0)))));
always @(posedge clk or posedge wb_rst_i) begin
else if (rls_int_pnd) begin
else if (ti_int_pnd) begin
else if (thre_int_pnd) begin
else if (ms_int_pnd) begin