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