OpenCores
URL https://opencores.org/ocsvn/wbuart32/wbuart32/trunk

Subversion Repositories wbuart32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /wbuart32
    from Rev 14 to Rev 15
    Reverse comparison

Rev 14 → Rev 15

/trunk/README.md
20,8 → 20,13
there wasn't a version of this UART interface containing a FIFO. Well, no
more. Now there is a [wbuart.v](rtl/wbuart.v) file that can be
integrated into a wishbone/B4/pipeline bus. As mentioned above, this module
contains a FIFO with a parameterized length that can extend up to 1023 entries.
contains a FIFO with a parameterized length that can extend up to 1023 entries.
Indeed, recent changes have even added in optional hardware flow control, should
you wish to use it.
 
Thus this is a very simple and easy to use controller.
 
# Commercial Applications
 
Should you find the GPLv3 license insufficient for your needs, other licenses
can be purchased from Gisselquist Technology, LLC.
/trunk/bench/cpp/linetest.cpp
63,7 → 63,7
UARTSIM *uart;
bool run_interactively = false;
int port = 0;
unsigned setup = 25;
unsigned setup = 868;
char string[] = "This is a UART testing string\r\n";
 
for(int argn=1; argn<argc; argn++) {
trunk/bench/cpp Property changes : Added: svn:ignore ## -0,0 +1,9 ## +.gitignore +helloworld +lintest +*.vcd +mkspeech +obj-pc +speech.hex +speech.inc +speechtest Index: trunk/bench/verilog/Makefile =================================================================== --- trunk/bench/verilog/Makefile (revision 14) +++ trunk/bench/verilog/Makefile (revision 15) @@ -85,13 +85,14 @@ $(VDIRFB)/Vlinetest__ALL.a: $(VDIRFB)/Vlinetest.mk $(VDIRFB)/Vlinetest.h $(VDIRFB)/Vlinetest.cpp $(VDIRFB)/Vlinetest.mk: linetest.v $(VDIRFB)/Vlinetest.h $(VDIRFB)/Vlinetest.cpp $(VDIRFB)/Vlinetest.mk: $(RTLDR)/rxuart.v $(RTLDR)/txuart.v +$(VDIRFB)/Vlinetest.h $(VDIRFB)/Vlinetest.cpp $(VDIRFB)/Vlinetest.mk: $(RTLDR)/rxuartlite.v $(RTLDR)/txuartlite.v $(VDIRFB)/Vhelloworld__ALL.a: $(VDIRFB)/Vhelloworld.h $(VDIRFB)/Vhelloworld.cpp $(VDIRFB)/Vhelloworld__ALL.a: $(VDIRFB)/Vhelloworld.mk $(VDIRFB)/Vhelloworld.h $(VDIRFB)/Vhelloworld.cpp $(VDIRFB)/Vhelloworld.mk: helloworld.v -$(VDIRFB)/Vhelloworld.h $(VDIRFB)/Vhelloworld.cpp $(VDIRFB)/Vhelloworld.mk: $(RTLDR)/rxuart.v $(RTLDR)/txuart.v +$(VDIRFB)/Vhelloworld.h $(VDIRFB)/Vhelloworld.cpp $(VDIRFB)/Vhelloworld.mk: $(RTLDR)/txuartlite.v $(RTLDR)/txuart.v -SPEECHSRCS := $(addprefix $(RTLDR)/,rxuart.v txuart.v ufifo.v wbuart.v) +SPEECHSRCS := $(addprefix $(RTLDR)/,rxuart.v txuart.v rxuartlite.v txuartlite.v ufifo.v wbuart.v) SPEECHVFILES:= $(addprefix $(VDIRFB)/,Vspeechfifo.h Vspeechfifo.cpp Vspeechfifo.mk) $(VDIRFB)/Vspeechfifo__ALL.a: $(VDIRFB)/Vspeechfifo.h $(VDIRFB)/Vspeechfifo.cpp $(VDIRFB)/Vspeechfifo__ALL.a: $(VDIRFB)/Vspeechfifo.mk
/trunk/bench/verilog/echotest.v
70,6 → 70,15
`define OPT_STANDALONE
`endif
//
//
// Two versions of the UART can be found in the rtl directory: a full featured
// UART, and a LITE UART that only handles 8N1 -- no break sending, break
// detection, parity error detection, etc. If we set USE_LITE_UART here, those
// simplified UART modules will be used.
//
// `define USE_LITE_UART
//
//
module echotest(i_clk,
`ifndef OPT_STANDALONE
i_setup,
130,16 → 139,34
wire rx_stb, rx_break, rx_perr, rx_ferr, rx_ignored;
wire [7:0] rx_data;
 
`ifdef USE_LITE_UART
//
// NOTE: this depends upon the Verilator implementation using a setup
// of 868, since we cannot change the setup of the RXUARTLITE module.
//
rxuartlite #(24'd868)
receiver(i_clk, i_uart_rx, rx_stb, rx_data);
`else
rxuart receiver(i_clk, pwr_reset, i_setup, i_uart_rx, rx_stb, rx_data,
rx_break, rx_perr, rx_ferr, rx_ignored);
`endif
 
// Bypass any transmit hardware flow control.
wire rts;
assign rts = 1'b1;
wire cts_n;
assign cts_n = 1'b0;
 
wire tx_busy;
`ifdef USE_LITE_UART
//
// NOTE: this depends upon the Verilator implementation using a setup
// of 868, since we cannot change the setup of the TXUARTLITE module.
//
txuartlite #(24'd868)
transmitter(i_clk, rx_stb, rx_data, o_uart_tx, tx_busy);
`else
txuart transmitter(i_clk, pwr_reset, i_setup, rx_break,
rx_stb, rx_data, rts, o_uart_tx, tx_busy);
`endif
 
`endif
 
/trunk/bench/verilog/helloworld.v
53,6 → 53,15
`define OPT_STANDALONE
`endif
//
//
// Two versions of the UART can be found in the rtl directory: a full featured
// UART, and a LITE UART that only handles 8N1 -- no break sending, break
// detection, parity error detection, etc. If we set USE_LITE_UART here, those
// simplified UART modules will be used.
//
// `define USE_LITE_UART
//
//
module helloworld(i_clk,
`ifndef OPT_STANDALONE
i_setup,
130,10 → 139,16
tx_stb <= 1'b0;
 
// Bypass any hardware flow control
wire rts;
assign rts = 1'b1;
wire cts_n;
assign cts_n = 1'b0;
 
`ifdef USE_LITE_UART
txuartlite
#(24'd868)
transmitter(i_clk, tx_stb, tx_data, o_uart_tx, tx_busy);
`else
txuart transmitter(i_clk, pwr_reset, i_setup, tx_break,
tx_stb, tx_data, rts, o_uart_tx, tx_busy);
tx_stb, tx_data, cts_n, o_uart_tx, tx_busy);
`endif
 
endmodule
/trunk/bench/verilog/linetest.v
54,6 → 54,15
`define OPT_STANDALONE
`endif
//
//
// Two versions of the UART can be found in the rtl directory: a full featured
// UART, and a LITE UART that only handles 8N1 -- no break sending, break
// detection, parity error detection, etc. If we set USE_LITE_UART here, those
// simplified UART modules will be used.
//
// `define USE_LITE_UART
//
//
module linetest(i_clk,
`ifndef OPT_STANDALONE
i_setup,
96,8 → 105,13
wire rx_stb, rx_break, rx_perr, rx_ferr, rx_ignored;
wire [7:0] rx_data;
 
`ifdef USE_LITE_UART
rxuartlite #(24'd868)
receiver(i_clk, i_uart_rx, rx_stb, rx_data);
`else
rxuart receiver(i_clk, pwr_reset, i_setup, i_uart_rx, rx_stb, rx_data,
rx_break, rx_perr, rx_ferr, rx_ignored);
`endif
 
 
// The next step in this process is to dump everything we read into a
201,10 → 215,15
tail <= tail + 8'h01;
 
// Bypass any hardwaare flow control
wire rts;
assign rts = 1'b1;
wire cts_n;
assign cts_n = 1'b0;
 
`ifdef USE_LITE_UART
txuartlite #(24'd868)
transmitter(i_clk, tx_stb, tx_data, o_uart_tx, tx_busy);
`else
txuart transmitter(i_clk, pwr_reset, i_setup, tx_break,
tx_stb, tx_data, rts, o_uart_tx, tx_busy);
tx_stb, tx_data, cts_n, o_uart_tx, tx_busy);
`endif
 
endmodule
/trunk/bench/verilog/speechfifo.v
259,8 → 259,8
//
// Since this is an output only module demonstrator, what would be the
// cts output is unused.
wire rts, cts;
assign rts = 1'b1;
wire cts_n, rts_n_ignored;
assign cts_n = 1'b0;
 
// Finally--the unit under test--now that we've set up all the wires
// to run/test it.
268,7 → 268,7
wbuarti(i_clk, pwr_reset,
wb_stb, wb_stb, 1'b1, wb_addr, wb_data,
uart_ack, uart_stall, uart_data,
1'b1, o_uart_tx, rts, cts,
1'b1, o_uart_tx, cts_n, rts_n_ignored,
ignored_rx_int, tx_int,
ignored_rxfifo_int, txfifo_int);
 
trunk/bench/verilog Property changes : Added: svn:ignore ## -0,0 +1,3 ## +obj_dir +speech.hex +speech.inc Index: trunk/doc/spec.pdf =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: trunk/doc/src/spec.tex =================================================================== --- trunk/doc/src/spec.tex (revision 14) +++ trunk/doc/src/spec.tex (revision 15) @@ -236,7 +236,7 @@ To use the core, a couple of steps are required. First, wire it up. This includes wiring the {\tt i\_uart} and {\tt o\_uart} ports, as well as any -{\tt i\_rts} and/or {\tt o\_cts} hardware flow control. The +{\tt i\_cts\_n} and/or {\tt o\_rts\_n} hardware flow control. The {\tt rxuart.v} and {\tt txuart.v} files may be wired up for use individually, or as part of a large module such as the example in{\tt wbuart-insert.v}. Alternatively, the {\tt wbuart.v} file may be connected to a straight 32--bit @@ -599,9 +599,22 @@ \end{tabbing} For those interested in hardware flow control, the core also offers an -{\tt i\_rts} input to control the flow out of our transmitter, and an -{\tt o\_cts} output when the receiver is full. +{\tt i\_cts\_n} input to control the flow out of our transmitter, and an +{\tt o\_rts\_n} output to indicate when the receiver is full. Both of these +wires are active low. +For those not interested in flow control there are three +possibilities. First, one can set the module parameter +{\tt HARDWARE\_FLOW\_CONTROL\_PRESENT} to zero which will disable hardware +flow control. This will also permanently set the hardware flow control is off +bit in the setup register. Second, hardware flow control can be disabled by +connecting a {\tt 1'b0} wire to {\tt i\_cts\_n} and by ignoring the +{\tt o\_rts\_n} output. In this case, the hardware flow control setup bit +becomes an unused flip flop within the driver. The third way to disable +hardware flow control is to simply disable it within the setup register. In +general, these approaches will only affect the transmitter's operation and how +the {\tt o\_rts\_n} bit gets set. + A more detailed discussion of the connections associated with these modules can begin with Tbl.~\ref{tbl:rxports}, \begin{table}\begin{center}\begin{portlist} @@ -628,7 +641,7 @@ {\tt i\_wr} & 1 & Input & An input strobe. Set to one when you wish to transmit data, clear once it has been accepted\\\hline {\tt i\_data} & 8 & Input & The data to be transmitted, ignored unless {\tt (i\_wr)\&\&(!o\_busy)} \\\hline -{\tt i\_rts} & 1 & Input & A hardware flow control wire, true if the receiver is ready to receive\\\hline +{\tt i\_cts\_n} & 1 & Input & A hardware flow control wire, true if the transmitter is cleared to send, active low\\\hline {\tt o\_uart} & 1 & Output & The wire to be connected to the external port\\\hline {\tt o\_busy} & 1 & Output & True if the transmitter is busy, false if it will receive data\\\hline \end{portlist}\caption{TXUART port list}\label{tbl:txports} @@ -638,8 +651,8 @@ \rowcolor[gray]{0.85} Port & W & Direction & Description \\\hline\hline {\tt i\_uart\_rx}& 1 & Input & The receive wire coming from the external port\\\hline {\tt o\_uart\_tx}& 1 & Output & The transmit wire to be connected to the external port\\\hline -{\tt i\_rts}& 1 & Input & The hardware flow control {\tt ready-to-send} (i.e. receive) input for the transmitter\\\hline -{\tt o\_cts}& 1 & Output & The hardware flow control {\tt clear-to-send} output\\\hline +{\tt i\_cts\_n}& 1 & Input & The hardware flow control {\tt clear-to-send} input for the transmitter, active low\\\hline +{\tt o\_rts\_n}& 1 & Output & The hardware flow control {\tt ready-to-send} (receive) output, also active low\\\hline {\tt o\_uart\_rx\_int} & 1 & Output & True if a byte may be read from the receiver\\\hline {\tt o\_uart\_tx\_int} & 1 & Output & True if a byte may be sent to the transmitter\\\hline {\tt o\_uart\_rxfifo\_int}&1& Output & True if the receive FIFO is half full\\\hline
/trunk/rtl/Makefile
49,15 → 49,25
test: $(VDIRFB)/Vtxuart__ALL.a
test: $(VDIRFB)/Vrxuart__ALL.a
test: $(VDIRFB)/Vwbuart__ALL.a
test: $(VDIRFB)/Vtxuartlite__ALL.a
test: $(VDIRFB)/Vrxuartlite__ALL.a
 
$(VDIRFB)/Vrxuart__ALL.a: $(VDIRFB)/Vrxuart.h $(VDIRFB)/Vrxuart.cpp
$(VDIRFB)/Vrxuart__ALL.a: $(VDIRFB)/Vrxuart.mk
$(VDIRFB)/Vrxuart.h $(VDIRFB)/Vrxuart.cpp $(VDIRFB)/Vrxuart.mk: rxuart.v
 
$(VDIRFB)/Vrxuartlite__ALL.a: $(VDIRFB)/Vrxuartlite.h $(VDIRFB)/Vrxuartlite.cpp
$(VDIRFB)/Vrxuartlite__ALL.a: $(VDIRFB)/Vrxuartlite.mk
$(VDIRFB)/Vrxuartlite.h $(VDIRFB)/Vrxuartlite.cpp $(VDIRFB)/Vrxuartlite.mk: rxuartlite.v
 
$(VDIRFB)/Vtxuart__ALL.a: $(VDIRFB)/Vtxuart.h $(VDIRFB)/Vtxuart.cpp
$(VDIRFB)/Vtxuart__ALL.a: $(VDIRFB)/Vtxuart.mk
$(VDIRFB)/Vtxuart.h $(VDIRFB)/Vtxuart.cpp $(VDIRFB)/Vtxuart.mk: txuart.v
 
$(VDIRFB)/Vtxuartlite__ALL.a: $(VDIRFB)/Vtxuartlite.h $(VDIRFB)/Vtxuartlite.cpp
$(VDIRFB)/Vtxuartlite__ALL.a: $(VDIRFB)/Vtxuartlite.mk
$(VDIRFB)/Vtxuartlite.h $(VDIRFB)/Vtxuartlite.cpp $(VDIRFB)/Vtxuartlite.mk: txuartlite.v
 
$(VDIRFB)/Vwbuart__ALL.a: $(VDIRFB)/Vwbuart.h $(VDIRFB)/Vwbuart.cpp
$(VDIRFB)/Vwbuart__ALL.a: $(VDIRFB)/Vwbuart.mk
$(VDIRFB)/Vwbuart.h $(VDIRFB)/Vwbuart.cpp $(VDIRFB)/Vwbuart.mk: wbuart.v ufifo.v txuart.v rxuart.v
/trunk/rtl/rxuartlite.v
0,0 → 1,197
////////////////////////////////////////////////////////////////////////////////
//
// Filename: rxuartlite.v
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: Receive and decode inputs from a single UART line.
//
//
// To interface with this module, connect it to your system clock,
// and a UART input. Set the parameter to the number of clocks per
// baud. When data becomes available, the o_wr line will be asserted
// for one clock cycle.
//
// This interface only handles 8N1 serial port communications. It does
// not handle the break, parity, or frame error conditions.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define RXU_BIT_ZERO 4'h0
`define RXU_BIT_ONE 4'h1
`define RXU_BIT_TWO 4'h2
`define RXU_BIT_THREE 4'h3
`define RXU_BIT_FOUR 4'h4
`define RXU_BIT_FIVE 4'h5
`define RXU_BIT_SIX 4'h6
`define RXU_BIT_SEVEN 4'h7
// `define RXU_PARITY 4'h8 // Unused in RXUARTLITE
`define RXU_STOP 4'h8
// `define RXU_SECOND_STOP 4'ha // Unused in RXUARTLITE
// Unused 4'hb
// Unused 4'hc
// `define RXU_BREAK 4'hd // Unused in RXUARTLITE
// `define RXU_RESET_IDLE 4'he // Unused in RXUARTLITE
`define RXU_IDLE 4'hf
 
module rxuartlite(i_clk, i_uart_rx, o_wr, o_data);
parameter [23:0] CLOCKS_PER_BAUD = 24'd868;
input i_clk;
input i_uart_rx;
output reg o_wr;
output reg [7:0] o_data;
 
 
wire [23:0] clocks_per_baud, half_baud;
reg [3:0] state;
 
assign half_baud = { 1'b0, CLOCKS_PER_BAUD[23:1] } - 24'h1;
reg [23:0] baud_counter;
reg zero_baud_counter;
 
 
// Since this is an asynchronous receiver, we need to register our
// input a couple of clocks over to avoid any problems with
// metastability. We do that here, and then ignore all but the
// ck_uart wire.
reg q_uart, qq_uart, ck_uart;
initial q_uart = 1'b0;
initial qq_uart = 1'b0;
initial ck_uart = 1'b0;
always @(posedge i_clk)
begin
q_uart <= i_uart_rx;
qq_uart <= q_uart;
ck_uart <= qq_uart;
end
 
// Keep track of the number of clocks since the last change.
//
// This is used to determine if we are in either a break or an idle
// condition, as discussed further below.
reg [23:0] chg_counter;
initial chg_counter = 24'h00;
always @(posedge i_clk)
if (qq_uart != ck_uart)
chg_counter <= 24'h00;
else
chg_counter <= chg_counter + 1;
 
// Are we in the middle of a baud iterval? Specifically, are we
// in the middle of a start bit? Set this to high if so. We'll use
// this within our state machine to transition out of the IDLE
// state.
reg half_baud_time;
initial half_baud_time = 0;
always @(posedge i_clk)
half_baud_time <= (~ck_uart)&&(chg_counter >= half_baud);
 
 
initial state = `RXU_IDLE;
always @(posedge i_clk)
begin
if (state == `RXU_IDLE)
begin // Idle state, independent of baud counter
// By default, just stay in the IDLE state
state <= `RXU_IDLE;
if ((~ck_uart)&&(half_baud_time))
// UNLESS: We are in the center of a valid
// start bit
state <= `RXU_BIT_ZERO;
end else if (zero_baud_counter)
begin
if (state < `RXU_STOP)
// Data arrives least significant bit first.
// By the time this is clocked in, it's what
// you'll have.
state <= state + 1;
else // Wait for the next character
state <= `RXU_IDLE;
end
end
 
// Data bit capture logic.
//
// This is drastically simplified from the state machine above, based
// upon: 1) it doesn't matter what it is until the end of a captured
// byte, and 2) the data register will flush itself of any invalid
// data in all other cases. Hence, let's keep it real simple.
reg [7:0] data_reg;
always @(posedge i_clk)
if (zero_baud_counter)
data_reg <= { ck_uart, data_reg[7:1] };
 
// Our data bit logic doesn't need nearly the complexity of all that
// work above. Indeed, we only need to know if we are at the end of
// a stop bit, in which case we copy the data_reg into our output
// data register, o_data, and tell others (for one clock) that data is
// available.
//
initial o_data = 8'h00;
reg pre_wr;
initial pre_wr = 1'b0;
always @(posedge i_clk)
if ((zero_baud_counter)&&(state == `RXU_STOP))
begin
o_wr <= 1'b1;
o_data <= data_reg;
end else
o_wr <= 1'b0;
 
// The baud counter
//
// This is used as a "clock divider" if you will, but the clock needs
// to be reset before any byte can be decoded. In all other respects,
// we set ourselves up for clocks_per_baud counts between baud
// intervals.
always @(posedge i_clk)
if ((zero_baud_counter)|||(state == `RXU_IDLE))
baud_counter <= CLOCKS_PER_BAUD-1'b1;
else
baud_counter <= baud_counter-1'b1;
 
// zero_baud_counter
//
// Rather than testing whether or not (baud_counter == 0) within our
// (already too complicated) state transition tables, we use
// zero_baud_counter to pre-charge that test on the clock
// before--cleaning up some otherwise difficult timing dependencies.
initial zero_baud_counter = 1'b0;
always @(posedge i_clk)
if (state == `RXU_IDLE)
zero_baud_counter <= 1'b0;
else
zero_baud_counter <= (baud_counter == 24'h01);
 
 
endmodule
 
 
/trunk/rtl/txuart.v
112,7 → 112,7
//
//
module txuart(i_clk, i_reset, i_setup, i_break, i_wr, i_data,
i_rts, o_uart_tx, o_busy);
i_cts_n, o_uart_tx, o_busy);
parameter [30:0] INITIAL_SETUP = 31'd868;
input i_clk, i_reset;
input [30:0] i_setup;
122,7 → 122,7
// Hardware flow control Ready-To-Send bit. Set this to one to use
// the core without flow control. (A more appropriate name would be
// the Ready-To-Receive bit ...)
input i_rts;
input i_cts_n;
// And the UART input line itself
output reg o_uart_tx;
// A line to tell others when we are ready to accept data. If
156,22 → 156,22
// Clock in the flow control data, two clocks to avoid metastability
// Default to using hardware flow control (uart_setup[30]==0 to use it).
// Set this high order bit off if you do not wish to use it.
reg q_rts, qq_rts, ck_rts;
// While we might wish to give initial values to q_rts and ck_rts,
reg q_cts_n, qq_cts_n, ck_cts;
// While we might wish to give initial values to q_rts and ck_cts,
// 1) it's not required since the transmitter starts in a long wait
// state, and 2) doing so will prevent the synthesizer from optimizing
// this pin in the case it is hard set to 1'b1 external to this
// peripheral.
//
// initial q_rts = 1'b0;
// initial qq_rts = 1'b0;
// initial ck_rts = 1'b0;
// initial q_cts_n = 1'b1;
// initial qq_cts_n = 1'b1;
// initial ck_cts = 1'b0;
always @(posedge i_clk)
q_rts <= i_rts;
q_cts_n <= i_cts_n;
always @(posedge i_clk)
qq_rts <= q_rts;
qq_cts_n <= q_cts_n;
always @(posedge i_clk)
ck_rts <= (qq_rts)||(!hw_flow_control);
ck_cts <= (!qq_cts_n)||(!hw_flow_control);
 
initial o_uart_tx = 1'b1;
initial r_busy = 1'b1;
208,7 → 208,7
2'b11: state <= `TXU_BIT_THREE;
endcase
end else begin // Stay in idle
r_busy <= !ck_rts;
r_busy <= !ck_cts;
end
end else begin
// One clock tick in each of these states ...
/trunk/rtl/txuartlite.v
0,0 → 1,206
////////////////////////////////////////////////////////////////////////////////
//
// Filename: txuartlite.v
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: Transmit outputs over a single UART line. This particular UART
// implementation has been extremely simplified: it does not handle
// generating break conditions, nor does it handle anything other than the
// 8N1 (8 data bits, no parity, 1 stop bit) UART sub-protocol.
//
// To interface with this module, connect it to your system clock, and
// pass it the byte of data you wish to transmit. Strobe the i_wr line
// high for one cycle, and your data will be off. Wait until the 'o_busy'
// line is low before strobing the i_wr line again--this implementation
// has NO BUFFER, so strobing i_wr while the core is busy will just
// get ignored. The output will be placed on the o_txuart output line.
//
// (I often set both data and strobe on the same clock, and then just leave
// them set until the busy line is low. Then I move on to the next piece
// of data.)
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define TXU_BIT_ZERO 4'h0
`define TXU_BIT_ONE 4'h1
`define TXU_BIT_TWO 4'h2
`define TXU_BIT_THREE 4'h3
`define TXU_BIT_FOUR 4'h4
`define TXU_BIT_FIVE 4'h5
`define TXU_BIT_SIX 4'h6
`define TXU_BIT_SEVEN 4'h7
`define TXU_STOP 4'h8
`define TXU_IDLE 4'hf
//
//
module txuartlite(i_clk, i_wr, i_data, o_uart_tx, o_busy);
parameter [23:0] CLOCKS_PER_BAUD = 24'd868;
input i_clk;
input i_wr;
input [7:0] i_data;
// And the UART input line itself
output reg o_uart_tx;
// A line to tell others when we are ready to accept data. If
// (i_wr)&&(!o_busy) is ever true, then the core has accepted a byte
// for transmission.
output wire o_busy;
 
reg [23:0] baud_counter;
reg [3:0] state;
reg [7:0] lcl_data;
reg r_busy, zero_baud_counter;
 
initial r_busy = 1'b1;
initial state = `TXU_IDLE;
initial lcl_data= 8'h0;
always @(posedge i_clk)
begin
if (!zero_baud_counter)
// r_busy needs to be set coming into here
r_busy <= 1'b1;
else if (state == `TXU_IDLE) // STATE_IDLE
begin
r_busy <= 1'b0;
if ((i_wr)&&(!r_busy))
begin // Immediately start us off with a start bit
r_busy <= 1'b1;
state <= `TXU_BIT_ZERO;
end
end else begin
// One clock tick in each of these states ...
r_busy <= 1'b1;
if (state <=`TXU_STOP) // start bit, 8-d bits, stop-b
state <= state + 1;
else
state <= `TXU_IDLE;
end
end
 
// o_busy
//
// This is a wire, designed to be true is we are ever busy above.
// originally, this was going to be true if we were ever not in the
// idle state. The logic has since become more complex, hence we have
// a register dedicated to this and just copy out that registers value.
assign o_busy = (r_busy);
 
 
// lcl_data
//
// This is our working copy of the i_data register which we use
// when transmitting. It is only of interest during transmit, and is
// allowed to be whatever at any other time. Hence, if r_busy isn't
// true, we can always set it. On the one clock where r_busy isn't
// true and i_wr is, we set it and r_busy is true thereafter.
// Then, on any zero_baud_counter (i.e. change between baud intervals)
// we simple logically shift the register right to grab the next bit.
initial lcl_data = 8'hff;
always @(posedge i_clk)
if ((i_wr)&&(!r_busy))
lcl_data <= i_data;
else if (zero_baud_counter)
lcl_data <= { 1'b1, lcl_data[7:1] };
 
// o_uart_tx
//
// This is the final result/output desired of this core. It's all
// centered about o_uart_tx. This is what finally needs to follow
// the UART protocol.
//
initial o_uart_tx = 1'b1;
always @(posedge i_clk)
if ((i_wr)&&(!r_busy))
o_uart_tx <= 1'b0; // Set the start bit on writes
else if (zero_baud_counter) // Set the data bit.
o_uart_tx <= lcl_data[0];
 
 
// All of the above logic is driven by the baud counter. Bits must last
// CLOCKS_PER_BAUD in length, and this baud counter is what we use to
// make certain of that.
//
// The basic logic is this: at the beginning of a bit interval, start
// the baud counter and set it to count CLOCKS_PER_BAUD. When it gets
// to zero, restart it.
//
// However, comparing a 28'bit number to zero can be rather complex--
// especially if we wish to do anything else on that same clock. For
// that reason, we create "zero_baud_counter". zero_baud_counter is
// nothing more than a flag that is true anytime baud_counter is zero.
// It's true when the logic (above) needs to step to the next bit.
// Simple enough?
//
// I wish we could stop there, but there are some other (ugly)
// conditions to deal with that offer exceptions to this basic logic.
//
// 1. When the user has commanded a BREAK across the line, we need to
// wait several baud intervals following the break before we start
// transmitting, to give any receiver a chance to recognize that we are
// out of the break condition, and to know that the next bit will be
// a stop bit.
//
// 2. A reset is similar to a break condition--on both we wait several
// baud intervals before allowing a start bit.
//
// 3. In the idle state, we stop our counter--so that upon a request
// to transmit when idle we can start transmitting immediately, rather
// than waiting for the end of the next (fictitious and arbitrary) baud
// interval.
//
// When (i_wr)&&(!r_busy)&&(state == `TXU_IDLE) then we're not only in
// the idle state, but we also just accepted a command to start writing
// the next word. At this point, the baud counter needs to be reset
// to the number of CLOCKS_PER_BAUD, and zero_baud_counter set to zero.
//
// The logic is a bit twisted here, in that it will only check for the
// above condition when zero_baud_counter is false--so as to make
// certain the STOP bit is complete.
initial zero_baud_counter = 1'b0;
initial baud_counter = 24'h05;
always @(posedge i_clk)
begin
zero_baud_counter <= (baud_counter == 24'h01);
if (state == `TXU_IDLE)
begin
baud_counter <= 24'h0;
zero_baud_counter <= 1'b1;
if ((i_wr)&&(!r_busy))
begin
baud_counter <= CLOCKS_PER_BAUD - 24'h01;
zero_baud_counter <= 1'b0;
end
end else if (!zero_baud_counter)
baud_counter <= baud_counter - 24'h01;
else
baud_counter <= CLOCKS_PER_BAUD - 24'h01;
end
endmodule
 
/trunk/rtl/wbuart-insert.v
86,16 → 86,16
if(((i_wb_stb)&&(!i_wb_we)&&(i_wb_addr == `UART_RX_ADDR))
||(rx_stb))
r_rx_data[8] <= !rx_stb;
assign o_cts = !r_rx_data[8];
assign o_rts_n = r_rx_data[8];
assign rx_data = { 20'h00, r_rx_data };
assign rx_int = !r_rx_data[8];
 
// Transmit hardware flow control, the rts line
wire rts;
// Set this rts value to one if you aren't ever going to use H/W flow
// Transmit hardware flow control, the cts line
wire cts_n;
// Set this cts value to zero if you aren't ever going to use H/W flow
// control, otherwise set it to the value coming in from the external
// i_rts pin.
assign rts = i_rts;
// i_cts_n pin.
assign cts_n = i_cts_n;
 
//
// Then the UART transmitter
109,7 → 109,7
wire [31:0] tx_data;
txuart #(UART_SETUP) tx(i_clk, 1'b0, uart_setup,
r_tx_break, r_tx_stb, r_tx_data,
rts, o_tx, tx_busy);
cts_n, o_tx, tx_busy);
always @(posedge i_clk)
if ((i_wb_stb)&&(i_wb_addr == 5'h0f))
begin
121,7 → 121,7
r_tx_stb <= 1'b0;
r_tx_data <= 8'h0;
end
assign tx_data = { 16'h00, rts, 3'h0,
assign tx_data = { 16'h00, cts_n, 3'h0,
ck_uart, o_tx, r_tx_break, tx_busy,
r_tx_data };
assign tx_int = ~tx_busy;
/trunk/rtl/wbuart.v
47,8 → 47,7
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
//
i_uart_rx, o_uart_tx, i_rts, o_cts,
// i_uart_rts, o_uart_cts, i_uart_dtr, o_uart_dts
i_uart_rx, o_uart_tx, i_cts_n, o_rts_n,
//
o_uart_rx_int, o_uart_tx_int,
o_uart_rxfifo_int, o_uart_txfifo_int);
77,13 → 76,13
// whether or not the receiving hardware is ready to accept another
// byte. If low, the transmitter will pause.
//
// If you don't wish to use hardware flow control, just set i_rts to
// 1'b1 and let the optimizer simply remove this logic.
input i_rts;
// If you don't wish to use hardware flow control, just set i_cts_n to
// 1'b0 and let the optimizer simply remove this logic.
input i_cts_n;
// CTS is the "Clear-to-send" signal. We set it anytime our FIFO
// isn't full. Feel free to ignore this output if you do not wish to
// use flow control.
output reg o_cts;
output reg o_rts_n;
output wire o_uart_rx_int, o_uart_tx_int,
o_uart_rxfifo_int, o_uart_txfifo_int;
 
120,15 → 119,25
 
// Here's our UART receiver. Basically, it accepts our setup wires,
// the UART input, a clock, and a reset line, and produces outputs:
// a stb (true when new data is ready), an 8-bit data out value
// valid when stb is high, a break value (true during a break cond.),
// and parity/framing error flags--also valid when stb is true.
// a stb (true when new data is ready), and an 8-bit data out value
// valid when stb is high.
`ifdef USE_LITE_UART
rxuartlite #(INITIAL_SETUP[23:0])
rx(i_clk, (i_rst), i_uart_rx, rx_stb, rx_uart_data);
assign rx_break = 1'b0;
assign rx_perr = 1'b0;
assign rx_ferr = 1'b0;
assign ck_uart = 1'b0;
`else
// The full receiver also produces a break value (true during a break
// cond.), and parity/framing error flags--also valid when stb is true.
rxuart #(INITIAL_SETUP) rx(i_clk, (i_rst)||(rx_uart_reset),
uart_setup, i_uart_rx,
rx_stb, rx_uart_data, rx_break,
rx_perr, rx_ferr, ck_uart);
// The real trick is ... now that we have this data, what do we do
// The real trick is ... now that we have this extra data, what do we do
// with it?
`endif
 
 
// We place it into a receiver FIFO.
170,12 → 179,10
// that if the transmit end starts sending we won't have a location to
// receive it. (Transmit might've started on the next character by the
// time we set this--need to set it to one character before necessary
// thus.)
wire [(LCLLGFLEN-1):0] check_cutoff;
assign check_cutoff = -3;
always @(posedge i_clk)
o_cts = (!HARDWARE_FLOW_CONTROL_PRESENT)
||(rxf_status[(LCLLGFLEN+1):2] > check_cutoff);
o_rts_n = ((HARDWARE_FLOW_CONTROL_PRESENT)
&&(!uart_setup[30])
&&(rxf_status[(LCLLGFLEN+1):4]=={(LCLLGFLEN-2){1'b1}}));
 
// If the bus requests that we read from the receive FIFO, we need to
// tell this to the receive FIFO. Note that because we are using a
250,10 → 257,10
//
//
/////////////////////////////////////////
wire tx_empty_n, txf_err;
wire tx_empty_n, txf_err, tx_break;
wire [7:0] tx_data;
wire [15:0] txf_status;
reg r_tx_break, txf_wb_write, tx_uart_reset;
reg txf_wb_write, tx_uart_reset;
reg [7:0] txf_wb_data;
 
// Unlike the receiver which goes from RXUART -> UFIFO -> WB, the
282,7 → 289,7
// and ... we just set the values (above) for controlling writing into
// this.
ufifo #(.LGFLEN(LGFLEN), .RXFIFO(0))
txfifo(i_clk, (r_tx_break)||(tx_uart_reset),
txfifo(i_clk, (tx_break)||(tx_uart_reset),
txf_wb_write, txf_wb_data,
tx_empty_n,
(!tx_busy)&&(tx_empty_n), tx_data,
296,6 → 303,7
// charged.
assign o_uart_txfifo_int = txf_status[1];
 
`ifndef USE_LITE_UART
// Break logic
//
// A break in a UART controller is any time the UART holds the line
304,6 → 312,7
// write unsigned characters to the interface, this will never be true
// unless you wish it to be true. Be aware, though, writing a valid
// value to the interface will bring it out of the break condition.
reg r_tx_break;
initial r_tx_break = 1'b0;
always @(posedge i_clk)
if (i_rst)
310,6 → 319,10
r_tx_break <= 1'b0;
else if ((i_wb_stb)&&(i_wb_addr[1:0]==`UART_TXREG)&&(i_wb_we))
r_tx_break <= i_wb_data[9];
assign tx_break = r_tx_break;
`else
assign tx_break = 1'b0;
`endif
 
// TX-Reset logic
//
326,8 → 339,12
else
tx_uart_reset <= 1'b0;
 
wire rts;
assign rts = (!HARDWARE_FLOW_CONTROL_PRESENT)||(i_rts);
`ifdef USE_LITE_UART
txuart #(INITIAL_SETUP[23:0]) tx(i_clk, (tx_empty_n), tx_data,
o_uart_tx, tx_busy);
`else
wire cts_n;
assign cts_n = (HARDWARE_FLOW_CONTROL_PRESENT)&&(i_cts_n);
// Finally, the UART transmitter module itself. Note that we haven't
// connected the reset wire. Transmitting is as simple as setting
// the stb value (here set to tx_empty_n) and the data. When these
339,7 → 356,8
// starting to transmit a new byte.)
txuart #(INITIAL_SETUP) tx(i_clk, 1'b0, uart_setup,
r_tx_break, (tx_empty_n), tx_data,
i_rts, o_uart_tx, tx_busy);
cts_n, o_uart_tx, tx_busy);
`endif
 
// Now that we are done with the chain, pick some wires for the user
// to read on any read of the transmit port.
355,8 → 373,8
// whether or not we are actively transmitting.
wire [31:0] wb_tx_data;
assign wb_tx_data = { 16'h00,
i_rts, txf_status[1:0], txf_err,
ck_uart, o_uart_tx, r_tx_break, (tx_busy|txf_status[0]),
i_cts_n, txf_status[1:0], txf_err,
ck_uart, o_uart_tx, tx_break, (tx_busy|txf_status[0]),
(tx_busy|txf_status[0])?txf_wb_data:8'b00};
 
// Each of the FIFO's returns a 16 bit status value. This value tells
trunk/rtl Property changes : Added: svn:ignore ## -0,0 +1 ## +obj_dir Index: trunk/wbuart32.core =================================================================== --- trunk/wbuart32.core (revision 14) +++ trunk/wbuart32.core (revision 15) @@ -5,6 +5,8 @@ [fileset rtl] files = + rtl/rxuartlite.v + rtl/txuartlite.v rtl/rxuart.v rtl/txuart.v rtl/ufifo.v
trunk Property changes : Added: svn:ignore ## -0,0 +1,6 ## +.git +.gitignore +*.vcd +*_tb +obj_dir +obj-pc

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.