├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── bench ├── README.md ├── cpp │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── helloworld.cpp │ ├── linetest.cpp │ ├── mkspeech.cpp │ ├── speech.txt │ ├── speechtest.cpp │ ├── uartsim.cpp │ └── uartsim.h ├── formal │ ├── .gitignore │ ├── Makefile │ ├── axiluart.gtkw │ ├── axiluart.sby │ ├── faxil_slave.v │ ├── genreport.pl │ ├── report.html │ ├── rxuartlite.sby │ ├── txuart.sby │ ├── txuartlite.sby │ └── ufifo.sby └── verilog │ ├── Makefile │ ├── README.md │ ├── echotest.v │ ├── helloworld.v │ ├── linetest.v │ └── speechfifo.v ├── doc ├── Makefile ├── gfx │ ├── ambiguous.png │ └── logic-timing.png ├── gpl-3.0.pdf ├── spec.pdf ├── src │ ├── GT.eps │ ├── gpl-3.0.tex │ ├── gqtekspec.cls │ └── spec.tex └── uart.png ├── rtl ├── Makefile ├── axiluart.v ├── rxuart.v ├── rxuartlite.v ├── skidbuffer.v ├── txuart.v ├── txuartlite.v ├── ufifo.v ├── wbuart-insert.v └── wbuart.v └── wbuart32.core /.gitignore: -------------------------------------------------------------------------------- 1 | legal.txt 2 | a.out 3 | .svn 4 | xilinx 5 | obj_dir 6 | obj-pc 7 | *.o 8 | *.a 9 | *.vcd 10 | .*.swp 11 | .*.swo 12 | svn-commit* 13 | *_tb 14 | *_tb.dbl 15 | *dbg.txt 16 | *dump.txt 17 | tags 18 | speech.hex 19 | speech.inc 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: Makefile 4 | ## {{{ 5 | ## Project: wbuart32, a full featured UART with simulator 6 | ## 7 | ## Purpose: This is the master Makefile for the project. It coordinates 8 | ## the build of a Verilator test, "proving" that this core works 9 | ## (to the extent that any simulated test "proves" anything). This 10 | ## make file depends upon the proper setup of Verilator. 11 | ## 12 | ## Creator: Dan Gisselquist, Ph.D. 13 | ## Gisselquist Technology, LLC 14 | ## 15 | ################################################################################ 16 | ## }}} 17 | ## Copyright (C) 2015-2022, Gisselquist Technology, LLC 18 | ## {{{ 19 | ## This program is free software (firmware): you can redistribute it and/or 20 | ## modify it under the terms of the GNU General Public License as published 21 | ## by the Free Software Foundation, either version 3 of the License, or (at 22 | ## your option) any later version. 23 | ## 24 | ## This program is distributed in the hope that it will be useful, but WITHOUT 25 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 26 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27 | ## for more details. 28 | ## 29 | ## You should have received a copy of the GNU General Public License along 30 | ## with this program. (It's in the $(ROOT)/doc directory, run make with no 31 | ## target there if the PDF file isn't present.) If not, see 32 | ## for a copy. 33 | ## }}} 34 | ## License: GPL, v3, as defined and found on www.gnu.org, 35 | ## {{{ 36 | ## http://www.gnu.org/licenses/gpl.html 37 | ## 38 | ## 39 | ################################################################################ 40 | ## 41 | ## }}} 42 | all: rtl bench test 43 | 44 | .PHONY: doc 45 | ## {{{ 46 | doc: 47 | cd doc ; $(MAKE) --no-print-directory 48 | ## }}} 49 | 50 | .PHONY: rtl 51 | ## {{{ 52 | rtl: 53 | cd rtl ; $(MAKE) --no-print-directory 54 | ## }}} 55 | 56 | .PHONY: bench 57 | ## {{{ 58 | bench: rtl 59 | cd bench/verilog ; $(MAKE) --no-print-directory 60 | cd bench/cpp ; $(MAKE) --no-print-directory 61 | ## }}} 62 | 63 | .PHONY: test 64 | ## {{{ 65 | test: bench 66 | bench/cpp/linetest 67 | # bench/cpp/speechtest bench/cpp/speech.txt 68 | ## }}} 69 | 70 | .PHONY: clean 71 | ## {{{ 72 | clean: 73 | cd rtl ; $(MAKE) --no-print-directory clean 74 | cd bench/verilog ; $(MAKE) --no-print-directory clean 75 | cd bench/cpp ; $(MAKE) --no-print-directory clean 76 | ## }}} 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Another Wishbone (or even AXI-lite) Controlled UART 2 | 3 | _Forasmuch as many have taken in hand to set forth_ a UART core, ... _It seemed 4 | good to me also, having had ~~perfect~~_ (a good) _understanding of ~~all~~ 5 | things from the very first, to write_ ... my own UART core. [[Ref](https://www.blueletterbible.org/kjv/luk/1/1)] 6 | 7 | - This Verilog core contains two UART modules, [one for transmit](rtl/txuart.v) and [one for receive](rtl/rxuart.v). Each can be configured via one 32-bit word for just about any baud rate, one or two stop bits, five through eight data bits, and odd, even, mark, or space parity. If you are looking for an example Verilog UART module containing all these features, then you have just found it. 8 | 9 | - The module goes beyond simple transmit and receive, however, to also include a fairly generic [synchronous FIFO](rtl/ufifo.v). For those looking for a fairly simple FIFO, whether for your UART capability or something else, you've also just found it. 10 | 11 | - If you are looking for a wishbone--enabled peripheral, this module offers two configuration methods: [one](rtl/wbuart-insert.v) that can be included in another, larger, wishbone module, and [another](rtl/wbuart.v) which is complete in its own right--together with an integrated FIFO and a FIFO status register. 12 | 13 | - If what you want is an AXI-lite peripheral, there is also an [AXI-lite 14 | wrapper](rtl/axiluart.v) having the same register interface as the [wbuart 15 | core](rtl/wbuart.v) listed above. 16 | 17 | - If you are familiar with other UART setup protocols, you'll find this one much easier to setup. For example, unlike the 16550 serial port, this serial port can be set up by just writing to and setting a single 32--bit register. Once set, either at startup or by writing the the port afterwards, and your UART is fully configured. Changes will take place on the next byte to be transmitted (or received). 18 | 19 | - If you would rather test your own UART transmitter and/or receiver, this core contains within it a Verilator enabled [UART simulator](bench/cpp/uartsim.cpp) which can be used in test-benches of your own UART implementation to know if you've done it right or not. 20 | 21 | - Finally, the test benches within [bench/verilog](bench/verilog) of this directory can be used as very simple test benches to test for UART functionality on a board with only two pins (clock and output UART), or three pins (adding the input UART). Thus, if you are just trying to start up a project and need a demonstration that will prove if your UART will work, you can find several such a demonstration projects in this code. Further, two of those test benches will also create VCD files that can be inspected via gtkwave, so you can get a feel for how the whole thing works. 22 | 23 | At one time, the biggest drawback to the files in these directories was that 24 | there wasn't a version of this UART interface containing a FIFO. Well, no more. 25 | Now there is a [wbuart.v](rtl/wbuart.v) file that can be integrated into a 26 | wishbone/B4/pipeline bus and a similar [axiluart.v](rtl/axiluart.v) file that 27 | can be used to integrate this into an AXI-lite environment. As mentioned above, 28 | this module contains a FIFO with a parameterized length that can extend up to 29 | 1024 entries. Indeed, recent changes have even added in optional hardware 30 | flow control, should you wish to use it. 31 | 32 | Thus this is a very simple and easy to use controller. 33 | 34 | # Commercial Applications 35 | 36 | Should you find the GPLv3 license insufficient for your needs, other licenses 37 | can be purchased from Gisselquist Technology, LLC. 38 | -------------------------------------------------------------------------------- /bench/README.md: -------------------------------------------------------------------------------- 1 | There are two bench testing directories, [one for Verilator sources](verilog), and [one for C++ simulation sources](cpp) that will work with Verilator. The Verilog sources may or may not be used with Verilator. Indeed, they would work nicely as stand--alone top--level files that may be used to test whether or not the UART on a given board works. 2 | -------------------------------------------------------------------------------- /bench/cpp/.gitignore: -------------------------------------------------------------------------------- 1 | mkspeech 2 | helloworld 3 | helloworldlite 4 | linetest 5 | linetestlite 6 | speechtest 7 | speechtestlite 8 | *.vcd 9 | obj-pc/* 10 | -------------------------------------------------------------------------------- /bench/cpp/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: Makefile 4 | ## {{{ 5 | ## Project: wbuart32, a full featured UART with simulator 6 | ## 7 | ## Purpose: To test a group of Verilator modules: txuart (UART transmitter), 8 | ## rxuart (UART receiver/sink) and wbuart (UART module, containing 9 | ## both receiver and transmitter, with FIFOs, controlled via wishbone). 10 | ## 11 | ## 12 | ## Targets: 13 | ## test 14 | ## Perform both tests. The end result should be either a PASS 15 | ## or a FAIL. 16 | ## 17 | ## helloworld 18 | ## A non-automated, and less interactive test than the others. In 19 | ## this test, the UART simply produces a Hello World message to the 20 | ## screen over and over again. 21 | ## 22 | ## linetest 23 | ## An automated test of both txuart and rxuart. The test works 24 | ## by sending a message through the rxuart, and receiving the 25 | ## message via the txuart. This depends upon a Verilog test 26 | ## infrastructure, linetest.v. 27 | ## 28 | ## This test may be ran in an interactive mode. In this mode, 29 | ## characters written to the UART will be reflected back upon 30 | ## the entrance of a return character. 31 | ## 32 | ## speechtest 33 | ## An automated test of the wbuart, txuart, and fifo. In this 34 | ## case, the test RTL produces a copy of the Gettysburg address, 35 | ## filling the FIFO at 12/16 at a time. In automated mode, the 36 | ## speechtest will compare the output against against a text copy 37 | ## of the speech, and report upon any success or failure. 38 | ## 39 | ## In interactive mode, the test will repeatedly print out the 40 | ## Gettysburg address until stopped. (It may take a significant 41 | ## amount of time between copies of the Gettysburg address ...) 42 | ## 43 | ## 44 | ## Creator: Dan Gisselquist, Ph.D. 45 | ## Gisselquist Technology, LLC 46 | ## 47 | ################################################################################ 48 | ## }}} 49 | ## Copyright (C) 2015-2024, Gisselquist Technology, LLC 50 | ## {{{ 51 | ## This program is free software (firmware): you can redistribute it and/or 52 | ## modify it under the terms of the GNU General Public License as published 53 | ## by the Free Software Foundation, either version 3 of the License, or (at 54 | ## your option) any later version. 55 | ## 56 | ## This program is distributed in the hope that it will be useful, but WITHOUT 57 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 58 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 59 | ## for more details. 60 | ## 61 | ## You should have received a copy of the GNU General Public License along 62 | ## with this program. (It's in the $(ROOT)/doc directory, run make with no 63 | ## target there if the PDF file isn't present.) If not, see 64 | ## for a copy. 65 | ## 66 | ## License: GPL, v3, as defined and found on www.gnu.org, 67 | ## http://www.gnu.org/licenses/gpl.html 68 | ## 69 | ## 70 | ################################################################################ 71 | ## 72 | ## 73 | CXX := g++ 74 | FLAGS := -Wall -Og -g 75 | OBJDIR := obj-pc 76 | RTLD := ../verilog 77 | VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"') 78 | VROOT := $(VERILATOR_ROOT) 79 | INCS := -I$(RTLD)/obj_dir/ -I$(VROOT)/include 80 | SOURCES := helloworld.cpp linetest.cpp uartsim.cpp uartsim.h 81 | VOBJDR := $(RTLD)/obj_dir 82 | SYSVDR := $(VROOT)/include 83 | ## }}} 84 | all: $(OBJDIR)/ linetest linetestlite helloworld helloworldlite speechtest speechtestlite test 85 | 86 | # Verilator's generated Makefile sets VM_* 87 | -include $(VOBJDR)/Vlinetest_classes.mk 88 | VSRC := $(addsuffix .cpp, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW)) 89 | VLIB := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(VSRC))) 90 | 91 | $(OBJDIR)/uartsim.o: uartsim.cpp uartsim.h 92 | 93 | $(OBJDIR)/%.o: %.cpp 94 | $(mk-objdir) 95 | $(CXX) $(FLAGS) $(INCS) -c $< -o $@ 96 | 97 | $(OBJDIR)/%.o: $(SYSVDR)/%.cpp 98 | $(mk-objdir) 99 | $(CXX) $(FLAGS) $(INCS) -c $< -o $@ 100 | 101 | ## linetest 102 | ## {{{ 103 | # Sources necessary to build the linetest program (rxuart-txuart test) 104 | LINSRCS := linetest.cpp uartsim.cpp 105 | LINOBJ := $(subst .cpp,.o,$(LINSRCS)) 106 | LINOBJS:= $(addprefix $(OBJDIR)/,$(LINOBJ)) $(VLIB) 107 | linetest: $(LINOBJS) $(VOBJDR)/Vlinetest__ALL.a 108 | $(CXX) $(FLAGS) $(INCS) $^ -lpthread -o $@ 109 | ## }}} 110 | 111 | ## linetestlite 112 | ## {{{ 113 | $(OBJDIR)/linetestlite.o: linetest.cpp 114 | $(mk-objdir) 115 | $(CXX) $(FLAGS) $(INCS) -DUSE_UART_LITE -c $< -lpthread -o $@ 116 | 117 | 118 | LINLTSRCS := linetest.cpp uartsim.cpp 119 | LINLTOBJ := linetestlite.o uartsim.o 120 | LINLTOBJS:= $(addprefix $(OBJDIR)/,$(LINLTOBJ)) $(VLIB) 121 | linetestlite: $(LINLTOBJS) $(VOBJDR)/Vlinetestlite__ALL.a 122 | $(CXX) $(FLAGS) $(INCS) $^ -lpthread -o $@ 123 | ## }}} 124 | 125 | ## Hello World 126 | ## {{{ 127 | # Sources necessary to build the helloworld test (txuart test) 128 | HLOSRCS := helloworld.cpp uartsim.cpp 129 | HLOOBJ := $(subst .cpp,.o,$(HLOSRCS)) 130 | HLOOBJS:= $(addprefix $(OBJDIR)/,$(HLOOBJ)) $(VLIB) 131 | helloworld: $(HLOOBJS) $(VOBJDR)/Vhelloworld__ALL.a 132 | $(CXX) $(FLAGS) $(INCS) $^ -lpthread -o $@ 133 | ## }}} 134 | 135 | ## helloworldlite 136 | ## {{{ 137 | $(OBJDIR)/helloworldlite.o: helloworld.cpp 138 | $(mk-objdir) 139 | $(CXX) $(FLAGS) $(INCS) -DUSE_UART_LITE -c $< -lpthread -o $@ 140 | 141 | HLOLTOBJ := helloworldlite.o uartsim.o 142 | HLOLTOBJS:= $(addprefix $(OBJDIR)/,$(HLOLTOBJ)) $(VLIB) 143 | helloworldlite: $(HLOLTOBJS) $(VOBJDR)/Vhelloworldlite__ALL.a 144 | $(CXX) $(FLAGS) $(INCS) $^ -lpthread -o $@ 145 | ## }}} 146 | 147 | # 148 | # The speech test program depends upon a copy of the Gettysburg Address, 149 | # turned into a hex file format which will be read by the Verilog/RTL 150 | # $readmemh function. However, we need to create that hex file that will 151 | # written. That's the purpose of mkspeech--to make a file that can be read 152 | # by $readmemh. 153 | # 154 | mkspeech: mkspeech.cpp 155 | $(CXX) mkspeech.cpp -o $@ 156 | 157 | # Now that mkspeech is available, use it to produce a speech.hex file from 158 | # the speech.txt file. Be careful if you adjust this speech: the speechfifo.v 159 | # verilog file depends upon the exact number of characters--its not a portable 160 | # dependency, but ... it is what it is. 161 | speech.hex: mkspeech speech.txt 162 | ./mkspeech speech.txt 163 | bash -c "if [ -d ../verilog/ ]; then cp speech.hex ../verilog/; fi" 164 | 165 | ## speechtest 166 | ## {{{ 167 | # Now, if the speech.hex file is available, then we can perform our final build. 168 | # Actually, we could've done this without the speech file being available, but 169 | # this works. 170 | # Sources necessary to build the speech test (wbuart test) 171 | SPCHSRCS:= speechtest.cpp uartsim.cpp 172 | SPCHOBJ := $(subst .cpp,.o,$(SPCHSRCS)) 173 | SPCHOBJS:= $(addprefix $(OBJDIR)/,$(SPCHOBJ)) $(VLIB) 174 | speechtest: speech.hex $(SPCHOBJS) $(VOBJDR)/Vspeechfifo__ALL.a 175 | $(CXX) $(FLAGS) $(INCS) $(SPCHOBJS) $(VOBJDR)/Vspeechfifo__ALL.a -lpthread -o $@ 176 | ## }}} 177 | 178 | ## speechtestlite 179 | ## {{{ 180 | $(OBJDIR)/speechtestlite.o: speechtest.cpp 181 | $(mk-objdir) 182 | $(CXX) $(FLAGS) $(INCS) -DUSE_UART_LITE -c $< -o $@ 183 | 184 | SPCHLTOBJ := speechtestlite.o uartsim.o 185 | SPCHLTOBJS:= $(addprefix $(OBJDIR)/,$(SPCHLTOBJ)) $(VLIB) 186 | speechtestlite: speech.hex $(SPCHLTOBJS) $(VOBJDR)/Vspeechfifolite__ALL.a 187 | $(CXX) $(FLAGS) $(INCS) $(SPCHLTOBJS) $(VOBJDR)/Vspeechfifolite__ALL.a -lpthread -o $@ 188 | ## }}} 189 | 190 | ## test 191 | ## {{{ 192 | 193 | test: 194 | # 195 | # 196 | # The "test" target, attempts to check if our core does what it should 197 | # without any user interaction 198 | test: linetest linetestlite helloworld helloworldlite speechtest speechtestlite 199 | ./linetest 200 | ./linetestlite 201 | ./helloworld 202 | ./helloworldlite 203 | ./speechtest 204 | ./speechtestlite 205 | ## }}} 206 | 207 | # 208 | # The "depends" target, to know what files things depend upon. The depends 209 | # file itself is kept in $(OBJDIR)/depends.txt 210 | # 211 | define build-depends 212 | $(mk-objdir) 213 | @echo "Building dependency file" 214 | @$(CXX) $(FLAGS) $(INCS) -MM $(SOURCES) > $(OBJDIR)/xdepends.txt 215 | @sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt 216 | @rm $(OBJDIR)/xdepends.txt 217 | endef 218 | 219 | .PHONY: depends 220 | depends: 221 | $(build-depends) 222 | 223 | $(OBJDIR)/depends.txt: depends 224 | 225 | # 226 | # Make sure the $(OBJDIR)/ directory exists. This has taken some work to get 227 | # right. While "mkdir -p $(OBJDIR)" could be used to do this as well, it 228 | # always bothered me that it seemed to be perpetually running. Hence, we'll 229 | # first check if the directory exists, and only create it if it does not. 230 | # Finally, by adding the @ in front of the bash command, it won't get printed 231 | # to the screen. That way ... I can run it as often as I want without getting 232 | # annoyed by it. ;) 233 | define mk-objdir 234 | @bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" 235 | endef 236 | 237 | # 238 | # The "tags" target 239 | # 240 | tags: $(SOURCES) $(HEADERS) 241 | @echo "Generating tags" 242 | @ctags $(SOURCES) $(HEADERS) 243 | 244 | # 245 | # The "clean" target, removing any and all remaining build (and test) products 246 | # 247 | .PHONY: clean 248 | clean: 249 | rm -f ./mkspeech ./speech.hex 250 | rm -f ./linetest ./linetestlite 251 | rm -f ./helloworld ./helloworldlite 252 | rm -f ./speechtest ./speechtestlite 253 | rm -rf $(OBJDIR)/ 254 | 255 | # Include our generated dependency file. The "-" in front of the include 256 | # basically tells "make" to include it if it can, and ignore it if it cannot 257 | # be included (i.e. if it doesn't exist) 258 | ifneq ($(MAKECMDGOALS),clean) 259 | -include $(OBJDIR)/depends.txt 260 | endif 261 | -------------------------------------------------------------------------------- /bench/cpp/README.md: -------------------------------------------------------------------------------- 1 | + C++ source files 2 | 3 | Items within this directory include: 4 | 5 | - uartsim defines a C++ class that can be used for simulating a UART within 6 | Verilator. This class can be used both to generate valid UART signaling, 7 | to determine if your configuration can receive it properly, as well as to decode 8 | valid UART signaling to determine if your configuration is properly setting the 9 | UART signaling wire. 10 | 11 | - speech.txt, and the associated speech.hex file, is the text that speechfifo 12 | will transmit. It is currently set to the Gettysburg Address. While you are welcome to change this, the length of this file is hard coded within the verilog file that references it. 13 | 14 | - mkspeech, a Verilog hex file generator--although it also converts newlines to 15 | carriage-return newline pairs 16 | 17 | - Demonstration projects using these: 18 | -- helloworld, exercises and tests the helloworld.v test bench 19 | -- linetest, exercises and tests the linetest.v test bench. This also creates a .VCD file which can be viewed via GTKwave 20 | -- speechtest, exercises and tests the speechfifo test bench. When run with the -i option, speechtest will also generate a .VCD file for use with GTKwave. 21 | 22 | -------------------------------------------------------------------------------- /bench/cpp/helloworld.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: helloworld.cpp 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To demonstrate a useful Verilog file which could be used as a 8 | // toplevel program later, to demo the transmit UART. 9 | // 10 | // Creator: Dan Gisselquist, Ph.D. 11 | // Gisselquist Technology, LLC 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // }}} 15 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 16 | // {{{ 17 | // This program is free software (firmware): you can redistribute it and/or 18 | // modify it under the terms of the GNU General Public License as published 19 | // by the Free Software Foundation, either version 3 of the License, or (at 20 | // your option) any later version. 21 | // 22 | // This program is distributed in the hope that it will be useful, but WITHOUT 23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | // for more details. 26 | // 27 | // You should have received a copy of the GNU General Public License along 28 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 29 | // target there if the PDF file isn't present.) If not, see 30 | // for a copy. 31 | // }}} 32 | // License: GPL, v3, as defined and found on www.gnu.org, 33 | // {{{ 34 | // http://www.gnu.org/licenses/gpl.html 35 | // 36 | // 37 | //////////////////////////////////////////////////////////////////////////////// 38 | // 39 | // }}} 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include "verilated.h" 49 | #include "verilated_vcd_c.h" 50 | #ifdef USE_UART_LITE 51 | #include "Vhelloworldlite.h" 52 | #define SIMCLASS Vhelloworldlite 53 | #else 54 | #include "Vhelloworld.h" 55 | #define SIMCLASS Vhelloworld 56 | #endif 57 | #include "uartsim.h" 58 | 59 | int main(int argc, char **argv) { 60 | Verilated::commandArgs(argc, argv); 61 | SIMCLASS tb; 62 | UARTSIM *uart; 63 | int port = 0; 64 | unsigned setup = 868, clocks = 0, baudclocks; 65 | 66 | // Set our baud rate 67 | // {{{ 68 | tb.i_setup = setup; 69 | uart = new UARTSIM(port); 70 | uart->setup(tb.i_setup); 71 | baudclocks = tb.i_setup & 0xfffffff; 72 | // }}} 73 | 74 | // Setup a VCD trace 75 | // {{{ 76 | #define VCDTRACE 77 | #ifdef VCDTRACE 78 | Verilated::traceEverOn(true); 79 | VerilatedVcdC* tfp = new VerilatedVcdC; 80 | tb.trace(tfp, 99); 81 | tfp->open("helloworld.vcd"); 82 | #define TRACE_POSEDGE tfp->dump(10*clocks) 83 | #define TRACE_NEGEDGE tfp->dump(10*clocks+5) 84 | #define TRACE_CLOSE tfp->close() 85 | #else 86 | #define TRACE_POSEDGE 87 | #define TRACE_NEGEDGE 88 | #define TRACE_CLOSE 89 | #endif 90 | // }}} 91 | 92 | // Main simulation loop 93 | // {{{ 94 | clocks = 0; 95 | while(clocks < 16*32*baudclocks) { 96 | 97 | tb.i_clk = 1; 98 | tb.eval(); 99 | TRACE_POSEDGE; 100 | tb.i_clk = 0; 101 | tb.eval(); 102 | TRACE_NEGEDGE; 103 | 104 | (*uart)(tb.o_uart_tx); 105 | clocks++; 106 | } 107 | // }}} 108 | 109 | TRACE_CLOSE; 110 | printf("\n\nSimulation complete\n"); 111 | } 112 | -------------------------------------------------------------------------------- /bench/cpp/linetest.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: linetest.cpp 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To create a pass-through test of the receiver and transmitter 8 | // which can be exercised/proven via Verilator. 9 | // 10 | // If you run this program with no arguments, it will run an automatic 11 | // test, returning "PASS" on success, or "FAIL" on failure as a last 12 | // output line--hence it should support automated testing. 13 | // 14 | // If you run with a '-i' argument, the program will run interactively. 15 | // It will then be up to you to determine if it works (or not). As 16 | // always, it may be killed with a control C. 17 | // 18 | // Creator: Dan Gisselquist, Ph.D. 19 | // Gisselquist Technology, LLC 20 | // 21 | //////////////////////////////////////////////////////////////////////////////// 22 | // }}} 23 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 24 | // {{{ 25 | // This program is free software (firmware): you can redistribute it and/or 26 | // modify it under the terms of the GNU General Public License as published 27 | // by the Free Software Foundation, either version 3 of the License, or (at 28 | // your option) any later version. 29 | // 30 | // This program is distributed in the hope that it will be useful, but WITHOUT 31 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 32 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 33 | // for more details. 34 | // 35 | // You should have received a copy of the GNU General Public License along 36 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 37 | // target there if the PDF file isn't present.) If not, see 38 | // for a copy. 39 | // }}} 40 | // License: GPL, v3, as defined and found on www.gnu.org, 41 | // {{{ 42 | // http://www.gnu.org/licenses/gpl.html 43 | // 44 | // 45 | //////////////////////////////////////////////////////////////////////////////// 46 | // 47 | // }}} 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include "verilated.h" 58 | #ifdef USE_UART_LITE 59 | #include "Vlinetestlite.h" 60 | #define SIMCLASS Vlinetestlite 61 | #else 62 | #include "Vlinetest.h" 63 | #define SIMCLASS Vlinetest 64 | #endif 65 | #include "verilated_vcd_c.h" 66 | #include "uartsim.h" 67 | 68 | int main(int argc, char **argv) { 69 | Verilated::commandArgs(argc, argv); 70 | UARTSIM *uart; 71 | bool run_interactively = false; 72 | int port = 0; 73 | unsigned setup = 868; 74 | char string[] = "This is a UART testing string\r\n"; 75 | 76 | // Argument processing 77 | // {{{ 78 | for(int argn=1; argnsetup(tb.i_setup); 110 | 111 | while(1) { 112 | 113 | tb.i_clk = 1; 114 | tb.eval(); 115 | tb.i_clk = 0; 116 | tb.eval(); 117 | 118 | tb.i_uart_rx = (*uart)(tb.o_uart_tx); 119 | } 120 | // }}} 121 | } else { 122 | // Set up a child process 123 | // {{{ 124 | int childs_stdin[2], childs_stdout[2]; 125 | 126 | if ((pipe(childs_stdin)!=0)||(pipe(childs_stdout) != 0)) { 127 | fprintf(stderr, "ERR setting up child pipes\n"); 128 | perror("O/S ERR"); 129 | printf("TEST FAILURE\n"); 130 | exit(EXIT_FAILURE); 131 | } 132 | 133 | pid_t childs_pid = fork(); 134 | 135 | if (childs_pid < 0) { 136 | fprintf(stderr, "ERR setting up child process\n"); 137 | perror("O/S ERR"); 138 | printf("TEST FAILURE\n"); 139 | exit(EXIT_FAILURE); 140 | } 141 | // }}} 142 | 143 | if (childs_pid) { // The parent, feeding the simulation 144 | // {{{ 145 | int nr=-2, nw; 146 | 147 | // We are the parent 148 | close(childs_stdin[ 0]); // Close the read end 149 | close(childs_stdout[1]); // Close the write end 150 | 151 | char test[256]; 152 | 153 | nw = write(childs_stdin[1], string, strlen(string)); 154 | if (nw == (int)strlen(string)) { 155 | int rpos = 0; 156 | test[0] = '\0'; 157 | while((rpos 0) 164 | test[rpos] = '\0'; 165 | printf("Successfully read %d characters: %s\n", nr, test); 166 | } 167 | 168 | int status = 0, rv = -1; 169 | 170 | // Give the child the oppoortunity to take another 171 | // 60 seconds to finish closing itself 172 | for(int waitcount=0; waitcount < 60; waitcount++) { 173 | rv = waitpid(-1, &status, WNOHANG); 174 | if (rv == childs_pid) 175 | break; 176 | else if (rv < 0) 177 | break; 178 | else // rv == 0 179 | sleep(1); 180 | } 181 | 182 | if (rv != childs_pid) { 183 | kill(childs_pid, SIGTERM); 184 | printf("WARNING: Child/simulator did not terminate normally\n"); 185 | } 186 | 187 | if (WEXITSTATUS(status) != EXIT_SUCCESS) { 188 | printf("WARNING: Child/simulator exit status does not indicate success\n"); 189 | } 190 | 191 | if ((nr == nw)&&(nw == (int)strlen(string)) 192 | &&(strcmp(test, string) == 0)) { 193 | printf("PASS!\n"); 194 | exit(EXIT_SUCCESS); 195 | } else { 196 | printf("TEST FAILED\n"); 197 | exit(EXIT_FAILURE); 198 | } 199 | // }}} 200 | } else { // The child (Verilator simulation) 201 | // {{{ 202 | 203 | // Fix up the FILE I/O 204 | // {{{ 205 | close(childs_stdin[ 1]); 206 | close(childs_stdout[0]); 207 | close(STDIN_FILENO); 208 | if (dup(childs_stdin[0]) < 0) { 209 | fprintf(stderr, "ERR setting up child FD\n"); 210 | perror("O/S ERR"); 211 | exit(EXIT_FAILURE); 212 | } 213 | close(STDOUT_FILENO); 214 | if (dup(childs_stdout[1]) < 0) { 215 | fprintf(stderr, "ERR setting up child FD\n"); 216 | perror("O/S ERR"); 217 | exit(EXIT_FAILURE); 218 | } 219 | 220 | // Setup the model and baud rate 221 | // {{{ 222 | SIMCLASS tb; 223 | tb.i_setup = setup; 224 | int baudclocks = setup & 0x0ffffff; 225 | tb.i_uart_rx = 1; 226 | // }}} 227 | 228 | // UARTSIM(0) uses stdin and stdout for its FD's 229 | uart = new UARTSIM(0); 230 | uart->setup(tb.i_setup); 231 | // }}} 232 | 233 | // Make sure we don't run longer than 4 seconds ... 234 | time_t start = time(NULL); 235 | int iterations_before_check = 2048; 236 | unsigned clocks = 0; 237 | bool done = false; 238 | 239 | // VCD trace setup 240 | // {{{ 241 | #define VCDTRACE 242 | #ifdef VCDTRACE 243 | Verilated::traceEverOn(true); 244 | VerilatedVcdC* tfp = new VerilatedVcdC; 245 | tb.trace(tfp, 99); 246 | tfp->open("linetest.vcd"); 247 | #define TRACE_POSEDGE tfp->dump(10*clocks) 248 | #define TRACE_NEGEDGE tfp->dump(10*clocks+5) 249 | #define TRACE_CLOSE tfp->close() 250 | #else 251 | #define TRACE_POSEDGE while(0) 252 | #define TRACE_NEGEDGE while(0) 253 | #define TRACE_CLOSE while(0) 254 | #endif 255 | // }}} 256 | 257 | // Clear any initial break condition 258 | // {{{ 259 | for(int i=0; i<(baudclocks*24); i++) { 260 | tb.i_clk = 1; 261 | tb.eval(); 262 | tb.i_clk = 0; 263 | tb.eval(); 264 | 265 | tb.i_uart_rx = 1; 266 | } 267 | // }}} 268 | 269 | // Simulation loop: process the hello world string 270 | // {{{ 271 | while(clocks < 2*(baudclocks*16)*strlen(string)) { 272 | tb.i_clk = 1; 273 | tb.eval(); 274 | TRACE_POSEDGE; 275 | tb.i_clk = 0; 276 | tb.eval(); 277 | TRACE_NEGEDGE; 278 | clocks++; 279 | 280 | tb.i_uart_rx = (*uart)(tb.o_uart_tx); 281 | 282 | if (false) { // Used only for debugging 283 | // {{{ 284 | /* 285 | static long counts = 0; 286 | static int lasti = 1, lasto = 1; 287 | bool writeout = false; 288 | 289 | counts++; 290 | if (lasti != tb.i_uart) { 291 | writeout = true; 292 | lasti = tb.i_uart; 293 | } if (lasto != tb.o_uart) { 294 | writeout = true; 295 | lasto = tb.o_uart; 296 | } 297 | 298 | if (writeout) { 299 | fprintf(stderr, "%08lx : [%d -> %d] %02x:%02x (%02x/%d) %d,%d->%02x [%2d/%d/%08x]\n", 300 | counts, tb.i_uart, tb.o_uart, 301 | tb.v__DOT__head, 302 | tb.v__DOT__tail, 303 | tb.v__DOT__lineend, 304 | tb.v__DOT__run_tx, 305 | tb.v__DOT__tx_stb, 306 | tb.v__DOT__transmitter__DOT__r_busy, 307 | tb.v__DOT__tx_data & 0x0ff, 308 | tb.v__DOT__transmitter__DOT__state, 309 | tb.v__DOT__transmitter__DOT__zero_baud_counter, 310 | tb.v__DOT__transmitter__DOT__baud_counter); 311 | } */ 312 | // }}} 313 | } 314 | 315 | if (iterations_before_check-- <= 0) { 316 | iterations_before_check = 2048; 317 | done = ((time(NULL)-start)>60); 318 | if (done) 319 | fprintf(stderr, "CHILD-TIMEOUT\n"); 320 | } 321 | } 322 | // }}} 323 | 324 | TRACE_CLOSE; 325 | 326 | exit(EXIT_SUCCESS); 327 | // }}} 328 | } 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /bench/cpp/mkspeech.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: mkspeech.cpp 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To turn a text file (i.e. the Gettysburg address) into a 8 | // hex file that can be included via readmemh. 9 | // 10 | // Creator: Dan Gisselquist, Ph.D. 11 | // Gisselquist Technology, LLC 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // }}} 15 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 16 | // {{{ 17 | // This program is free software (firmware): you can redistribute it and/or 18 | // modify it under the terms of the GNU General Public License as published 19 | // by the Free Software Foundation, either version 3 of the License, or (at 20 | // your option) any later version. 21 | // 22 | // This program is distributed in the hope that it will be useful, but WITHOUT 23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | // for more details. 26 | // 27 | // You should have received a copy of the GNU General Public License along 28 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 29 | // target there if the PDF file isn't present.) If not, see 30 | // for a copy. 31 | // }}} 32 | // License: GPL, v3, as defined and found on www.gnu.org, 33 | // {{{ 34 | // http://www.gnu.org/licenses/gpl.html 35 | // 36 | // 37 | //////////////////////////////////////////////////////////////////////////////// 38 | // 39 | // }}} 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | /* 46 | * endswith 47 | * {{{ 48 | * Real simple: returns true if the given string ends with the given ending. 49 | * Useful for determining if a file ends with the extension .txt. 50 | * 51 | */ 52 | bool endswith(const char *str, const char *ending) { 53 | int slen = strlen(str), send = strlen(ending); 54 | if (slen < send) 55 | return false; 56 | if (strcmp(&str[slen-send], ".txt")!=0) 57 | return false; 58 | return true; 59 | } 60 | // }}} 61 | 62 | /* 63 | * usage() 64 | * {{{ 65 | * Tell the user the calling conventions of this program, and what the program 66 | * can be used to accomplish. 67 | */ 68 | void usage(void) { 69 | fprintf(stderr, "USAGE:\tmkspeech [-x] .txt [-o ]\n"); 70 | fprintf(stderr, "\n" 71 | "\tConverts a text file to a file such as can be included in a Verilog\n" 72 | "\tprogram. Without the -x argument, the mkspeech program defaults\n" 73 | "\tto converting the text file to a hex file, whose output name defaults\n" 74 | "\tto \'speech.hex\'. With the -x argument, mkspeech converts the file\n" 75 | "\tinto an include file such as might be used in a Verilog program\n" 76 | "\tif and when the synthesis tool doesn\'t support hex files (Xilinx\'s\n" 77 | "\tISE). In this case, the output filename defaults to \'speech.inc\'.\n" 78 | "\n\n"); 79 | } 80 | // }}} 81 | 82 | int main(int argc, char **argv) { 83 | FILE *fp, *fout; 84 | const char *input_filename = NULL, *output_filename = NULL; 85 | bool xise_file = false; 86 | 87 | // Argument processing 88 | // {{{ 89 | for(int argn=1; argn < argc; argn++) { 90 | if (argv[argn][0] == '-') { 91 | if (argv[argn][2] == '\0') { 92 | if (argv[argn][1] == 'x') 93 | xise_file = true; 94 | else if (argv[argn][1] == 'o') { 95 | if (argn+1= 77) { 198 | fprintf(fout, "\n"); 199 | linelen = 0; 200 | fprintf(fout, "@%08x ", addr); linelen += 4+6; 201 | } 202 | } 203 | fprintf(fout, "%02x ", ch & 0x0ff); linelen += 3; addr++; 204 | 205 | if (linelen >= 77) { 206 | fprintf(fout, "\n"); 207 | linelen = 0; 208 | fprintf(fout, "@%08x ", addr); linelen += 4+6; 209 | } 210 | } fprintf(fout, "\n"); 211 | // }}} 212 | } 213 | fclose(fp); 214 | fclose(fout); 215 | } 216 | -------------------------------------------------------------------------------- /bench/cpp/speech.txt: -------------------------------------------------------------------------------- 1 | |===================================================================| 2 | | | 3 | | Four score and seven years ago our fathers brought forth on this | 4 | | continent, a new nation, conceived in Liberty, and dedicated to | 5 | | the proposition that all men are created equal. | 6 | | | 7 | | Now we are engaged in a great civil war, testing whether that | 8 | | nation, or any nation so conceived and so dedicated, can long | 9 | | endure. We are met on a great battle-field of that war. We have | 10 | | come to dedicate a portion of that field, as a final resting | 11 | | place for those who here gave their lives that that nation might | 12 | | live. It is altogether fitting and proper that we should do this. | 13 | | | 14 | | But, in a larger sense, we can not dedicate-we can not consecrate-| 15 | | we can not hallow-this ground. The brave men, living and dead, | 16 | | who struggled here, have consecrated it, far above our poor power | 17 | | to add or detract. The world will little note, nor long remember | 18 | | what we say here, but it can never forget what they did here. It | 19 | | is for us the living, rather, to be dedicated here to the | 20 | | unfinished work which they who fought here have thus far so nobly | 21 | | advanced. It is rather for us to be here dedicated to the great | 22 | | task remaining before us-that from these honored dead we take | 23 | | increased devotion to that cause for which they gave the last | 24 | | full measure of devotion-that we here highly resolve that these | 25 | | dead shall not have died in vain-that this nation, under God, | 26 | | shall have a new birth of freedom-and that government of the | 27 | | people, by the people, for the people, shall not perish from the | 28 | | earth. | 29 | | | 30 | | | 31 | |===================================================================| 32 | 33 | -------------------------------------------------------------------------------- /bench/cpp/speechtest.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: speechtest.cpp 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To demonstrate a useful Verilog file which could be used as a 8 | // toplevel program later, to demo the transmit UART as it might 9 | // be commanded from a WB bus, and having a FIFO. 10 | // 11 | // If all goes well, the program will write out the words of the Gettysburg 12 | // address in interactive mode. In non-interactive mode, the program will 13 | // read its own output and report on whether or not it worked well. 14 | // 15 | // Creator: Dan Gisselquist, Ph.D. 16 | // Gisselquist Technology, LLC 17 | // 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // }}} 20 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 21 | // {{{ 22 | // This program is free software (firmware): you can redistribute it and/or 23 | // modify it under the terms of the GNU General Public License as published 24 | // by the Free Software Foundation, either version 3 of the License, or (at 25 | // your option) any later version. 26 | // 27 | // This program is distributed in the hope that it will be useful, but WITHOUT 28 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 29 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 30 | // for more details. 31 | // 32 | // You should have received a copy of the GNU General Public License along 33 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 34 | // target there if the PDF file isn't present.) If not, see 35 | // for a copy. 36 | // }}} 37 | // License: GPL, v3, as defined and found on www.gnu.org, 38 | // {{{ 39 | // http://www.gnu.org/licenses/gpl.html 40 | // 41 | // 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // }}} 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include "verilated.h" 55 | #ifdef USE_UART_LITE 56 | #include "Vspeechfifolite.h" 57 | #define SIMCLASS Vspeechfifolite 58 | #else 59 | #include "Vspeechfifo.h" 60 | #define SIMCLASS Vspeechfifo 61 | #endif 62 | #include "uartsim.h" 63 | #include "verilated_vcd_c.h" 64 | 65 | void usage(void) { 66 | // {{{ 67 | fprintf(stderr, "USAGE: speechtest [-i] [.txt]\n"); 68 | fprintf(stderr, "\n" 69 | "\tWhere ... \n" 70 | "\t-i\tis an optional argument, instructing speechtest to run\n" 71 | "\t\tinteractively. This mode offers no checkin against any possible\n" 72 | "\t\ttruth or match file.\n" 73 | "\n" 74 | "\t\t is the name of a file which will be compared against\n" 75 | "\t\tthe output of the simulation. If the output matches the match\n" 76 | "\t\tfile, the simulation will exit with success. Only the number of\n" 77 | "\t\tcharacters in the match file will be tested.\n\n"); 78 | }; 79 | // }}} 80 | 81 | int main(int argc, char **argv) { 82 | Verilated::commandArgs(argc, argv); 83 | SIMCLASS tb; 84 | UARTSIM *uart; 85 | int port = 0; 86 | unsigned setup = 25, testcount = 0, baudclocks; 87 | const char *matchfile = "speech.txt"; 88 | bool run_interactively = false; 89 | 90 | // Argument processing 91 | // {{{ 92 | for(int argn=1; argnsetup(tb.i_setup); 124 | 125 | Verilated::traceEverOn(true); 126 | VerilatedVcdC* tfp = new VerilatedVcdC; 127 | tb.trace(tfp, 99); 128 | tfp->open("speechtrace.vcd"); 129 | 130 | testcount = 0; 131 | while(testcount < baudclocks * 16 * 4096) { 132 | // Run one tick of the clock. 133 | 134 | tb.i_clk = 1; // Positive edge 135 | tb.eval(); 136 | tfp->dump(5*(2*testcount)); 137 | tb.i_clk = 0; // Negative edge 138 | tb.eval(); 139 | 140 | // Now, evaluate the UART, throwing away the received 141 | // value since the SpeechTest doesnt use it. 142 | (*uart)(tb.o_uart_tx); 143 | 144 | tfp->dump(5*(2*testcount+1)); 145 | testcount++; 146 | 147 | // #define DEBUG 148 | #ifdef DEBUG 149 | // 150 | // Here are my notes from my last attempt at debug by printf. 151 | printf("%08x ", 152 | tb.v__DOT__restart_counter); 153 | printf("%s %s@%d<-%08x[%c/%4d] (%s%s,%08x,%2d,%2d,%2d,%c,%s) %s,%02x >%d\n", 154 | (tb.v__DOT__restart)?"RST":" ", 155 | (tb.v__DOT__wb_stb)?"STB":" ", 156 | (tb.v__DOT__wb_addr), 157 | (tb.v__DOT__wb_data), 158 | isgraph(tb.v__DOT__wb_data&0x0ff)? 159 | (tb.v__DOT__wb_data&0x0ff) : '.', 160 | (tb.v__DOT__msg_index), 161 | (tb.v__DOT__wbuarti__DOT____Vcellinp__txfifo____pinNumber2)?"RST":" ", 162 | (tb.v__DOT__wbuarti__DOT__txf_wb_write)?"WR":" ", 163 | (tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_fill), 164 | (tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_first), 165 | (tb.v__DOT__wbuarti__DOT__txfifo__DOT__w_first_plus_one), 166 | (tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_last), 167 | isgraph(tb.v__DOT__wbuarti__DOT__tx_data&0x0ff)? 168 | (tb.v__DOT__wbuarti__DOT__tx_data&0x0ff) : '.', 169 | (tb.v__DOT__wbuarti__DOT____Vcellinp__txfifo____pinNumber5)?"RD":" ", 170 | (tb.v__DOT__wbuarti__DOT__tx_empty_n)?"TXI":"EMP", 171 | (tb.v__DOT__wbuarti__DOT__tx_data), 172 | (tb.o_uart_tx)); 173 | #endif 174 | } 175 | 176 | tfp->close(); 177 | 178 | // 179 | // *IF* we ever get here, then at least explain to the user 180 | // why we stopped. 181 | // 182 | printf("\n\nSimulation complete\n"); 183 | // }}} 184 | } else { 185 | // 186 | // Non-interactive mode is more difficult. In this case, we 187 | // {{{ 188 | // must figure out how to determine if the test was successful 189 | // or not. Since uartsim dumps the UART output to standard 190 | // out, we then need to do a bit of work to capture that. 191 | // 192 | // In particular, we are going to fork ourselves and set up our 193 | // child process so that we can read from its standard out 194 | // (and write to its standard in--although we don't). 195 | // }}} 196 | 197 | // Setup parent/child processes 198 | // {{{ 199 | int childs_stdin[2], childs_stdout[2]; 200 | FILE *fp = fopen(matchfile, "r"); 201 | long flen = 0; 202 | 203 | // 204 | // Before forking (and getting complicated), let's read the 205 | // file describing the data we are supposed to read. Our goal 206 | // will basically be to do an strncmp with the data in this 207 | // file, and then to check for zero (equality). 208 | // 209 | if (fp == NULL) { 210 | fprintf(stderr, "ERR - could not open %s\n", matchfile); 211 | perror("O/S Err:"); 212 | printf("FAIL\n"); 213 | exit(EXIT_FAILURE); 214 | } 215 | 216 | // Quick, look up how long this file is. 217 | fseek(fp, 0l, SEEK_END); 218 | flen = ftell(fp); 219 | fseek(fp, 0l, SEEK_SET); 220 | 221 | if (flen <= 0) { 222 | if (flen == 0) 223 | fprintf(stderr, "ERR - zero length match file!\n"); 224 | else { 225 | fprintf(stderr, "ERR - getting file length\n"); 226 | perror("O/S Err:"); 227 | } 228 | printf("FAIL\n"); 229 | exit(EXIT_FAILURE); 230 | } 231 | 232 | 233 | // We are ready to do our forking magic. So, let's allocate 234 | // pipes for the childs standard input and output streams. 235 | if ((pipe(childs_stdin)!=0)||(pipe(childs_stdout) != 0)) { 236 | fprintf(stderr, "ERR setting up child pipes\n"); 237 | perror("O/S Err:"); 238 | printf("FAIL\n"); 239 | exit(EXIT_FAILURE); 240 | } 241 | 242 | 243 | // 244 | // FORK !!!!! 245 | // 246 | // After this line, there are two threads running--a parent and 247 | // a child. The childs child_pid will be zero, the parents 248 | // child_pid will be the pid of the child. 249 | pid_t child_pid = fork(); 250 | 251 | // Make sure the fork worked ... 252 | if (child_pid < 0) { 253 | fprintf(stderr, "ERR setting up child process fork\n"); 254 | perror("O/S Err:"); 255 | printf("FAIL\n"); 256 | exit(EXIT_FAILURE); 257 | } 258 | // }}} 259 | 260 | if (child_pid) { // We are the parent 261 | // {{{ 262 | int nr = -2, rd, fail; 263 | 264 | // Set up the parents file relationships 265 | // {{{ 266 | // Adjust our pipe file descriptors so that they are 267 | // useful. 268 | close(childs_stdin[ 0]); // Close the read end 269 | close(childs_stdout[1]); // Close the write end 270 | // }}} 271 | 272 | // Read the string to match against here 273 | // {{{ 274 | // Let's allocate some buffers to contain both our 275 | // match file (string), and what we read from the 276 | // UART. Nominally, we would only need flen+1 277 | // characters, but this number doesn't quite work--since 278 | // mkspeech turned all of the the LFs into CR/LF pairs. 279 | // In the worst case, this would double the number of 280 | // characters we would need. Hence, we read allocate 281 | // enough for the worst case. 282 | char *string = (char *)malloc((size_t)(2*flen+2)), 283 | *rdbuf = (char *)malloc((size_t)(2*flen+2)); 284 | 285 | // If this doesn't work, admit to a failure 286 | if ((string == NULL)||(rdbuf == NULL)) { 287 | fprintf(stderr, "ERR Malloc failure --- cannot allocate space to read match file\n"); 288 | perror("O/S Err:"); 289 | printf("FAIL\n"); 290 | exit(EXIT_FAILURE); 291 | } 292 | 293 | // Read the string we are going to match against from 294 | // the matchfile. Expand NLs into CR,NL pairs. Also 295 | // keep track of the resulting length (in flen), and 296 | // terminate the string with a null character. 297 | // 298 | { 299 | // Read string, and expand newlines into 300 | // CR LF pairs 301 | char *dp = string; 302 | int ch; 303 | while((ch =fgetc(fp))!=EOF) { 304 | if (ch == '\n') 305 | *dp++ = '\r'; 306 | *dp++ = ch; 307 | } 308 | *dp++ = '\0'; 309 | flen = strlen(string); 310 | } 311 | // }}} 312 | 313 | // Read from the sim and compare 314 | // {{{ 315 | // Enough setup, let's do our work: Read a character 316 | // from the pipe and compare it against what we are 317 | // expecting. Break out on any comparison failure. 318 | // 319 | nr = 0; 320 | rd = 0; 321 | fail = -1; 322 | while((nr0)) { 325 | for(int i=0; i=0) 331 | break; 332 | rdbuf[rd+nr] = 0; 333 | nr += rd; 334 | } 335 | // }}} 336 | 337 | // Kill the child and clean up 338 | // {{{ 339 | // Tell the user how many (of how many) characters we 340 | // compared (that matched), for debugging purposes. 341 | // 342 | printf("MATCH COMPLETE, nr = %d (/ %ld)\n", nr, flen); 343 | fflush(stdout); 344 | 345 | kill(child_pid, SIGKILL); 346 | 347 | free(string); 348 | free(rdbuf); 349 | // }}} 350 | 351 | // Report on the results, either PASS or FAIL 352 | // {{{ 353 | if (nr == flen) { 354 | printf("PASS\n"); 355 | exit(EXIT_SUCCESS); 356 | } else { 357 | printf("%s\n\nDoes not match. MISMATCH: ch[%d]=%c != %c (%02x)\nFAIL\n", rdbuf, fail, rdbuf[fail], string[fail], string[fail]); 358 | exit(EXIT_FAILURE); 359 | } 360 | // 361 | // At this point, the parent is complete, and can 362 | // exit. 363 | // }}} 364 | // }}} 365 | } else { // If childs_pid == 0, then we are the child 366 | // {{{ 367 | 368 | // Finish setting up the child's I/O 369 | // {{{ 370 | // The child reports the uart result via stdout, so 371 | // let's make certain it points to STDOUT_FILENO. 372 | // 373 | close(childs_stdin[ 1]); // Close the write end 374 | close(childs_stdout[0]); // Close the read end 375 | 376 | // Now, adjust our stdin/stdout file numbers 377 | // Stdin first. (Yes, I know we arent use stdin, this 378 | // is more for form than anything else.) 379 | close(STDIN_FILENO); 380 | if (dup(childs_stdin[0]) != STDIN_FILENO) { 381 | fprintf(stderr, "Could not create childs stdin\n"); 382 | perror("O/S ERR"); 383 | exit(EXIT_FAILURE); 384 | } 385 | 386 | // Set up the standard out file descriptor so that it 387 | // points to our pipe 388 | close(STDOUT_FILENO); 389 | if (dup(childs_stdout[1]) != STDOUT_FILENO) { 390 | fprintf(stderr, "Could not create childs stdout\n"); 391 | perror("O/S ERR"); 392 | exit(EXIT_FAILURE); 393 | } 394 | // }}} 395 | 396 | // Set the UARTSIM up to producing an output to the 397 | // STDOUT, rather than a TCP/IP port 398 | uart = new UARTSIM(0); 399 | // Set up our baud rate, stop bits, parity, etc. 400 | // properly 401 | uart->setup(tb.i_setup); 402 | 403 | // Main simulation loop 404 | // {{{ 405 | // Now ... we're finally ready to run our simulation. 406 | // 407 | // while(testcount < baudclocks * 16 * 2048) 408 | while(testcount++ < 0x7f000000) { 409 | // Rising edge of the clock 410 | tb.i_clk = 1; 411 | tb.eval(); 412 | // Negative edge of the clock 413 | tb.i_clk = 0; 414 | tb.eval(); 415 | 416 | // Advance the UART based upon the output 417 | // o_uart_tx value 418 | (*uart)(tb.o_uart_tx); 419 | } 420 | // }}} 421 | 422 | // Fail if we ever get here 423 | // {{{ 424 | // We will never get here. If all goes well, we will be 425 | // killed as soon as we produce the speech.txt file 426 | // output--many clocks before this. 427 | 428 | // 429 | // If we do get here, something is terribly wrong. 430 | // 431 | fprintf(stderr, "Child was never killed, did it produce any output?\n"); 432 | fprintf(stderr, "FAIL\n"); 433 | exit(EXIT_FAILURE); 434 | // }}} 435 | // }}} 436 | } 437 | } 438 | } 439 | 440 | -------------------------------------------------------------------------------- /bench/cpp/uartsim.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: uartsim.cpp 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To forward a Verilator simulated UART link over a TCP/IP pipe. 8 | // 9 | // Creator: Dan Gisselquist, Ph.D. 10 | // Gisselquist Technology, LLC 11 | // 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // }}} 14 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 15 | // {{{ 16 | // This program is free software (firmware): you can redistribute it and/or 17 | // modify it under the terms of the GNU General Public License as published 18 | // by the Free Software Foundation, either version 3 of the License, or (at 19 | // your option) any later version. 20 | // 21 | // This program is distributed in the hope that it will be useful, but WITHOUT 22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24 | // for more details. 25 | // 26 | // You should have received a copy of the GNU General Public License along 27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 28 | // target there if the PDF file isn't present.) If not, see 29 | // for a copy. 30 | // }}} 31 | // License: GPL, v3, as defined and found on www.gnu.org, 32 | // {{{ 33 | // http://www.gnu.org/licenses/gpl.html 34 | // 35 | // 36 | //////////////////////////////////////////////////////////////////////////////// 37 | // 38 | // }}} 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #include "uartsim.h" 51 | 52 | // setup_listener 53 | // {{{ 54 | void UARTSIM::setup_listener(const int port) { 55 | struct sockaddr_in my_addr; 56 | 57 | signal(SIGPIPE, SIG_IGN); 58 | 59 | printf("Listening on port %d\n", port); 60 | 61 | m_skt = socket(AF_INET, SOCK_STREAM, 0); 62 | if (m_skt < 0) { 63 | perror("ERR: Could not allocate socket: "); 64 | exit(EXIT_FAILURE); 65 | } 66 | 67 | // Set the reuse address option 68 | { 69 | int optv = 1, er; 70 | er = setsockopt(m_skt, SOL_SOCKET, SO_REUSEADDR, &optv, sizeof(optv)); 71 | if (er != 0) { 72 | perror("ERR: SockOpt Err:"); 73 | exit(EXIT_FAILURE); 74 | } 75 | } 76 | 77 | memset(&my_addr, 0, sizeof(struct sockaddr_in)); // clear structure 78 | my_addr.sin_family = AF_INET; 79 | // Use *all* internet ports to this computer, allowing connections from 80 | // any/every one of them. 81 | my_addr.sin_addr.s_addr = htonl(INADDR_ANY); 82 | my_addr.sin_port = htons(port); 83 | 84 | if (bind(m_skt, (struct sockaddr *)&my_addr, sizeof(my_addr))!=0) { 85 | perror("ERR: BIND FAILED:"); 86 | exit(EXIT_FAILURE); 87 | } 88 | 89 | if (listen(m_skt, 1) != 0) { 90 | perror("ERR: Listen failed:"); 91 | exit(EXIT_FAILURE); 92 | } 93 | } 94 | // }}} 95 | 96 | // UARTSIM::UARTSIM(const int port) 97 | // {{{ 98 | UARTSIM::UARTSIM(const int port) { 99 | m_conrd = m_conwr = m_skt = -1; 100 | if (port == 0) { 101 | m_conrd = STDIN_FILENO; 102 | m_conwr = STDOUT_FILENO; 103 | } else 104 | setup_listener(port); 105 | setup(25); // Set us up for (default) 8N1 w/ a baud rate of CLK/25 106 | m_rx_baudcounter = 0; 107 | m_tx_baudcounter = 0; 108 | m_rx_state = RXIDLE; 109 | m_tx_state = TXIDLE; 110 | } 111 | // }}} 112 | 113 | // UARTSIM::kill 114 | // {{{ 115 | void UARTSIM::kill(void) { 116 | fflush(stdout); 117 | 118 | // Quickly double check that we aren't about to close stdin/stdout 119 | if (m_conrd == STDIN_FILENO) 120 | m_conrd = -1; 121 | if (m_conwr == STDOUT_FILENO) 122 | m_conwr = -1; 123 | // Close any active connection 124 | if (m_conrd >= 0) close(m_conrd); 125 | if ((m_conwr >= 0)&&(m_conwr != m_conrd)) close(m_conwr); 126 | if (m_skt >= 0) close(m_skt); 127 | 128 | m_conrd = m_conwr = m_skt = -1; 129 | } 130 | // }}} 131 | 132 | // UARTSIM::setup(isetup) 133 | // {{{ 134 | void UARTSIM::setup(unsigned isetup) { 135 | if (isetup != m_setup) { 136 | m_setup = isetup; 137 | m_baud_counts = (isetup & 0x0ffffff); 138 | m_nbits = 8-((isetup >> 28)&0x03); 139 | m_nstop =((isetup >> 27)&1)+1; 140 | m_nparity = (isetup >> 26)&1; 141 | m_fixdp = (isetup >> 25)&1; 142 | m_evenp = (isetup >> 24)&1; 143 | } 144 | } 145 | // }}} 146 | 147 | // UARTSIM::check_for_new_connections 148 | // {{{ 149 | void UARTSIM::check_for_new_connections(void) { 150 | if ((m_conrd < 0)&&(m_conwr<0)&&(m_skt>=0)) { 151 | // Can we accept a connection? 152 | struct pollfd pb; 153 | 154 | pb.fd = m_skt; 155 | pb.events = POLLIN; 156 | poll(&pb, 1, 0); 157 | 158 | if (pb.revents & POLLIN) { 159 | m_conrd = accept(m_skt, 0, 0); 160 | m_conwr = m_conrd; 161 | 162 | if (m_conrd < 0) 163 | perror("Accept failed:"); 164 | // else printf("New connection accepted!\n"); 165 | } 166 | } 167 | 168 | } 169 | // }}} 170 | 171 | // UARTSIM::rawtick(i_tx, network) 172 | // {{{ 173 | int UARTSIM::rawtick(const int i_tx, const bool network) { 174 | int o_rx = 1, nr = 0; 175 | 176 | if (network) 177 | check_for_new_connections(); 178 | 179 | if ((!i_tx)&&(m_last_tx)) 180 | m_rx_changectr = 0; 181 | else m_rx_changectr++; 182 | m_last_tx = i_tx; 183 | 184 | if (m_rx_state == RXIDLE) { 185 | if (!i_tx) { 186 | m_rx_state = RXDATA; 187 | m_rx_baudcounter =m_baud_counts+m_baud_counts/2-1; 188 | m_rx_baudcounter -= m_rx_changectr; 189 | m_rx_busy = 0; 190 | m_rx_data = 0; 191 | } 192 | } else if (m_rx_baudcounter <= 0) { 193 | if (m_rx_busy >= (1<<(m_nbits+m_nparity+m_nstop-1))) { 194 | m_rx_state = RXIDLE; 195 | if (m_conwr >= 0) { 196 | char buf[1]; 197 | buf[0] = (m_rx_data >> (32-m_nbits-m_nstop-m_nparity))&0x0ff; 198 | if ((network)&&(1 != send(m_conwr, buf, 1, 0))) { 199 | close(m_conwr); 200 | m_conrd = m_conwr = -1; 201 | fprintf(stderr, "Failed write, connection closed\n"); 202 | } else if ((!network)&&(1 != write(m_conwr, buf, 1))) { 203 | fprintf(stderr, "ERR while attempting to write out--closing output port\n"); 204 | perror("UARTSIM::write() "); 205 | m_conrd = m_conwr = -1; 206 | } 207 | } 208 | } else { 209 | m_rx_busy = (m_rx_busy << 1)|1; 210 | // Low order bit is transmitted first, in this 211 | // order: 212 | // Start bit (1'b1) 213 | // bit 0 214 | // bit 1 215 | // bit 2 216 | // ... 217 | // bit N-1 218 | // (possible parity bit) 219 | // stop bit 220 | // (possible secondary stop bit) 221 | m_rx_data = ((i_tx&1)<<31) | (m_rx_data>>1); 222 | } m_rx_baudcounter = m_baud_counts-1; 223 | } else 224 | m_rx_baudcounter--; 225 | 226 | if ((m_tx_state == TXIDLE)&&((network)||(m_conrd >= 0))) { 227 | struct pollfd pb; 228 | pb.fd = m_conrd; 229 | pb.events = POLLIN; 230 | if (poll(&pb, 1, 0) < 0) 231 | perror("Polling error:"); 232 | 233 | if (pb.revents & POLLIN) { 234 | char buf[1]; 235 | 236 | if (network) 237 | nr = recv(m_conrd, buf, 1, MSG_DONTWAIT); 238 | else 239 | nr = read(m_conrd, buf, 1); 240 | if (1 == nr) { 241 | m_tx_data = (-1<<(m_nbits+m_nparity+1)) 242 | // << nstart_bits 243 | |((buf[0]<<1)&0x01fe); 244 | if (m_nparity) { 245 | int p; 246 | 247 | // If m_nparity is set, we need to then 248 | // create the parity bit. 249 | if (m_fixdp) 250 | p = m_evenp; 251 | else { 252 | p = (m_tx_data >> 1)&0x0ff; 253 | p = p ^ (p>>4); 254 | p = p ^ (p>>2); 255 | p = p ^ (p>>1); 256 | p &= 1; 257 | p ^= m_evenp; 258 | } 259 | m_tx_data |= (p<<(m_nbits+m_nparity)); 260 | } 261 | m_tx_busy = (1<<(m_nbits+m_nparity+m_nstop+1))-1; 262 | m_tx_state = TXDATA; 263 | o_rx = 0; 264 | m_tx_baudcounter = m_baud_counts-1; 265 | } else if ((network)&&(nr == 0)) { 266 | close(m_conrd); 267 | m_conrd = m_conwr = -1; 268 | // printf("Closing network connection\n"); 269 | } else if (nr < 0) { 270 | if (!network) { 271 | fprintf(stderr, "ERR while attempting to read in--closing input port\n"); 272 | perror("UARTSIM::read() "); 273 | m_conrd = -1; 274 | } else { 275 | perror("O/S Read err:"); 276 | close(m_conrd); 277 | m_conrd = m_conwr = -1; 278 | } 279 | } 280 | } 281 | } else if (m_tx_baudcounter <= 0) { 282 | m_tx_data >>= 1; 283 | m_tx_busy >>= 1; 284 | if (!m_tx_busy) 285 | m_tx_state = TXIDLE; 286 | else 287 | m_tx_baudcounter = m_baud_counts-1; 288 | o_rx = m_tx_data&1; 289 | } else { 290 | m_tx_baudcounter--; 291 | o_rx = m_tx_data&1; 292 | } 293 | 294 | return o_rx; 295 | } 296 | // }}} 297 | 298 | // UARTSIM::nettick 299 | // {{{ 300 | int UARTSIM::nettick(const int i_tx) { 301 | return rawtick(i_tx, true); 302 | } 303 | // }}} 304 | 305 | // UARTSIM::fdtick 306 | // {{{ 307 | int UARTSIM::fdtick(const int i_tx) { 308 | return rawtick(i_tx, false); 309 | } 310 | // }}} 311 | -------------------------------------------------------------------------------- /bench/cpp/uartsim.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: uartsim.h 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To forward a Verilator simulated UART link over a TCP/IP pipe. 8 | // 9 | // This file provides the description of the interface between the UARTSIM 10 | // and the rest of the world. See below for more detailed descriptions. 11 | // 12 | // Creator: Dan Gisselquist, Ph.D. 13 | // Gisselquist Technology, LLC 14 | // 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // }}} 17 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 18 | // {{{ 19 | // This program is free software (firmware): you can redistribute it and/or 20 | // modify it under the terms of the GNU General Public License as published 21 | // by the Free Software Foundation, either version 3 of the License, or (at 22 | // your option) any later version. 23 | // 24 | // This program is distributed in the hope that it will be useful, but WITHOUT 25 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 26 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27 | // for more details. 28 | // 29 | // You should have received a copy of the GNU General Public License along 30 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 31 | // target there if the PDF file isn't present.) If not, see 32 | // for a copy. 33 | // }}} 34 | // License: GPL, v3, as defined and found on www.gnu.org, 35 | // {{{ 36 | // http://www.gnu.org/licenses/gpl.html 37 | // 38 | // 39 | //////////////////////////////////////////////////////////////////////////////// 40 | // 41 | // }}} 42 | #ifndef UARTSIM_H 43 | #define UARTSIM_H 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #define TXIDLE 0 56 | #define TXDATA 1 57 | #define RXIDLE 0 58 | #define RXDATA 1 59 | 60 | class UARTSIM { 61 | // Member declarations 62 | // {{{ 63 | // The file descriptors: 64 | // m_skt is the socket/port we are listening on 65 | // m_conrd is the file descriptor to read from 66 | // m_conwr is the file descriptor to write to 67 | int m_skt, m_conrd, m_conwr; 68 | // 69 | // The m_setup register is the 29'bit control register used within 70 | // the core. 71 | unsigned m_setup; 72 | // And the pieces of the setup register broken out. 73 | int m_nparity, m_fixdp, m_evenp, m_nbits, m_nstop, m_baud_counts; 74 | 75 | // UART state 76 | int m_rx_baudcounter, m_rx_state, m_rx_busy, 77 | m_rx_changectr, m_last_tx; 78 | int m_tx_baudcounter, m_tx_state, m_tx_busy; 79 | unsigned m_rx_data, m_tx_data; 80 | // }}} 81 | 82 | // Private methods 83 | // {{{ 84 | // setup_listener is an attempt to encapsulate all of the network 85 | // related setup stuff. 86 | void setup_listener(const int port); 87 | 88 | // Call check_for_new_connections() to see if we can accept a new 89 | // network socket connection to our device 90 | void check_for_new_connections(void); 91 | 92 | // nettick() gets called if we are connected to a network, and 93 | int nettick(const int i_tx); 94 | int fdtick(const int i_tx); 95 | int rawtick(const int i_tx, const bool network); 96 | 97 | // We'll use the file descriptor for the listener socket to determine 98 | // whether we are connected to the network or not. If not connected 99 | // to the network, then we assume m_conrd and m_conwr refer to 100 | // your more traditional file descriptors, and use them as such. 101 | int tick(const int i_tx) { 102 | return rawtick(i_tx, (m_skt >= 0)); 103 | } 104 | // }}} 105 | public: 106 | // Public member functions 107 | // {{{ 108 | 109 | // UARTSIM(port) 110 | // {{{ 111 | // The UARTSIM constructor takes one argument: the port on the 112 | // localhost to listen in on. Once started, connections may be made 113 | // to this port to get the output from the port. 114 | UARTSIM(const int port); 115 | // }}} 116 | 117 | // kill(void) 118 | // {{{ 119 | // kill() closes any active connection and the socket. Once killed, 120 | // no further output will be sent to the port. 121 | void kill(void); 122 | // }}} 123 | 124 | // setup(isetup) 125 | // {{{ 126 | // setup() busts out the bits from isetup to the various internal 127 | // parameters. It is ideally only called between bits at appropriate 128 | // transition intervals. 129 | void setup(unsigned isetup); 130 | // }}} 131 | 132 | // operator()(i_tx) 133 | // {{{ 134 | // The operator() function is called on every tick. The input is the 135 | // the output txuart transmit wire from the device. The output is to 136 | // be connected to the the rxuart receive wire into the device. This 137 | // makes hookup and operation very simple. 138 | // 139 | // This is the most appropriate simulation entry function if the 140 | // setup register will never change. 141 | // 142 | int operator()(int i_tx) { 143 | return tick(i_tx); } 144 | // }}} 145 | 146 | // operator()(i_tx, isetup) 147 | // {{{ 148 | // If there is a possibility that the core might change the UART setup, 149 | // then it makes sense to include that current setup when calling the 150 | // tick operator. 151 | int operator()(int i_tx, unsigned isetup) { 152 | setup(isetup); return tick(i_tx); } 153 | // }}} 154 | // }}} 155 | }; 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /bench/formal/.gitignore: -------------------------------------------------------------------------------- 1 | rxuartlite_*/ 2 | txuartlite_*/ 3 | ufifo_*/ 4 | ctrtest 5 | txuart 6 | axiluart_*/ 7 | -------------------------------------------------------------------------------- /bench/formal/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: Makefile 4 | ## {{{ 5 | ## Project: wbuart32, a full featured UART with simulator 6 | ## 7 | ## Purpose: To direct the formal verification of the UART (and FIFO) 8 | ## sources. 9 | ## 10 | ## Targets: The default target, all, tests all of the components defined 11 | ## within this module. 12 | ## 13 | ## Creator: Dan Gisselquist, Ph.D. 14 | ## Gisselquist Technology, LLC 15 | ## 16 | ################################################################################ 17 | ## }}} 18 | ## Copyright (C) 2017-2024, Gisselquist Technology, LLC 19 | ## {{{ 20 | ## This program is free software (firmware): you can redistribute it and/or 21 | ## modify it under the terms of the GNU General Public License as published 22 | ## by the Free Software Foundation, either version 3 of the License, or (at 23 | ## your option) any later version. 24 | ## 25 | ## This program is distributed in the hope that it will be useful, but WITHOUT 26 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 27 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28 | ## for more details. 29 | ## 30 | ## You should have received a copy of the GNU General Public License along 31 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 32 | ## target there if the PDF file isn't present.) If not, see 33 | ## for a copy. 34 | ## }}} 35 | ## License: GPL, v3, as defined and found on www.gnu.org, 36 | ## {{{ 37 | ## http://www.gnu.org/licenses/gpl.html 38 | ## 39 | ################################################################################ 40 | ## 41 | ## }}} 42 | TESTS := ufifo txuartlite rxuartlite txuart axiluart 43 | .PHONY: $(TESTS) 44 | all: $(TESTS) 45 | RTL := ../../rtl 46 | 47 | FIFO := ufifo 48 | TX := txuart 49 | TXLITE:= txuartlite 50 | RX := rxuartlite 51 | AXIL := axiluart 52 | 53 | ## Dependencies 54 | ## {{{ 55 | .PHONY: $(FIFO) $(TX) $(RX) $(TXLITE) 56 | $(FIFO): $(FIFO)_prf/PASS $(FIFO)_cvr/PASS 57 | $(TX): $(TX)/PASS 58 | $(RX): $(RX)_prf/PASS $(RX)_cvr/PASS 59 | $(TXLITE): $(TXLITE)_cvr/PASS $(TXLITE)_prf/PASS 60 | $(AXIL): $(AXIL)_cvr/PASS $(AXIL)_prf/PASS $(AXIL)_cvrs/PASS $(AXIL)_prfs/PASS 61 | ## }}} 62 | 63 | ## TX = txuart 64 | ## {{{ 65 | $(TX)/PASS: $(TX).sby $(RTL)/$(TX).v 66 | sby -f $(TX).sby 67 | ## }}} 68 | 69 | ## RX = rxuartlite 70 | ## {{{ 71 | $(RX)_prf/PASS: $(RX).sby $(RTL)/$(RX).v 72 | sby -f $(RX).sby prf 73 | $(RX)_cvr/PASS: $(RX).sby $(RTL)/$(RX).v 74 | sby -f $(RX).sby cvr 75 | ## }}} 76 | 77 | ## TXLITE = txuartlite 78 | ## {{{ 79 | $(TXLITE)_cvr/PASS: $(TXLITE).sby $(RTL)/$(TXLITE).v 80 | sby -f $(TXLITE).sby cvr 81 | $(TXLITE)_prf/PASS: $(TXLITE).sby $(RTL)/$(TXLITE).v 82 | sby -f $(TXLITE).sby prf 83 | ## }}} 84 | 85 | ## FIFO == ufifo 86 | ## {{{ 87 | $(FIFO)_prf/PASS: $(FIFO).sby $(RTL)/$(FIFO).v 88 | sby -f $(FIFO).sby prf 89 | $(FIFO)_cvr/PASS: $(FIFO).sby $(RTL)/$(FIFO).v 90 | sby -f $(FIFO).sby cvr 91 | ## }}} 92 | 93 | ## AXIL 94 | ## {{{ 95 | AXILDEPS := $(AXIL).sby $(RTL)/$(AXIL).v $(RTL)/$(FIFO).v $(RTL)/skidbuffer.v faxil_slave.v 96 | $(AXIL)_prf/PASS: $(AXILDEPS) 97 | sby -f $(AXIL).sby prf 98 | $(AXIL)_cvr/PASS: $(AXILDEPS) 99 | sby -f $(AXIL).sby cvr 100 | $(AXIL)_prfs/PASS: $(AXILDEPS) 101 | sby -f $(AXIL).sby prfs 102 | $(AXIL)_cvrs/PASS: $(AXILDEPS) 103 | sby -f $(AXIL).sby cvrs 104 | ## }}} 105 | 106 | .PHONY: report 107 | report: 108 | +perl genreport.pl > report.html 109 | ## Clean 110 | ## {{{ 111 | .PHONY: clean 112 | clean: 113 | rm -rf $(FIFO)_prf/ $(FIFO)_cvr/ 114 | rm -rf $(RX)_*/ $(TX)/ $(TXLITE)_cvr/ $(TXLITE)_prf/ 115 | rm -rf $(AXIL)_*/ 116 | ## }}} 117 | -------------------------------------------------------------------------------- /bench/formal/axiluart.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI 3 | [*] Tue Jun 9 12:45:44 2020 4 | [*] 5 | [dumpfile] "(null)" 6 | [timestart] 0 7 | [size] 1920 1021 8 | [pos] -1 -1 9 | *-3.760617 43 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 10 | [sst_width] 270 11 | [signals_width] 280 12 | [sst_expanded] 1 13 | [sst_vpaned_height] 290 14 | @28 15 | axiluart.S_AXI_ACLK 16 | axiluart.S_AXI_ARESETN 17 | @200 18 | - 19 | @28 20 | axiluart.S_AXI_AWVALID 21 | axiluart.S_AXI_AWREADY 22 | @22 23 | axiluart.S_AXI_AWADDR[3:0] 24 | @28 25 | axiluart.S_AXI_AWPROT[2:0] 26 | @200 27 | - 28 | @28 29 | axiluart.S_AXI_WVALID 30 | axiluart.S_AXI_WREADY 31 | @22 32 | axiluart.S_AXI_WDATA[31:0] 33 | axiluart.S_AXI_WSTRB[3:0] 34 | @28 35 | axiluart.S_AXI_BVALID 36 | @200 37 | - 38 | @28 39 | axiluart.S_AXI_BREADY 40 | axiluart.S_AXI_BRESP[1:0] 41 | @200 42 | - 43 | @29 44 | axiluart.S_AXI_ARVALID 45 | axiluart.S_AXI_ARREADY 46 | @23 47 | axiluart.S_AXI_ARADDR[3:0] 48 | @29 49 | axiluart.S_AXI_ARPROT[2:0] 50 | @201 51 | - 52 | @28 53 | axiluart.S_AXI_RVALID 54 | axiluart.S_AXI_RREADY 55 | @22 56 | axiluart.S_AXI_RDATA[31:0] 57 | @28 58 | axiluart.S_AXI_RRESP[1:0] 59 | @22 60 | axiluart.faxil_rd_outstanding[3:0] 61 | @28 62 | axiluart.r_preread 63 | axiluart.r_axil_addr[1:0] 64 | @22 65 | axiluart.uart_setup[30:0] 66 | [pattern_trace] 1 67 | [pattern_trace] 0 68 | -------------------------------------------------------------------------------- /bench/formal/axiluart.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | prfs prf opt_skidbuffer 4 | cvr 5 | cvrs cvr opt_skidbuffer 6 | 7 | [options] 8 | prf: mode prove 9 | prf: depth 5 10 | cvr: mode cover 11 | cvr: depth 32 12 | 13 | [engines] 14 | smtbmc 15 | 16 | [script] 17 | read -formal ufifo.v 18 | read -formal axiluart.v 19 | read -formal skidbuffer.v 20 | read -formal faxil_slave.v 21 | opt_skidbuffer: hierarchy -top axiluart -chparam OPT_SKIDBUFFER 1 22 | ~opt_skidbuffer: hierarchy -top axiluart -chparam OPT_SKIDBUFFER 0 23 | prep -top axiluart 24 | 25 | [files] 26 | ../../rtl/ufifo.v 27 | ../../rtl/skidbuffer.v 28 | ../../rtl/axiluart.v 29 | faxil_slave.v 30 | -------------------------------------------------------------------------------- /bench/formal/genreport.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | ################################################################################ 3 | ## 4 | ## Filename: genreport.pl 5 | ## {{{ 6 | ## Project: wbuart32, a full featured UART with simulator 7 | ## 8 | ## Purpose: Generates an HTML report documenting the success (or failure) 9 | ## of the various formal proofs contained in this repository. 10 | ## 11 | ## Creator: Dan Gisselquist, Ph.D. 12 | ## Gisselquist Technology, LLC 13 | ## 14 | ################################################################################ 15 | ## }}} 16 | ## Copyright (C) 2023-2024, Gisselquist Technology, LLC 17 | ## {{{ 18 | ## This program is free software (firmware): you can redistribute it and/or 19 | ## modify it under the terms of the GNU General Public License as published 20 | ## by the Free Software Foundation, either version 3 of the License, or (at 21 | ## your option) any later version. 22 | ## 23 | ## This program is distributed in the hope that it will be useful, but WITHOUT 24 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 25 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26 | ## for more details. 27 | ## 28 | ## You should have received a copy of the GNU General Public License along 29 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 30 | ## target there if the PDF file isn't present.) If not, see 31 | ## for a copy. 32 | ## }}} 33 | ## License: GPL, v3, as defined and found on www.gnu.org, 34 | ## {{{ 35 | ## http://www.gnu.org/licenses/gpl.html 36 | ## 37 | ################################################################################ 38 | ## 39 | ## }}} 40 | 41 | ## Variable declarations 42 | ## {{{ 43 | $dir = "."; 44 | @proofs = ( 45 | "axiluart", 46 | "rxuartlite", 47 | "txuartlite", 48 | # "rxuart", 49 | "txuart", 50 | "ufifo" 51 | ); 52 | 53 | %desc = ( 54 | "axiluart" => "AXI-Lite UART peripheral", 55 | "rxuartlite" => "UART Receiver, lite version", 56 | "txuartlite" => "UART Transmitter, lite version", 57 | "txuart" => "UART Transmitter, full featured", 58 | "ufifo" => "A synchronous FIFO supporting the UART" 59 | ); 60 | ## }}} 61 | 62 | ## getstatus subroutine 63 | ## {{{ 64 | # This subroutine runs make, to see if a proof is up to date, or otherwise 65 | # checks the logfile to see what the status was the last time the proof was 66 | # run. 67 | sub getstatus($) { 68 | my $based = shift; 69 | my $log = "$based/logfile.txt"; 70 | 71 | my $bmc = 0; 72 | my $ind = 0; 73 | my $cvr = 0; 74 | my $ncvr = 0; 75 | 76 | my $PASS = 0; 77 | my $FAIL = 0; 78 | my $UNK = 0; 79 | my $ERR = 0; 80 | my $terminated = 0; 81 | my $current = 1; 82 | 83 | # print "Checking make $based/PASS\n"; 84 | 85 | if (open(MAK, "make -n $based/PASS |")) { 86 | while($line = ) { 87 | if ($line =~ /sby/) { 88 | $current = 0; 89 | } 90 | } close(MAK); 91 | } 92 | 93 | # print "Opening log, $log\n"; 94 | 95 | open (LOG, "< $log") or return "No log"; 96 | while($line = ) { 97 | # print "LINE=$line\n"; 98 | if ($line =~ /DONE.*FAIL/) { 99 | $FAIL = 1; 100 | # print "FAIL match\n"; 101 | } if ($line =~ /DONE.*PASS/) { 102 | $PASS = 1; 103 | # print "PASS match\n"; 104 | } if ($line =~ /DONE.*UNKNOWN/) { 105 | $UNK = 1; 106 | # print "UNKNOWN match\n"; 107 | } if ($line =~ /DONE.*ERROR/) { 108 | $ERR = 1; 109 | # print "ERROR match\n"; 110 | } if ($line =~ /terminating process/) { 111 | $terminated = 1; 112 | } if ($line =~ /Checking cover/) { 113 | $cvr = 1; 114 | } if ($line =~ /engine_\d.induction/) { 115 | $ind = 1; 116 | # print "induction match\n"; 117 | } if ($line =~ /engine_\d.basecase.*Checking assertions in step\s+(\d+)/) { 118 | if ($1 > $bmc) { 119 | $bmc = $1; 120 | # print "basecase $bmc match\n"; 121 | } 122 | } if ($line =~ /engine_\d:.*Reached cover statement/) { 123 | $ncvr = $ncvr+1; 124 | } 125 | } 126 | close(LOG); 127 | 128 | if ($PASS) { 129 | if ($current == 0) { 130 | "Out of date"; 131 | } elsif ($cvr) { 132 | "Cover $ncvr"; 133 | } else { 134 | "PASS"; 135 | } 136 | } elsif ($FAIL) { 137 | "FAIL"; 138 | } elsif ($ERR) { 139 | "ERROR"; 140 | } elsif (($ind == 0 || $UNK != 0) && $bmc > 0) { 141 | "BMC $bmc"; 142 | } elsif ($terminated) { 143 | "Terminated"; 144 | } else { 145 | "Unknown"; 146 | } 147 | } 148 | ## }}} 149 | 150 | ## Start the HTML output 151 | ## {{{ 152 | ## Grab a timestamp 153 | $now = time; 154 | ($sc,$mn,$nhr,$ndy,$nmo,$nyr,$nwday,$nyday,$nisdst) = localtime($now); 155 | $nyr = $nyr+1900; $nmo = $nmo+1; 156 | $tstamp = sprintf("%04d%02d%02d",$nyr,$nmo,$ndy); 157 | 158 | print <<"EOM"; 159 | Formal Verification Report 160 | 161 |

Wishbone UART Verification Report

162 |

$tstamp

163 | 164 | 165 | EOM 166 | ## }}} 167 | 168 | ## Look up all directory entries 169 | ## {{{ 170 | # We'll use this result to look for subdirectories that might contain 171 | # log files. 172 | opendir(DIR, $dir) or die "Cannot open directory for reading"; 173 | my @dirent = readdir(DIR); 174 | closedir(DIR); 175 | 176 | # print "@dirent"; 177 | ## }}} 178 | 179 | # Lookup each components proof 180 | foreach $prf (sort @proofs) { 181 | my $ndirs=0; 182 | foreach $dent (@dirent) { 183 | next if (! -d $dent); 184 | next if ($dent =~ /^\./); 185 | next if ($dent !~ /^$prf(_\S+)/); 186 | $subprf = $1; 187 | 188 | $ndirs = $ndirs+1; 189 | } 190 | 191 | my $firstd = 1; 192 | 193 | # Find each subproof of the component 194 | foreach $dent (@dirent) { 195 | ## Filter out the wrong directories 196 | ## {{{ 197 | # print("\n"); 198 | # Only look at subdirectories 199 | next if (! -d $dent); 200 | next if ($dent =~ /^\./); 201 | next if ($dent !~ /^$prf(_\S+)/); 202 | $subprf = $1; 203 | # print("\n"); 204 | ## }}} 205 | 206 | ## Get the resulting status 207 | $st = getstatus($dent); 208 | # print("\n"); 209 | 210 | ## Fill out one entry of our table 211 | ## {{{ 212 | my $tail; 213 | if ($firstd) { 214 | print "\n"; 215 | $tail = "\n"; 216 | $firstd = 0; 217 | } else { 218 | $tail = "\n"; 219 | } 220 | if ($st =~ /PASS/) { 221 | print "\n"; 252 | } 253 | } 254 | 255 | ## Finish the HTML log file 256 | ## {{{ 257 | print <<"EOM"; 258 |
StatusComponentProofComponent description
DIR $dent
$dent matches $prf
STATUS = $st
$prf$subprf$desc{$prf}
$prf$subprf
Pass$tail"; 222 | } elsif ($st =~ /Cover\s+(\d+)/) { 223 | my $cvr = $1; 224 | if ($cvr < 1) { 225 | print "
$1 Cover points$tail"; 226 | } else { 227 | print "
$1 Cover points$tail"; 228 | } 229 | } elsif ($st =~ /FAIL/) { 230 | print "
FAIL$tail"; 231 | } elsif ($st =~ /Terminated/) { 232 | print "
Terminated$tail"; 233 | } elsif ($st =~ /ERROR/) { 234 | print "
ERROR$tail"; 235 | } elsif ($st =~ /Out of date/) { 236 | print "
Out of date$tail"; 237 | } elsif ($st =~ /BMC\s+(\d+)/) { 238 | my $bmc = $1; 239 | if ($bmc < 2) { 240 | print "
$bmc steps of BMC$tail"; 241 | } else { 242 | print "
$bmc steps of BMC$tail"; 243 | } 244 | } elsif ($st =~ /No log/) { 245 | print "
No log file found$tail"; 246 | } else { 247 | print "
Unknown$tail"; 248 | } 249 | ## }}} 250 | } if ($myfirstd != 0) { 251 | print "
Not found$prf $desc{$prf}
259 | 260 | EOM 261 | ## }}} 262 | -------------------------------------------------------------------------------- /bench/formal/report.html: -------------------------------------------------------------------------------- 1 | Formal Verification Report 2 | 3 |

Wishbone UART Verification Report

4 |

20240112

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
StatusComponentProofComponent description
Passaxiluart_prfAXI-Lite UART peripheral
6 Cover pointsaxiluart_cvr
Passaxiluart_prfs
6 Cover pointsaxiluart_cvrs
Passrxuartlite_prfUART Receiver, lite version
13 Cover pointsrxuartlite_cvr
1 Cover pointstxuartlite_cvrUART Transmitter, lite version
Passtxuartlite_prf
Passufifo_prfA synchronous FIFO supporting the UART
3 Cover pointsufifo_cvr
22 | 23 | -------------------------------------------------------------------------------- /bench/formal/rxuartlite.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | cvr 4 | 5 | [options] 6 | prf: mode prove 7 | cvr: mode cover 8 | multiclock on 9 | prf: depth 110 10 | cvr: depth 720 11 | 12 | [engines] 13 | smtbmc yices 14 | 15 | [script] 16 | prf: read -formal -DRXUARTLITE -D PHASE_TWO rxuartlite.v 17 | cvr: read -formal -DRXUARTLITE -D PHASE_TWO rxuartlite.v 18 | hierarchy -top rxuartlite -chparam CLOCKS_PER_BAUD 16 19 | prep -top rxuartlite 20 | # opt_merge -share_all 21 | 22 | [files] 23 | ../../rtl/rxuartlite.v 24 | -------------------------------------------------------------------------------- /bench/formal/txuart.sby: -------------------------------------------------------------------------------- 1 | [options] 2 | mode prove 3 | depth 10 4 | 5 | [engines] 6 | smtbmc boolector 7 | 8 | [script] 9 | read -formal -DTXUART txuart.v 10 | prep -top txuart 11 | 12 | [files] 13 | ../../rtl/txuart.v 14 | -------------------------------------------------------------------------------- /bench/formal/txuartlite.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | cvr 3 | prf 4 | 5 | [options] 6 | prf: mode prove 7 | cvr: mode cover 8 | depth 90 9 | 10 | [engines] 11 | smtbmc boolector 12 | 13 | [script] 14 | read -formal -DTXUARTLITE txuartlite.v 15 | proc -norom 16 | prep -top txuartlite 17 | 18 | [files] 19 | ../../rtl/txuartlite.v 20 | -------------------------------------------------------------------------------- /bench/formal/ufifo.sby: -------------------------------------------------------------------------------- 1 | [tasks] 2 | prf 3 | cvr 4 | 5 | [options] 6 | prf: mode prove 7 | prf: depth 4 8 | cvr: mode cover 9 | cvr: depth 32 10 | 11 | [engines] 12 | smtbmc 13 | 14 | [script] 15 | read -formal -D UFIFO ufifo.v 16 | prep -top ufifo 17 | 18 | [files] 19 | ../../rtl/ufifo.v 20 | -------------------------------------------------------------------------------- /bench/verilog/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: Makefile 4 | ## {{{ 5 | ## Project: wbuart32, a full featured UART with simulator 6 | ## 7 | ## Purpose: To direct the Verilator build of the Verilog portion of the 8 | ## bench test. The result is C++ code (built by Verilator), that 9 | ## is then built (herein) into a library. 10 | ## 11 | ## ALTERNATE_PURPOSE: 12 | ## All of the Verilog files within this directory may be made top level 13 | ## files in their own right for the purpose of testing the UART capability 14 | ## of your board. Should you wish to test these as toplevel files, you 15 | ## will need to remove the i_setup from the input, and set it to something 16 | ## like: 17 | ## wire [29:0] i_setup; 18 | ## 19 | ## // If we have a 100MHz clock, then we can set up for a 115,200 20 | ## // baud clock by setting i_setup to (100MHz / 115200) ~= 868. 21 | ## // The upper bits of this number also set the protocol to 22 | ## // one stop bit, no parity, and 8 data bits. 23 | ## assign i_setup = 30'd868; // 115,200 Baud 8N1 24 | ## 25 | ## Using this purpose, the UART ports of a new piece of hardware may be 26 | ## proven. To do this, 27 | ## 1. get BLINKY working first--to prove that the clock works like 28 | ## you think it does. Then, once BLINKY is running, 29 | ## 2. get helloworld working. This requires only the clock and 30 | ## the output UART pin to work. 31 | ## (Aside) 3. Once helloworld works, you should be able to get 32 | ## speechfifo to work with no further hassles. 33 | ## 4. After helloworld works, switch to getting linetest running on 34 | ## your hardware. This will prove that you have not only 35 | ## the clock and output UART pin working, but that you also 36 | ## have the input UART pin working as well. 37 | ## 38 | ## Targets: The default target of this makefile, all, builds the target 39 | ## test, which includes the linetest Verilator library, the 40 | ## helloworld Verilator library, and the speechfifo Verilator library--all 41 | ## necessary for bench testing using the C++ files in bench/cpp. 42 | ## 43 | ## Creator: Dan Gisselquist, Ph.D. 44 | ## Gisselquist Technology, LLC 45 | ## 46 | ################################################################################ 47 | ## }}} 48 | ## Copyright (C) 2015-2024, Gisselquist Technology, LLC 49 | ## {{{ 50 | ## This program is free software (firmware): you can redistribute it and/or 51 | ## modify it under the terms of the GNU General Public License as published 52 | ## by the Free Software Foundation, either version 3 of the License, or (at 53 | ## your option) any later version. 54 | ## 55 | ## This program is distributed in the hope that it will be useful, but WITHOUT 56 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 57 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 58 | ## for more details. 59 | ## 60 | ## You should have received a copy of the GNU General Public License along 61 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 62 | ## target there if the PDF file isn't present.) If not, see 63 | ## for a copy. 64 | ## 65 | ## License: GPL, v3, as defined and found on www.gnu.org, 66 | ## http://www.gnu.org/licenses/gpl.html 67 | ## 68 | ################################################################################ 69 | ## 70 | .PHONY: all 71 | .DELETE_ON_ERROR: 72 | ## }}} 73 | all: test 74 | ## {{{ 75 | YYMMDD=`date +%Y%m%d` 76 | CXX := g++ 77 | FBDIR := . 78 | VDIRFB:= $(FBDIR)/obj_dir 79 | RTLDR := ../../rtl 80 | VERILATOR := verilator 81 | VFLAGS := -Wall --MMD --trace -y $(RTLDR) -cc 82 | 83 | .PHONY: test testline testhello speechfifo 84 | ## }}} 85 | test: testline testlinelite testhello testhellolite speechfifo speechfifolite 86 | ## Dependencies 87 | ## {{{ 88 | testline: $(VDIRFB)/Vlinetest__ALL.a 89 | testlinelite: $(VDIRFB)/Vlinetestlite__ALL.a 90 | testhello: $(VDIRFB)/Vhelloworld__ALL.a 91 | testhellolite: $(VDIRFB)/Vhelloworldlite__ALL.a 92 | speechfifo: $(VDIRFB)/Vspeechfifo__ALL.a 93 | speechfifolite: $(VDIRFB)/Vspeechfifolite__ALL.a 94 | 95 | $(VDIRFB)/Vlinetest__ALL.a: $(VDIRFB)/Vlinetest.cpp 96 | $(VDIRFB)/Vlinetestlite__ALL.a: $(VDIRFB)/Vlinetestlite.cpp 97 | $(VDIRFB)/Vhelloworld__ALL.a: $(VDIRFB)/Vhelloworld.cpp 98 | $(VDIRFB)/Vhelloworldlite__ALL.a: $(VDIRFB)/Vhelloworldlite.cpp 99 | $(VDIRFB)/Vspeechfifo__ALL.a: $(VDIRFB)/Vspeechfifo.cpp 100 | $(VDIRFB)/Vspeechfifolite__ALL.a: $(VDIRFB)/Vspeechfifolite.cpp 101 | ## }}} 102 | 103 | ## Verilate build instructions 104 | ## {{{ 105 | $(VDIRFB)/V%.mk: $(VDIRFB)/V%.h 106 | $(VDIRFB)/V%.h: $(VDIRFB)/V%.cpp 107 | $(VDIRFB)/V%.cpp: $(FBDIR)/%.v 108 | $(VERILATOR) $(VFLAGS) $*.v 109 | 110 | $(VDIRFB)/Vlinetestlite.cpp: $(FBDIR)/linetest.v 111 | $(VERILATOR) $(VFLAGS) -DUSE_UART_LITE --prefix Vlinetestlite linetest.v 112 | $(VDIRFB)/Vhelloworldlite.cpp: $(FBDIR)/helloworld.v 113 | $(VERILATOR) $(VFLAGS) -DUSE_UART_LITE --prefix Vhelloworldlite helloworld.v 114 | $(VDIRFB)/Vspeechfifolite.cpp: $(FBDIR)/speechfifo.v 115 | $(VERILATOR) $(VFLAGS) -DUSE_UART_LITE --prefix Vspeechfifolite speechfifo.v 116 | ## }}} 117 | 118 | ## Turn C++ to libraries 119 | ## {{{ 120 | $(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.cpp 121 | cd $(VDIRFB); make -f V$*.mk 122 | ## }}} 123 | 124 | ## TAGS 125 | ## {{{ 126 | tags: $(wildcard *.v) $(wildcard $(RTLDR)/*.v) 127 | ctags *.v $(RTLDR)/*.v 128 | ## }}} 129 | 130 | ## Clean 131 | ## {{{ 132 | .PHONY: clean 133 | clean: 134 | rm -rf tags $(VDIRFB)/ 135 | ## }}} 136 | 137 | ## Automatic dependency handling 138 | ## {{{ 139 | DEPS := $(wildcard $(VDIRFB)/*.d) 140 | 141 | ifneq ($(MAKECMDGOALS),clean) 142 | ifneq ($(DEPS),) 143 | include $(DEPS) 144 | endif 145 | endif 146 | ## }}} 147 | -------------------------------------------------------------------------------- /bench/verilog/README.md: -------------------------------------------------------------------------------- 1 | This directory contains three basic configurations for testing your UART 2 | and proving that it works: 3 | - [helloworld](helloworld.v): Displays the familiar "Hello, World!" message over and over. Tests the transmit UART port. 4 | - [echotest](echotest.v): Echoes any characters received directly back to the transmit port. Two versions of this exist: one that processes characters and regenerates them, and another that just connects the input port to the output port. These are good tests to be applied if you already know your transmit UART works. If the transmitter works, then this will help to verify that your receiver works. It's one fault is that it tends to support single character UART tests, hence the test below. 5 | - [linetest](linetest.v): Reads a line of text, then parrots it back. Tests both receive and transmit UART. 6 | - [speechfifo](speechfifo.v): Recites the [Gettysburg address](../cpp/speech.txt) over and over again. This can be used to test the transmit UART port, and particularly to test receivers to see if they can receive 1400+ characters at full speed without any problems. 7 | 8 | Each of these configurations has a commented line defining OPT_STANDALONE within 9 | it. This option will automatically be defined if built within Verilator, 10 | allowing the Verilator simulation to set the serial port parameters. Otherwise, 11 | you should be able to run these files as direct top level design files. (You 12 | will probably want to adjust the baud clock divider if so, so that you can set 13 | to the baud rate you wish to generate as well as the clock rate you will be 14 | generating this from.) 15 | 16 | -------------------------------------------------------------------------------- /bench/verilog/echotest.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: echotest.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To test that the txuart and rxuart modules work properly, by 8 | // echoing the input directly to the output. 9 | // 10 | // This module may be run as either a DUMBECHO, simply forwarding the input 11 | // wire to the output with a touch of clock in between, or it can run as 12 | // a smarter echo routine that decodes text before returning it. The 13 | // difference depends upon whether or not OPT_DUMBECHO is defined, as 14 | // discussed below. 15 | // 16 | // With some modifications (discussed below), this RTL should be able to 17 | // run as a top-level testing file, requiring only the transmit and receive 18 | // UART pins and the clock to work. 19 | // 20 | // DON'T FORGET TO TURN OFF HARDWARE FLOW CONTROL! ... or this'll never 21 | // work. If you want to run with hardware flow control on, add another 22 | // wire to this module in order to set o_cts to 1'b1. 23 | // 24 | // 25 | // Creator: Dan Gisselquist, Ph.D. 26 | // Gisselquist Technology, LLC 27 | // 28 | //////////////////////////////////////////////////////////////////////////////// 29 | // }}} 30 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 31 | // {{{ 32 | // This program is free software (firmware): you can redistribute it and/or 33 | // modify it under the terms of the GNU General Public License as published 34 | // by the Free Software Foundation, either version 3 of the License, or (at 35 | // your option) any later version. 36 | // 37 | // This program is distributed in the hope that it will be useful, but WITHOUT 38 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 39 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 40 | // for more details. 41 | // 42 | // You should have received a copy of the GNU General Public License along 43 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 44 | // target there if the PDF file isn't present.) If not, see 45 | // for a copy. 46 | // 47 | // License: GPL, v3, as defined and found on www.gnu.org, 48 | // http://www.gnu.org/licenses/gpl.html 49 | // 50 | // 51 | //////////////////////////////////////////////////////////////////////////////// 52 | // 53 | // 54 | // Uncomment the next line defining OPT_DUMBECHO in order to test the wires 55 | // and external functionality of any UART, independent of the UART protocol. 56 | // }}} 57 | `define OPT_DUMBECHO 58 | // {{{ 59 | // 60 | // One issue with the design is how to set the values of the setup register. 61 | // (*This is a comment, not a verilator attribute ... ) Verilator needs to 62 | // know/set those values in order to work. However, this design can also be 63 | // used as a stand-alone top level configuration file. In this latter case, 64 | // the setup register needs to be set internal to the file. Here, we use 65 | // OPT_STANDALONE to distinguish between the two. If set, the file runs under 66 | // (* Another comment still ...) Verilator and we need to get i_setup from the 67 | // external environment. If not, it must be set internally. 68 | // }}} 69 | `ifndef VERILATOR 70 | `define OPT_STANDALONE 71 | `endif 72 | // {{{ 73 | // 74 | // Two versions of the UART can be found in the rtl directory: a full featured 75 | // UART, and a LITE UART that only handles 8N1 -- no break sending, break 76 | // detection, parity error detection, etc. If we set USE_LITE_UART here, those 77 | // simplified UART modules will be used. 78 | // }}} 79 | // `define USE_LITE_UART 80 | // 81 | // 82 | module echotest( 83 | // {{{ 84 | input i_clk, 85 | `ifndef OPT_STANDALONE 86 | input [30:0] i_setup, 87 | `endif 88 | input i_uart_rx, 89 | output wire o_uart_tx 90 | // }}} 91 | ); 92 | 93 | `ifdef OPT_DUMBECHO 94 | // {{{ 95 | reg r_uart_tx; 96 | 97 | initial r_uart_tx = 1'b1; 98 | always @(posedge i_clk) 99 | r_uart_tx <= i_uart_rx; 100 | assign o_uart_tx = r_uart_tx; 101 | // }}} 102 | `else 103 | // {{{ 104 | // This is the "smart" echo verion--one that decodes, and then 105 | // re-encodes, values over the UART. There is a risk, though, doing 106 | // things in this manner that the receive UART might run *just* a touch 107 | // faster than the transmitter, and hence drop a bit every now and 108 | // then. Hence, it works nicely for hand-testing, but not as nicely 109 | // for high-speed UART testing. 110 | 111 | 112 | // i_setup 113 | // {{{ 114 | // If i_setup isnt set up as an input parameter, it needs to be set. 115 | // We do so here, to a setting appropriate to create a 115200 Baud 116 | // comms system from a 100MHz clock. This also sets us to an 8-bit 117 | // data word, 1-stop bit, and no parity. 118 | // 119 | // This code only applies if OPT_DUMBECHO is not defined. 120 | `ifdef OPT_STANDALONE 121 | wire [30:0] i_setup; 122 | assign i_setup = 31'd868; // 115200 Baud, if clk @ 100MHz 123 | `endif 124 | // }}} 125 | 126 | // pwr_reset 127 | // {{{ 128 | // Create a reset line that will always be true on a power on reset 129 | reg pwr_reset; 130 | initial pwr_reset = 1'b1; 131 | always @(posedge i_clk) 132 | pwr_reset = 1'b0; 133 | // }}} 134 | 135 | // The UART Receiver 136 | // {{{ 137 | // This is where everything begins, by reading data from the UART. 138 | // 139 | // Data (rx_data) is present when rx_stb is true. Any parity or 140 | // frame errors will also be valid at that time. Finally, we'll ignore 141 | // errors, and even the clocked uart input distributed from here. 142 | // 143 | // This code only applies if OPT_DUMBECHO is not defined. 144 | wire rx_stb, rx_break, rx_perr, rx_ferr, rx_ignored; 145 | wire [7:0] rx_data; 146 | 147 | `ifdef USE_LITE_UART 148 | // 149 | // NOTE: this depends upon the Verilator implementation using a setup 150 | // of 868, since we cannot change the setup of the RXUARTLITE module. 151 | // 152 | rxuartlite #(24'd868) 153 | receiver(i_clk, i_uart_rx, rx_stb, rx_data); 154 | `else 155 | rxuart receiver(i_clk, pwr_reset, i_setup, i_uart_rx, rx_stb, rx_data, 156 | rx_break, rx_perr, rx_ferr, rx_ignored); 157 | `endif 158 | // }}} 159 | 160 | // The UART return transmitter 161 | // {{{ 162 | // Bypass any transmit hardware flow control. 163 | wire cts_n; 164 | assign cts_n = 1'b0; 165 | 166 | wire tx_busy; 167 | `ifdef USE_LITE_UART 168 | // 169 | // NOTE: this depends upon the Verilator implementation using a setup 170 | // of 868, since we cannot change the setup of the TXUARTLITE module. 171 | // 172 | txuartlite #(24'd868) 173 | transmitter(i_clk, rx_stb, rx_data, o_uart_tx, tx_busy); 174 | `else 175 | txuart transmitter(i_clk, pwr_reset, i_setup, rx_break, 176 | rx_stb, rx_data, rts, o_uart_tx, tx_busy); 177 | `endif 178 | // }}} 179 | // }}} 180 | `endif // OPT_DUMBECHO 181 | endmodule 182 | 183 | -------------------------------------------------------------------------------- /bench/verilog/helloworld.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: helloworld.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To create a *very* simple UART test program, which can be used 8 | // as the top level design file of any FPGA program. 9 | // 10 | // With some modifications (discussed below), this RTL should be able to 11 | // run as a top-level testing file, requiring only the UART and clock pin 12 | // to work. 13 | // 14 | // Creator: Dan Gisselquist, Ph.D. 15 | // Gisselquist Technology, LLC 16 | // 17 | //////////////////////////////////////////////////////////////////////////////// 18 | // }}} 19 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 20 | // {{{ 21 | // This program is free software (firmware): you can redistribute it and/or 22 | // modify it under the terms of the GNU General Public License as published 23 | // by the Free Software Foundation, either version 3 of the License, or (at 24 | // your option) any later version. 25 | // 26 | // This program is distributed in the hope that it will be useful, but WITHOUT 27 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 28 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 29 | // for more details. 30 | // 31 | // You should have received a copy of the GNU General Public License along 32 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 33 | // target there if the PDF file isn't present.) If not, see 34 | // for a copy. 35 | // 36 | // License: GPL, v3, as defined and found on www.gnu.org, 37 | // http://www.gnu.org/licenses/gpl.html 38 | // 39 | // 40 | //////////////////////////////////////////////////////////////////////////////// 41 | // 42 | // 43 | // One issue with the design is how to set the values of the setup register. 44 | // (*This is a comment, not a verilator attribute ... ) Verilator needs to 45 | // know/set those values in order to work. However, this design can also be 46 | // used as a stand-alone top level configuration file. In this latter case, 47 | // the setup register needs to be set internal to the file. Here, we use 48 | // OPT_STANDALONE to distinguish between the two. If set, the file runs under 49 | // (* Another comment still ...) Verilator and we need to get i_setup from the 50 | // external environment. If not, it must be set internally. 51 | // }}} 52 | `ifndef VERILATOR 53 | `define OPT_STANDALONE 54 | `endif 55 | // {{{ 56 | // 57 | // Two versions of the UART can be found in the rtl directory: a full featured 58 | // UART, and a LITE UART that only handles 8N1 -- no break sending, break 59 | // detection, parity error detection, etc. If we set USE_LITE_UART here, those 60 | // simplified UART modules will be used. 61 | // }}} 62 | // `define USE_LITE_UART 63 | // 64 | `default_nettype none 65 | // 66 | module helloworld #( 67 | // {{{ 68 | // Here we set i_setup to something appropriate to create a 69 | // 115200 Baud UART system from a 100MHz clock. This also sets 70 | // us to an 8-bit data word, 1-stop bit, and no parity. This 71 | // will be overwritten by i_setup, but at least it gives us 72 | // something to start with/from. 73 | // Verilator lint_off UNUSED 74 | parameter INITIAL_UART_SETUP = 31'd868 75 | // Verilator lint_on UNUSED 76 | // }}} 77 | ) ( 78 | // {{{ 79 | input wire i_clk, 80 | `ifndef OPT_STANDALONE 81 | input wire [30:0] i_setup, 82 | `endif 83 | output wire o_uart_tx 84 | // }}} 85 | ); 86 | 87 | // Signal declarations 88 | // {{{ 89 | reg [7:0] message [0:15]; 90 | reg pwr_reset; 91 | 92 | reg [27:0] counter; 93 | wire tx_break, tx_busy; 94 | reg tx_stb; 95 | reg [3:0] tx_index; 96 | reg [7:0] tx_data; 97 | 98 | wire cts_n; 99 | // }}} 100 | 101 | // i_setup 102 | // {{{ 103 | `ifdef OPT_STANDALONE 104 | // The i_setup wires are input when run under Verilator, but need to 105 | // be set internally if this is going to run as a standalone top level 106 | // test configuration. 107 | assign i_setup = INITIAL_UART_SETUP; 108 | `endif 109 | // }}} 110 | 111 | // pwr_reset 112 | // {{{ 113 | initial pwr_reset = 1'b1; 114 | always @(posedge i_clk) 115 | pwr_reset <= 1'b0; 116 | // }}} 117 | 118 | // Initialize the message 119 | // {{{ 120 | initial begin 121 | message[ 0] = "H"; 122 | message[ 1] = "e"; 123 | message[ 2] = "l"; 124 | message[ 3] = "l"; 125 | message[ 4] = "o"; 126 | message[ 5] = ","; 127 | message[ 6] = " "; 128 | message[ 7] = "W"; 129 | message[ 8] = "o"; 130 | message[ 9] = "r"; 131 | message[10] = "l"; 132 | message[11] = "d"; 133 | message[12] = "!"; 134 | message[13] = " "; 135 | message[14] = "\r"; 136 | message[15] = "\n"; 137 | end 138 | // }}} 139 | 140 | // Send a Hello World message to the transmitter 141 | // {{{ 142 | initial counter = 28'hffffff0; 143 | always @(posedge i_clk) 144 | counter <= counter + 1'b1; 145 | 146 | assign tx_break = 1'b0; 147 | 148 | initial tx_index = 4'h0; 149 | always @(posedge i_clk) 150 | if ((tx_stb)&&(!tx_busy)) 151 | tx_index <= tx_index + 1'b1; 152 | 153 | always @(posedge i_clk) 154 | tx_data <= message[tx_index]; 155 | 156 | initial tx_stb = 1'b0; 157 | always @(posedge i_clk) 158 | if (&counter) 159 | tx_stb <= 1'b1; 160 | else if ((tx_stb)&&(!tx_busy)&&(tx_index==4'hf)) 161 | tx_stb <= 1'b0; 162 | // }}} 163 | 164 | // The UART transmitter 165 | // {{{ 166 | // Bypass any hardware flow control 167 | assign cts_n = 1'b0; 168 | 169 | `ifdef USE_LITE_UART 170 | txuartlite 171 | #(24'd868) 172 | transmitter(i_clk, tx_stb, tx_data, o_uart_tx, tx_busy); 173 | `else 174 | txuart transmitter(i_clk, pwr_reset, i_setup, tx_break, 175 | tx_stb, tx_data, cts_n, o_uart_tx, tx_busy); 176 | `endif 177 | // }}} 178 | endmodule 179 | -------------------------------------------------------------------------------- /bench/verilog/linetest.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: linetest.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To test that the txuart and rxuart modules work properly, by 8 | // buffering one line's worth of input, and then piping that line 9 | // to the transmitter while (possibly) receiving a new line. 10 | // 11 | // With some modifications (discussed below), this RTL should be able to 12 | // run as a top-level testing file, requiring only the transmit and receive 13 | // UART pins and the clock to work. 14 | // 15 | // Creator: Dan Gisselquist, Ph.D. 16 | // Gisselquist Technology, LLC 17 | // 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // }}} 20 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 21 | // {{{ 22 | // This program is free software (firmware): you can redistribute it and/or 23 | // modify it under the terms of the GNU General Public License as published 24 | // by the Free Software Foundation, either version 3 of the License, or (at 25 | // your option) any later version. 26 | // 27 | // This program is distributed in the hope that it will be useful, but WITHOUT 28 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 29 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 30 | // for more details. 31 | // 32 | // You should have received a copy of the GNU General Public License along 33 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 34 | // target there if the PDF file isn't present.) If not, see 35 | // for a copy. 36 | // }}} 37 | // License: GPL, v3, as defined and found on www.gnu.org, 38 | // {{{ 39 | // http://www.gnu.org/licenses/gpl.html 40 | // 41 | //////////////////////////////////////////////////////////////////////////////// 42 | // 43 | // 44 | // One issue with the design is how to set the values of the setup register. 45 | // (*This is a comment, not a verilator attribute ... ) Verilator needs to 46 | // know/set those values in order to work. However, this design can also be 47 | // used as a stand-alone top level configuration file. In this latter case, 48 | // the setup register needs to be set internal to the file. Here, we use 49 | // OPT_STANDALONE to distinguish between the two. If set, the file runs under 50 | // (* Another comment still ...) Verilator and we need to get i_setup from the 51 | // external environment. If not, it must be set internally. 52 | // }}} 53 | `ifndef VERILATOR 54 | `define OPT_STANDALONE 55 | `endif 56 | // {{{ 57 | // 58 | // Two versions of the UART can be found in the rtl directory: a full featured 59 | // UART, and a LITE UART that only handles 8N1 -- no break sending, break 60 | // detection, parity error detection, etc. If we set USE_LITE_UART here, those 61 | // simplified UART modules will be used. 62 | // }}} 63 | // `define USE_LITE_UART 64 | // 65 | `default_nettype none 66 | // 67 | module linetest( 68 | // {{{ 69 | input wire i_clk, 70 | `ifndef OPT_STANDALONE 71 | input wire [30:0] i_setup, 72 | `endif 73 | input i_uart_rx, 74 | output wire o_uart_tx 75 | // }}} 76 | ); 77 | 78 | // Signal declarations 79 | // {{{ 80 | reg [7:0] buffer [0:255]; 81 | reg [7:0] head, tail; 82 | reg pwr_reset; 83 | wire rx_stb, rx_break, rx_perr, rx_ferr; 84 | /* verilator lint_off UNUSED */ 85 | wire rx_ignored; 86 | /* verilator lint_on UNUSED */ 87 | wire [7:0] rx_data; 88 | wire [7:0] nxt_head; 89 | wire [7:0] nused; 90 | reg [7:0] lineend; 91 | reg run_tx; 92 | wire tx_break, tx_busy; 93 | reg [7:0] tx_data; 94 | reg tx_stb; 95 | wire cts_n; 96 | // }}} 97 | 98 | // i_setup 99 | // {{{ 100 | // If i_setup isnt set up as an input parameter, it needs to be set. 101 | // We do so here, to a setting appropriate to create a 115200 Baud 102 | // comms system from a 100MHz clock. This also sets us to an 8-bit 103 | // data word, 1-stop bit, and no parity. 104 | `ifdef OPT_STANDALONE 105 | wire [30:0] i_setup; 106 | assign i_setup = 31'd868; // 115200 Baud, if clk @ 100MHz 107 | `endif 108 | // }}} 109 | 110 | // pwr_reset 111 | // {{{ 112 | // Create a reset line that will always be true on a power on reset 113 | initial pwr_reset = 1'b1; 114 | always @(posedge i_clk) 115 | pwr_reset <= 1'b0; 116 | // }}} 117 | 118 | // The UART Receiver 119 | // {{{ 120 | // This is where everything begins, by reading data from the UART. 121 | // 122 | // Data (rx_data) is present when rx_stb is true. Any parity or 123 | // frame errors will also be valid at that time. Finally, we'll ignore 124 | // errors, and even the clocked uart input distributed from here. 125 | `ifdef USE_LITE_UART 126 | rxuartlite #(24'd868) 127 | receiver(i_clk, i_uart_rx, rx_stb, rx_data); 128 | `else 129 | rxuart receiver(i_clk, pwr_reset, i_setup, i_uart_rx, rx_stb, rx_data, 130 | rx_break, rx_perr, rx_ferr, rx_ignored); 131 | `endif 132 | // }}} 133 | 134 | // nxt_head, and write to the buffer 135 | // {{{ 136 | // The next step in this process is to dump everything we read into a 137 | // FIFO. First step: writing into the FIFO. Always write into FIFO 138 | // memory. (The next step will step the memory address if rx_stb was 139 | // true ...) 140 | assign nxt_head = head + 8'h01; 141 | always @(posedge i_clk) 142 | buffer[head] <= rx_data; 143 | // }}} 144 | 145 | // head 146 | // {{{ 147 | // Select where in our FIFO memory to write. On reset, we clear the 148 | // memory. In all other cases/respects, we step the memory forward. 149 | // 150 | // However ... we won't step it forward IF ... 151 | // rx_break - we are in a BREAK condition on the line 152 | // (i.e. ... it's disconnected) 153 | // rx_perr - We've seen a parity error 154 | // rx_ferr - Same thing for a frame error 155 | // nxt_head != tail - If the FIFO is already full, we'll just drop 156 | // this new value, rather than dumping random garbage 157 | // from the FIFO until we go round again ... i.e., we 158 | // don't write on potential overflow. 159 | // 160 | // Adjusting this address will make certain that the next write to the 161 | // FIFO goes to the next address--since we've already written the FIFO 162 | // memory at this address. 163 | initial head= 8'h00; 164 | always @(posedge i_clk) 165 | if (pwr_reset) 166 | head <= 8'h00; 167 | else if ((rx_stb)&&(!rx_break)&&(!rx_perr)&&(!rx_ferr)&&(nxt_head != tail)) 168 | head <= nxt_head; 169 | // }}} 170 | 171 | // How much of the FIFO is in use? head - tail. What if they wrap 172 | // around? Still: head-tail, but this time truncated to the number of 173 | // bits of interest. It can never be negative ... so ... we're good, 174 | // this just measures that number. 175 | assign nused = head-tail; 176 | 177 | // run_tx, lineend 178 | // {{{ 179 | // Here's the guts of the algorithm--setting run_tx. Once set, the 180 | // buffer will flush. Here, we set it on one of two conditions: 1) 181 | // a newline is received, or 2) the line is now longer than 80 182 | // characters. 183 | // 184 | // Once the line has ben transmitted (separate from emptying the buffer) 185 | // we stop transmitting. 186 | initial run_tx = 0; 187 | initial lineend = 0; 188 | always @(posedge i_clk) 189 | if (pwr_reset) 190 | begin 191 | run_tx <= 1'b0; 192 | lineend <= 8'h00; 193 | end else if(((rx_data == 8'h0a)||(rx_data == 8'hd))&&(rx_stb)) 194 | begin 195 | // Start transmitting once we get to either a newline 196 | // or a carriage return character 197 | lineend <= head+8'h1; 198 | run_tx <= 1'b1; 199 | end else if ((!run_tx)&&(nused>8'd80)) 200 | begin 201 | // Start transmitting once we get to 80 chars 202 | lineend <= head; 203 | run_tx <= 1'b1; 204 | end else if (tail == lineend) 205 | // Line buffer has been emptied 206 | run_tx <= 1'b0; 207 | // }}} 208 | 209 | // UART transmitter 210 | // {{{ 211 | // Now ... let's deal with the transmitter 212 | assign tx_break = 1'b0; 213 | 214 | // When do we wish to transmit? 215 | // 216 | // Any time run_tx is true--but we'll give it an extra clock. 217 | initial tx_stb = 1'b0; 218 | always @(posedge i_clk) 219 | tx_stb <= run_tx; 220 | 221 | // We'll transmit the data from our FIFO from ... wherever our tail 222 | // is pointed. 223 | always @(posedge i_clk) 224 | tx_data <= buffer[tail]; 225 | 226 | // We increment the pointer to where we read from any time 1) we are 227 | // requesting to transmit a character, and 2) the transmitter was not 228 | // busy and thus accepted our request. At that time, increment the 229 | // pointer, and we'll be ready for another round. 230 | initial tail = 8'h00; 231 | always @(posedge i_clk) 232 | if(pwr_reset) 233 | tail <= 8'h00; 234 | else if ((tx_stb)&&(!tx_busy)) 235 | tail <= tail + 8'h01; 236 | 237 | // Bypass any hardwaare flow control 238 | assign cts_n = 1'b0; 239 | 240 | `ifdef USE_LITE_UART 241 | txuartlite #(24'd868) 242 | transmitter(i_clk, tx_stb, tx_data, o_uart_tx, tx_busy); 243 | `else 244 | txuart transmitter(i_clk, pwr_reset, i_setup, tx_break, 245 | tx_stb, tx_data, cts_n, o_uart_tx, tx_busy); 246 | `endif 247 | // }}} 248 | endmodule 249 | -------------------------------------------------------------------------------- /bench/verilog/speechfifo.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: speechfifo.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: To test/demonstrate/prove the wishbone access to the FIFO'd 8 | // UART via sending more information than the FIFO can hold, 9 | // and then verifying that this was the value received. 10 | // 11 | // To do this, we "borrow" a copy of Abraham Lincolns Gettysburg address, 12 | // make that the FIFO isn't large enough to hold it, and then try 13 | // to send this address every couple of minutes. 14 | // 15 | // With some minor modifications (discussed below), this RTL should be 16 | // able to be run as a top-level testing file, requiring only that the 17 | // clock and the transmit UART pins be working. 18 | // 19 | // Creator: Dan Gisselquist, Ph.D. 20 | // Gisselquist Technology, LLC 21 | // 22 | //////////////////////////////////////////////////////////////////////////////// 23 | // }}} 24 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 25 | // {{{ 26 | // This program is free software (firmware): you can redistribute it and/or 27 | // modify it under the terms of the GNU General Public License as published 28 | // by the Free Software Foundation, either version 3 of the License, or (at 29 | // your option) any later version. 30 | // 31 | // This program is distributed in the hope that it will be useful, but WITHOUT 32 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 33 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 34 | // for more details. 35 | // 36 | // You should have received a copy of the GNU General Public License along 37 | // with this program. (It's in the $(ROOT)/doc directory, run make with no 38 | // target there if the PDF file isn't present.) If not, see 39 | // for a copy. 40 | // 41 | // License: GPL, v3, as defined and found on www.gnu.org, 42 | // http://www.gnu.org/licenses/gpl.html 43 | // 44 | // 45 | //////////////////////////////////////////////////////////////////////////////// 46 | // 47 | // 48 | // One issue with the design is how to set the values of the setup register. 49 | // (*This is a comment, not a verilator attribute ... ) Verilator needs to 50 | // know/set those values in order to work. However, this design can also be 51 | // used as a stand-alone top level configuration file. In this latter case, 52 | // the setup register needs to be set internal to the file. Here, we use 53 | // OPT_STANDALONE to distinguish between the two. If set, the file runs under 54 | // (* Another comment still ...) Verilator and we need to get i_setup from the 55 | // external environment. If not, it must be set internally. 56 | // 57 | `ifndef VERILATOR 58 | `define OPT_STANDALONE 59 | `endif 60 | // }}} 61 | module speechfifo #( 62 | // {{{ 63 | // Here we set i_setup to something appropriate to create a 64 | // 115200 Baud UART system from a 100MHz clock. This also sets 65 | // us to an 8-bit data word, 1-stop bit, and no parity (for the 66 | // non-LITE UART). This will be overwritten by i_setup (if 67 | // present), but at least it gives us something to start 68 | // with/from. 69 | parameter INITIAL_UART_SETUP = 31'd868, 70 | 71 | // Let's set our message length, in case we ever wish to change 72 | // it in the future 73 | localparam MSGLEN=2203 74 | // }}} 75 | ) ( 76 | // {{{ 77 | input wire i_clk, 78 | `ifndef OPT_STANDALONE 79 | input wire [30:0] i_setup, 80 | `endif 81 | output wire o_uart_tx 82 | // }}} 83 | ); 84 | 85 | // Signal declarations 86 | // {{{ 87 | reg restart; 88 | reg wb_stb; 89 | reg [1:0] wb_addr; 90 | reg [31:0] wb_data; 91 | 92 | wire uart_stall; 93 | 94 | // We aren't using the receive interrupts, or the received data, or the 95 | // ready to send line, so we'll just mark them all here as ignored. 96 | 97 | /* verilator lint_off UNUSED */ 98 | wire uart_ack, tx_int; 99 | wire [31:0] uart_data; 100 | wire ignored_rx_int, ignored_rxfifo_int; 101 | wire rts_n_ignored; 102 | /* verilator lint_on UNUSED */ 103 | 104 | reg pwr_reset; 105 | reg [7:0] message [0:4095]; 106 | reg [30:0] restart_counter; 107 | reg [11:0] msg_index; 108 | reg end_of_message; 109 | 110 | wire cts_n; 111 | wire txfifo_int; 112 | // }}} 113 | 114 | // i_setup 115 | // {{{ 116 | // The i_setup wires are input when run under Verilator, but need to 117 | // be set internally if this is going to run as a standalone top level 118 | // test configuration. 119 | `ifdef OPT_STANDALONE 120 | wire [30:0] i_setup; 121 | assign i_setup = INITIAL_UART_SETUP; 122 | `endif 123 | // }}} 124 | 125 | // pwr_reset 126 | // {{{ 127 | // The next four lines create a strobe signal that is true on the first 128 | // clock, but never after. This makes for a decent power-on reset 129 | // signal. 130 | initial pwr_reset = 1'b1; 131 | always @(posedge i_clk) 132 | pwr_reset <= 1'b0; 133 | // }}} 134 | 135 | // initializing the memory 136 | // {{{ 137 | // The message we wish to transmit is kept in "message". It needs to be 138 | // set initially. Do so here. 139 | // 140 | // Since the message has fewer than 2048 elements in it, we preset every 141 | // element to a space so that if (for some reason) we broadcast past the 142 | // end of our message, we'll at least be sending something useful. 143 | integer i; 144 | initial begin 145 | // xx Verilator needs this file to be in the directory the file 146 | // is run from. For that reason, the project builds, makes, 147 | // and keeps speech.hex in bench/cpp. 148 | // 149 | // Vivado, however, wants speech.hex to be in a project file 150 | // directory, such as bench/verilog. For that reason, the 151 | // build function in bench/cpp also copies speech.hex to the 152 | // bench/verilog directory. You may need to make certain the 153 | // file is both built, and copied into a directory where your 154 | // synthesis tool can find it. 155 | // 156 | $readmemh("speech.hex", message); 157 | for(i=MSGLEN; i<4095; i=i+1) 158 | message[i] = 8'h20; 159 | 160 | // 161 | // The problem with the above approach is Xilinx's ISE program. 162 | // It's broken. It can't handle HEX files well (at all?) and 163 | // has more problems with HEX's defining ROM's. For that 164 | // reason, the mkspeech program can be tuned to create an 165 | // include file, speech.inc. We include that program here. 166 | // It is rather ugly, though, and not a very elegant solution, 167 | // since it walks through every value in our speech, byte by 168 | // byte, with an initial line for each byte declaring what it 169 | // is to be. 170 | // 171 | // If you (need to) use this route, comment out both the 172 | // readmemh, the for loop, and the message[i] = 8'h20 lines 173 | // above and uncomment the include line below. 174 | // 175 | // `include "speech.inc" 176 | end 177 | // }}} 178 | 179 | // restart_counter 180 | // {{{ 181 | // Let's keep track of time, and send our message over and over again. 182 | // To do this, we'll keep track of a restart counter. When this counter 183 | // rolls over, we restart our message. 184 | // 185 | // Since we want to start our message just a couple clocks after power 186 | // up, we'll set the reset counter just a couple clocks shy of a roll 187 | // over. 188 | initial restart_counter = -31'd16; 189 | always @(posedge i_clk) 190 | restart_counter <= restart_counter+1'b1; 191 | // }}} 192 | 193 | // restart 194 | // {{{ 195 | // Ok, now that we have a counter that tells us when to start over, 196 | // let's build a set of signals that we can use to get things started 197 | // again. This will be the restart signal. On this signal, we just 198 | // restart everything. 199 | initial restart = 0; 200 | always @(posedge i_clk) 201 | restart <= (restart_counter == 0); 202 | // }}} 203 | 204 | // msg_index 205 | // {{{ 206 | // Our message index. This is the address of the character we wish to 207 | // transmit next. Note, there's a clock delay between setting this 208 | // index and when the wb_data is valid. Hence, we set the index on 209 | // restart[0] to zero. 210 | initial msg_index = 12'h000 - 12'h8; 211 | always @(posedge i_clk) 212 | if (restart) 213 | msg_index <= 0; 214 | else if ((wb_stb)&&(!uart_stall)) 215 | // We only advance the index if a port operation on the 216 | // wbuart has taken place. That's what the 217 | // (wb_stb)&&(!uart_stall) is about. (wb_stb) is the 218 | // request for a transaction on the bus, uart_stall 219 | // tells us to wait 'cause the peripheral isn't ready. 220 | // In our case, it's always ready, uart_stall == 0, but 221 | // we keep/maintain this logic for good form. 222 | // 223 | // Note also, we only advance when restart[0] is zero. 224 | // This keeps us from advancing prior to the setup 225 | // word. 226 | msg_index <= msg_index + 1'b1; 227 | // }}} 228 | 229 | // wb_data -- What data will we be sending to the port? 230 | // {{{ 231 | always @(posedge i_clk) 232 | if (restart) 233 | // The first thing we do is set the baud rate, and 234 | // serial port configuration parameters. Ideally, 235 | // we'd only set this once. But rather than complicate 236 | // the logic, we set it everytime we start over. 237 | wb_data <= { 1'b0, i_setup }; 238 | else if ((wb_stb)&&(!uart_stall)) 239 | // Then, if the last thing was received over the bus, 240 | // we move to the next data item. 241 | wb_data <= { 24'h00, message[msg_index] }; 242 | // }}} 243 | 244 | // wb_addr 245 | // {{{ 246 | // We send our first value to the SETUP address (all zeros), all other 247 | // values we send to the transmitters address. We should really be 248 | // double checking that stall remains low, but its not required here. 249 | always @(posedge i_clk) 250 | if (restart) 251 | wb_addr <= 2'b00; 252 | else // if (!uart_stall)?? 253 | wb_addr <= 2'b11; 254 | // }}} 255 | 256 | // end_of_message 257 | // {{{ 258 | // Knowing when to stop sending the speech is important, but depends 259 | // upon an 11 bit comparison. Since FPGA logic is best measured by the 260 | // number of inputs to an always block, we pull those 11-bits out of 261 | // the always block for wb_stb, and place them here on the clock prior. 262 | // If end_of_message is true, then we need to stop transmitting, and 263 | // wait for the next (restart) to get us started again. We set that 264 | // flag hee. 265 | initial end_of_message = 1'b1; 266 | always @(posedge i_clk) 267 | if (restart) 268 | end_of_message <= 1'b0; 269 | else 270 | end_of_message <= (msg_index >= MSGLEN); 271 | // }}} 272 | 273 | // wb_stb 274 | // {{{ 275 | // The wb_stb signal indicates that we wish to write, using the wishbone 276 | // to our peripheral. We have two separate types of writes. First, 277 | // we wish to write our setup. Then we want to drop STB and write 278 | // our data. Once we've filled half of the FIFO, we wait for the FIFO 279 | // to empty before issuing a STB again and then fill up half the FIFO 280 | // again. 281 | initial wb_stb = 1'b0; 282 | always @(posedge i_clk) 283 | if (restart) 284 | // Start sending to the UART on a reset. The first 285 | // thing we'll send will be the configuration, but 286 | // that's done elsewhere. This just starts up the 287 | // writes to the peripheral wbuart. 288 | wb_stb <= 1'b1; 289 | else if (end_of_message) 290 | // Stop transmitting when we get to the end of our 291 | // message. 292 | wb_stb <= 1'b0; 293 | else if (txfifo_int) 294 | // If the FIFO is less than half full, then write to 295 | // it. 296 | wb_stb <= 1'b1; 297 | else 298 | // But once the FIFO gets to half full, stop. 299 | wb_stb <= 1'b0; 300 | // }}} 301 | 302 | // cts_n 303 | // {{{ 304 | // The WBUART can handle hardware flow control signals. This test, 305 | // however, cannot. The reason? Simply just to keep things simple. 306 | // If you want to add hardware flow control to your design, simply 307 | // make rts an input to this module. 308 | // 309 | // Since this is an output only module demonstrator, what would be the 310 | // cts output is unused. 311 | assign cts_n = 1'b0; 312 | // }}} 313 | 314 | // Finally--the unit under test--now that we've set up all the wires 315 | // to run/test it. 316 | wbuart #(INITIAL_UART_SETUP) 317 | wbuarti(i_clk, pwr_reset, 318 | wb_stb, wb_stb, 1'b1, wb_addr, wb_data, 4'hf, 319 | uart_stall, uart_ack, uart_data, 320 | 1'b1, o_uart_tx, cts_n, rts_n_ignored, 321 | ignored_rx_int, tx_int, 322 | ignored_rxfifo_int, txfifo_int); 323 | 324 | endmodule 325 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: Makefile 4 | ## {{{ 5 | ## Project: wbuart32, a full featured UART with simulator 6 | ## 7 | ## Purpose: To coordinate the build of documentation PDFs from their 8 | ## LaTeX sources. 9 | ## 10 | ## Targets include: 11 | ## all Builds all documents 12 | ## 13 | ## gpl-3.0.pdf Builds the GPL license these files are released 14 | ## under. 15 | ## 16 | ## spec.pdf Builds the specification for the SDSPI 17 | ## controller. 18 | ## 19 | ## Creator: Dan Gisselquist, Ph.D. 20 | ## Gisselquist Technology, LLC 21 | ## 22 | ################################################################################ 23 | ## }}} 24 | ## Copyright (C) 2015-2022, Gisselquist Technology, LLC 25 | ## {{{ 26 | ## This program is free software (firmware): you can redistribute it and/or 27 | ## modify it under the terms of the GNU General Public License as published 28 | ## by the Free Software Foundation, either version 3 of the License, or (at 29 | ## your option) any later version. 30 | ## 31 | ## This program is distributed in the hope that it will be useful, but WITHOUT 32 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 33 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 34 | ## for more details. 35 | ## 36 | ## You should have received a copy of the GNU General Public License along 37 | ## with this program. (It's in the $(ROOT)/doc directory, run make with no 38 | ## target there if the PDF file isn't present.) If not, see 39 | ## for a copy. 40 | ## 41 | ## License: GPL, v3, as defined and found on www.gnu.org, 42 | ## }}} 43 | ## http://www.gnu.org/licenses/gpl.html 44 | ## {{{ 45 | ## 46 | ## 47 | ################################################################################ 48 | ## 49 | ## }}} 50 | all: gpl spec 51 | pdf: gpl spec 52 | DSRC := src 53 | 54 | .PHONY: gpl 55 | ## {{{ 56 | gpl: gpl-3.0.pdf 57 | 58 | gpl-3.0.pdf: $(DSRC)/gpl-3.0.tex 59 | latex $(DSRC)/gpl-3.0.tex 60 | latex $(DSRC)/gpl-3.0.tex 61 | dvips -q -z -t letter -P pdf -o gpl-3.0.ps gpl-3.0.dvi 62 | ps2pdf -dAutoRotatePages=/All gpl-3.0.ps gpl-3.0.pdf 63 | rm gpl-3.0.dvi gpl-3.0.log gpl-3.0.aux gpl-3.0.ps 64 | ## }}} 65 | 66 | .PHONY: spec 67 | ## {{{ 68 | spec: spec.pdf 69 | 70 | spec.pdf: $(DSRC)/spec.tex $(DSRC)/gqtekspec.cls $(DSRC)/GT.eps 71 | cd $(DSRC)/; latex spec.tex 72 | cd $(DSRC)/; latex spec.tex 73 | cd $(DSRC)/; dvips -q -z -t letter -P pdf -o ../spec.ps spec.dvi 74 | ps2pdf -dAutoRotatePages=/All spec.ps spec.pdf 75 | -grep -i warning $(DSRC)/spec.log 76 | @rm -f $(DSRC)/spec.dvi $(DSRC)/spec.log 77 | @rm -f $(DSRC)/spec.aux $(DSRC)/spec.toc 78 | @rm -f $(DSRC)/spec.lot $(DSRC)/spec.lof 79 | @rm -f $(DSRC)/spec.out spec.ps 80 | ## }}} 81 | 82 | .PHONY: clean 83 | ## {{{ 84 | clean: 85 | rm -f $(DSRC)/spec.dvi $(DSRC)/spec.log 86 | rm -f $(DSRC)/spec.aux $(DSRC)/spec.toc 87 | rm -f $(DSRC)/spec.lot $(DSRC)/spec.lof 88 | rm -f $(DSRC)/spec.out spec.ps spec.pdf 89 | rm -f gpl-3.0.pdf 90 | ## }}} 91 | -------------------------------------------------------------------------------- /doc/gfx/ambiguous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/wbuart32/f43a6b83c3a70fb2ac0696a45c5545b233fb860b/doc/gfx/ambiguous.png -------------------------------------------------------------------------------- /doc/gfx/logic-timing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/wbuart32/f43a6b83c3a70fb2ac0696a45c5545b233fb860b/doc/gfx/logic-timing.png -------------------------------------------------------------------------------- /doc/gpl-3.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/wbuart32/f43a6b83c3a70fb2ac0696a45c5545b233fb860b/doc/gpl-3.0.pdf -------------------------------------------------------------------------------- /doc/spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/wbuart32/f43a6b83c3a70fb2ac0696a45c5545b233fb860b/doc/spec.pdf -------------------------------------------------------------------------------- /doc/src/GT.eps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 EPSF-3.0 2 | %%BoundingBox: 0 0 504 288 3 | %%Creator: Gisselquist Technology LLC 4 | %%Title: Gisselquist Technology Logo 5 | %%CreationDate: 11 Mar 2014 6 | %%EndComments 7 | %%BeginProlog 8 | /black { 0 setgray } def 9 | /white { 1 setgray } def 10 | /height { 288 } def 11 | /lw { height 8 div } def 12 | %%EndProlog 13 | % %%Page: 1 14 | 15 | false { % A bounding box 16 | 0 setlinewidth 17 | newpath 18 | 0 0 moveto 19 | 0 height lineto 20 | 1.625 height mul lw add 0 rlineto 21 | 0 height neg rlineto 22 | closepath stroke 23 | } if 24 | 25 | true { % The "G" 26 | newpath 27 | height 2 div 1.25 mul height moveto 28 | height 2 div height 4 div sub height lineto 29 | 0 height 3 4 div mul lineto 30 | 0 height 4 div lineto 31 | height 4 div 0 lineto 32 | height 3 4 div mul 0 lineto 33 | height height 4 div lineto 34 | height height 2 div lineto 35 | % 36 | height lw sub height 2 div lineto 37 | height lw sub height 4 div lw 2 div add lineto 38 | height 3 4 div mul lw 2 div sub lw lineto 39 | height 4 div lw 2 div add lw lineto 40 | lw height 4 div lw 2 div add lineto 41 | lw height 3 4 div mul lw 2 div sub lineto 42 | height 4 div lw 2 div add height lw sub lineto 43 | height 2 div 1.25 mul height lw sub lineto 44 | closepath fill 45 | newpath 46 | height 2 div height 2 div moveto 47 | height 2 div 0 rlineto 48 | 0 height 2 div neg rlineto 49 | lw neg 0 rlineto 50 | 0 height 2 div lw sub rlineto 51 | height 2 div height 2 div lw sub lineto 52 | closepath fill 53 | } if 54 | 55 | height 2 div 1.25 mul lw add 0 translate 56 | false { 57 | newpath 58 | 0 height moveto 59 | height 0 rlineto 60 | 0 lw neg rlineto 61 | height lw sub 2 div neg 0 rlineto 62 | 0 height lw sub neg rlineto 63 | lw neg 0 rlineto 64 | 0 height lw sub rlineto 65 | height lw sub 2 div neg 0 rlineto 66 | 0 lw rlineto 67 | closepath fill 68 | } if 69 | 70 | true { % The "T" of "GT". 71 | newpath 72 | 0 height moveto 73 | height lw add 2 div 0 rlineto 74 | 0 height neg rlineto 75 | lw neg 0 rlineto 76 | 0 height lw sub rlineto 77 | height lw sub 2 div neg 0 rlineto 78 | closepath fill 79 | 80 | % The right half of the top of the "T" 81 | newpath 82 | % (height + lw)/2 + lw 83 | height lw add 2 div lw add height moveto 84 | % height - (above) = height - height/2 - 3/2 lw = height/2-3/2lw 85 | height 3 lw mul sub 2 div 0 rlineto 86 | 0 lw neg rlineto 87 | height 3 lw mul sub 2 div neg 0 rlineto 88 | closepath fill 89 | } if 90 | 91 | 92 | grestore 93 | showpage 94 | %%EOF 95 | -------------------------------------------------------------------------------- /doc/src/gqtekspec.cls: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%/ 2 | % 3 | % Copyright (C) 2022, Gisselquist Technology, LLC 4 | % 5 | % This template is free software: you can redistribute it and/or modify it 6 | % under the terms of the GNU General Public License as published by the 7 | % Free Software Foundation, either version 3 of the License, or (at your 8 | % option) any later version. 9 | % 10 | % This template is distributed in the hope that it will be useful, but WITHOUT 11 | % ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 12 | % FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 | % for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License along 16 | % with this program. If not, see for a copy. 17 | % 18 | % License: GPL, v3, as defined and found on www.gnu.org, 19 | % http://www.gnu.org/licenses/gpl.html 20 | % 21 | % 22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | % \NeedsTeXFormat{LaTeX2e}[1995/12/01] 24 | \ProvidesClass{gqtekspec}[2022/11/14 v0.1 -- Gisselquist Technology Specification] 25 | \typeout{by Dan Gisselquist} 26 | \LoadClassWithOptions{report} 27 | \usepackage{datetime} 28 | \usepackage{graphicx} 29 | \usepackage[dvips]{pstricks} 30 | \usepackage{hhline} 31 | \usepackage{colortbl} 32 | \definecolor{webgreen}{rgb}{0,0.5,0} 33 | \usepackage[dvips,colorlinks=true,linkcolor=webgreen]{hyperref} 34 | \newdateformat{headerdate}{\THEYEAR/\twodigit{\THEMONTH}/\twodigit{\THEDAY}} 35 | \setlength{\hoffset}{0.25in} 36 | \setlength{\voffset}{-0.5in} 37 | \setlength{\marginparwidth}{0in} 38 | \setlength{\marginparsep}{0in} 39 | \setlength{\textwidth}{6in} 40 | \setlength{\oddsidemargin}{0in} 41 | 42 | % ************************************** 43 | % * APPENDIX * 44 | % ************************************** 45 | % 46 | \newcommand\appfl@g{\appendixname} %used to test \@chapapp 47 | % 48 | % \renewcommand\appendix{\par\clearpage 49 | % \setcounter{chapter}{0}% 50 | % \setcounter{section}{0}% 51 | % \renewcommand\@chapapp{\appendixname}% 52 | % \renewcommand\thechapter{\Alph{chapter}} 53 | % \if@nosectnum\else 54 | % \renewcommand\thesection{\Alph{chapter}.\arabic{section}} 55 | % \fi 56 | % } 57 | 58 | 59 | % FIGURE 60 | % redefine the @caption command to put a period after the figure or 61 | % table number in the lof and lot tables 62 | \long\def\@caption#1[#2]#3{\par\addcontentsline{\csname 63 | ext@#1\endcsname}{#1}{\protect\numberline{\csname 64 | the#1\endcsname.}{\ignorespaces #2}}\begingroup 65 | \@parboxrestore 66 | \normalsize 67 | \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par 68 | \endgroup} 69 | 70 | % **************************************** 71 | % * TABLE OF CONTENTS, ETC. * 72 | % **************************************** 73 | 74 | \renewcommand\contentsname{Contents} 75 | \renewcommand\listfigurename{Figures} 76 | \renewcommand\listtablename{Tables} 77 | 78 | \newif\if@toc \@tocfalse 79 | \renewcommand\tableofcontents{% 80 | \begingroup% temporarily set if@toc so that \@schapter will not 81 | % put Table of Contents in the table of contents. 82 | \@toctrue 83 | \chapter*{\contentsname} 84 | \endgroup 85 | \thispagestyle{gqtekspecplain} 86 | 87 | \baselineskip=10pt plus .5pt minus .5pt 88 | 89 | {\raggedleft Page \par\vskip-\parskip} 90 | \@starttoc{toc}% 91 | \baselineskip=\normalbaselineskip 92 | } 93 | 94 | \def\l@appendix{\pagebreak[3] 95 | \vskip 1.0em plus 1pt % space above appendix line 96 | \@dottedtocline{0}{0em}{8em}} 97 | 98 | \def\l@chapter{\pagebreak[3] 99 | \vskip 1.0em plus 1pt % space above appendix line 100 | \@dottedtocline{0}{0em}{4em}} 101 | 102 | % \if@nosectnum\else 103 | % \renewcommand\l@section{\@dottedtocline{1}{5.5em}{2.4em}} 104 | % \renewcommand\l@subsection{\@dottedtocline{2}{8.5em}{3.2em}} 105 | % \renewcommand\l@subsubsection{\@dottedtocline{3}{11em}{4.1em}} 106 | % \renewcommand\l@paragraph{\@dottedtocline{4}{13.5em}{5em}} 107 | % \renewcommand\l@subparagraph{\@dottedtocline{5}{16em}{6em}} 108 | % \fi 109 | 110 | % LIST OF FIGURES 111 | % 112 | \def\listoffigures{% 113 | \begingroup 114 | \chapter*{\listfigurename}% 115 | \endgroup 116 | \thispagestyle{gqtekspecplain}% 117 | 118 | \baselineskip=10pt plus .5pt minus .5pt% 119 | 120 | {\hbox to \hsize{Figure\hfil Page} \par\vskip-\parskip}% 121 | 122 | \rule[2mm]{\textwidth}{0.5mm}\par 123 | 124 | \@starttoc{lof}% 125 | \baselineskip=\normalbaselineskip}% 126 | 127 | \def\l@figure{\@dottedtocline{1}{1em}{4.0em}} 128 | 129 | % LIST OF TABLES 130 | % 131 | \def\listoftables{% 132 | \begingroup 133 | \chapter*{\listtablename}% 134 | \endgroup 135 | \thispagestyle{gqtekspecplain}% 136 | \baselineskip=10pt plus .5pt minus .5pt% 137 | {\hbox to \hsize{Table\hfil Page} \par\vskip-\parskip}% 138 | 139 | % Added line underneath headings, 20 Jun 01, Capt Todd Hale. 140 | \rule[2mm]{\textwidth}{0.5mm}\par 141 | 142 | \@starttoc{lot}% 143 | \baselineskip=\normalbaselineskip}% 144 | 145 | \let\l@table\l@figure 146 | 147 | % **************************************** 148 | % * PAGE STYLES * 149 | % **************************************** 150 | % 151 | \def\ps@gqtekspectoc{% 152 | \let\@mkboth\@gobbletwo 153 | \def \@oddhead{} 154 | \def \@oddfoot{\rm 155 | \hfil\raisebox{-9pt}{\thepage}\hfil\thispagestyle{gqtekspectocn}} 156 | \let \@evenhead\@oddhead \let \@evenfoot\@oddfoot} 157 | \def\ps@gqtekspectocn{\let\@mkboth\@gobbletwo 158 | \def \@oddhead{\rm \hfil\raisebox{10pt}{Page}} 159 | \def \@oddfoot{\rm 160 | \hfil\raisebox{-9pt}{\thepage}\hfil\thispagestyle{gqtekspectocn}} 161 | \let \@evenhead\@oddhead \let \@evenfoot\@oddfoot} 162 | 163 | \def\ps@gqtekspeclof{\let\@mkboth\@gobbletwo 164 | \def \@oddhead{} 165 | \def \@oddfoot{\rm 166 | \hfil\raisebox{-9pt}{\thepage}\hfil\thispagestyle{gqtekspeclofn}} 167 | \let \@evenhead\@oddhead \let \@evenfoot\@oddfoot} 168 | \def\ps@gqtekspeclofn{\let\@mkboth\@gobbletwo 169 | \def \@oddhead{\rm 170 | \parbox{\textwidth}{\raisebox{0pt}{Figure}\hfil\raisebox{0pt}{Page} % 171 | \raisebox{20pt}{\rule[10pt]{\textwidth}{0.5mm}} }} 172 | 173 | \def \@oddfoot{\rm 174 | \hfil\raisebox{-9pt}{\thepage}\hfil\thispagestyle{gqtekspeclofn}} 175 | \let \@evenhead\@oddhead \let \@evenfoot\@oddfoot} 176 | 177 | \def\ps@gqtekspeclot{\let\@mkboth\@gobbletwo 178 | \def \@oddhead{} 179 | \def \@oddfoot{\rm 180 | \hfil\raisebox{-9pt}{\thepage}\hfil\thispagestyle{gqtekspeclotn}} 181 | \let \@evenhead\@oddhead \let \@evenfoot\@oddfoot} 182 | \def\ps@gqtekspeclotn{\let\@mkboth\@gobbletwo 183 | \def \@oddhead{\rm 184 | \parbox{\textwidth}{\raisebox{0pt}{Table}\hfil\raisebox{0pt}{Page} % 185 | \raisebox{20pt}{\rule[10pt]{\textwidth}{0.5mm}} }} 186 | 187 | \def \@oddfoot{\rm 188 | \hfil\raisebox{-9pt}{\thepage}\hfil\thispagestyle{gqtekspeclotn}} 189 | \let \@evenhead\@oddhead \let \@evenfoot\@oddfoot} 190 | 191 | \def\ps@gqtekspecplain{\let\@mkboth\@gobbletwo 192 | \def \@oddhead{\rput(0,-2pt){\psline(0,0)(\textwidth,0)}\rm \hbox to 1in{\includegraphics[height=0.8\headheight]{GT.eps} Gisselquist Technology, LLC}\hfil\hbox{\@title}\hfil\hbox to 1in{\hfil\headerdate\@date}} 193 | \def \@oddfoot{\rput(0,9pt){\psline(0,0)(\textwidth,0)}\rm \hbox to 1in{www.opencores.com\hfil}\hfil\hbox{\r@vision}\hfil\hbox to 1in{\hfil{\thepage}}} 194 | \let \@evenhead\@oddhead \let \@evenfoot\@oddfoot} 195 | 196 | % \def\author#1{\def\auth@r{#1}} 197 | % \def\title#1{\def\ti@tle{#1}} 198 | 199 | \def\logo{\begin{pspicture}(0,0)(5.67in,0.75in) 200 | \rput[lb](0.05in,0.10in){\includegraphics[height=0.75in]{GT.eps}} 201 | \rput[lb](1.15in,0.05in){\scalebox{1.8}{\parbox{2.0in}{Gisselquist\\Technology, LLC}}} 202 | \end{pspicture}} 203 | % TITLEPAGE 204 | % 205 | \def\titlepage{\setcounter{page}{1} 206 | \typeout{^^JTitle Page.} 207 | \thispagestyle{empty} 208 | \leftline{\rput(0,0){\psline(0,0)(\textwidth,0)}\hfill} 209 | \vskip 2\baselineskip 210 | \logo\hfil % Original is 3.91 in x 1.26 in, let's match V thus 211 | \vskip 2\baselineskip 212 | \vspace*{10pt}\vfil 213 | \begin{minipage}{\textwidth}\raggedleft 214 | \ifproject{\Huge\bfseries\MakeUppercase\@project} \\\fi 215 | \vspace*{15pt} 216 | {\Huge\bfseries\MakeUppercase\@title} \\ 217 | \vskip 10\baselineskip 218 | \Large \@author \\ 219 | \ifemail{\Large \@email}\\\fi 220 | \vskip 6\baselineskip 221 | \Large \usdate\@date \\ 222 | \end{minipage} 223 | % \baselineskip 22.5pt\large\rm\MakeUppercase\ti@tle 224 | \vspace*{30pt} 225 | \vfil 226 | \newpage\baselineskip=\normalbaselineskip} 227 | 228 | \newenvironment{license}{\clearpage\typeout{^^JLicense Page.}\ \vfill\noindent}% 229 | {\vfill\newpage} 230 | % **************************************** 231 | % * CHAPTER DEFINITIONS * 232 | % **************************************** 233 | % 234 | \renewcommand\chapter{\if@openright\cleardoublepage\else\clearpage\fi 235 | \thispagestyle{gqtekspecplain}% 236 | \global\@topnum\z@ 237 | \@afterindentfalse 238 | \secdef\@chapter\@schapter} 239 | \renewcommand\@makechapterhead[1]{% 240 | \hbox to \textwidth{\hfil{\Huge\bfseries \thechapter.}}\vskip 10\p@ 241 | \hbox to \textwidth{\rput(0,0){\psline[linewidth=0.04in](0,0)(\textwidth,0)}}\vskip \p@ 242 | \hbox to \textwidth{\rput(0,0){\psline[linewidth=0.04in](0,0)(\textwidth,0)}}\vskip 10\p@ 243 | \hbox to \textwidth{\hfill{\Huge\bfseries #1}}% 244 | \par\nobreak\vskip 40\p@} 245 | \renewcommand\@makeschapterhead[1]{% 246 | \hbox to \textwidth{\hfill{\Huge\bfseries #1}}% 247 | \par\nobreak\vskip 40\p@} 248 | % **************************************** 249 | % * INITIALIZATION * 250 | % **************************************** 251 | % 252 | % Default initializations 253 | 254 | \ps@gqtekspecplain % 'gqtekspecplain' page style with lowered page nos. 255 | \onecolumn % Single-column. 256 | \pagenumbering{roman} % the first chapter will change pagenumbering 257 | % to arabic 258 | \setcounter{page}{1} % in case a titlepage is not requested 259 | % otherwise titlepage sets page to 1 since the 260 | % flyleaf is not counted as a page 261 | \widowpenalty 10000 % completely discourage widow lines 262 | \clubpenalty 10000 % completely discourage club (orphan) lines 263 | \raggedbottom % don't force alignment of bottom of pages 264 | 265 | \date{\today} 266 | \newif\ifproject\projectfalse 267 | \def\project#1{\projecttrue\gdef\@project{#1}} 268 | \def\@project{} 269 | \newif\ifemail\emailfalse 270 | \def\email#1{\emailtrue\gdef\@email{#1}} 271 | \def\@email{} 272 | \def\revision#1{\gdef\r@vision{#1}} 273 | \def\r@vision{} 274 | \def\at{\makeatletter @\makeatother} 275 | \newdateformat{theyear}{\THEYEAR} 276 | \newenvironment{revisionhistory}{\clearpage\typeout{^^JRevision History.}% 277 | \hbox to \textwidth{\hfil\scalebox{1.8}{\large\bfseries Revision History}}\vskip 10\p@\noindent% 278 | \begin{tabular}{|p{0.5in}|p{1in}|p{1in}|p{2.875in}|}\hline 279 | \rowcolor[gray]{0.8} Rev. & Date & Author & Description\\\hline\hline} 280 | {\end{tabular}\clearpage} 281 | \newenvironment{clocklist}{\begin{tabular}{|p{0.75in}|p{0.5in}|l|l|p{2.875in}|}\hline 282 | \rowcolor[gray]{0.85} Name & Source & \multicolumn{2}{l|}{Rates (MHz)} & Description \\\hhline{~|~|-|-|~}% 283 | \rowcolor[gray]{0.85} & & Max & Min & \\\hline\hline}% 284 | {\end{tabular}} 285 | \newenvironment{reglist}{\begin{tabular}{|p{0.75in}|p{0.5in}|p{0.5in}|p{0.5in}|p{2.875in}|}\hline 286 | \rowcolor[gray]{0.85} Name & Address & Width & Access & Description \\\hline\hline}% 287 | {\end{tabular}} 288 | \newenvironment{bitlist}{\begin{tabular}{|p{0.5in}|p{0.5in}|p{3.875in}|}\hline 289 | \rowcolor[gray]{0.85} Bit \# & Access & Description \\\hline\hline}% 290 | {\end{tabular}} 291 | \newenvironment{portlist}{\begin{tabular}{|p{0.75in}|p{0.5in}|p{0.75in}|p{3.375in}|}\hline 292 | \rowcolor[gray]{0.85} Port & Width & Direction & Description \\\hline\hline}% 293 | {\end{tabular}} 294 | \newenvironment{wishboneds}{\begin{tabular}{|p{2.5in}|p{2.5in}|}\hline 295 | \rowcolor[gray]{0.85} Description & Specification \\\hline\hline}% 296 | {\end{tabular}} 297 | \newenvironment{preface}{\chapter*{Preface}}{\par\bigskip\bigskip\leftline{\hfill\@author}} 298 | \endinput 299 | -------------------------------------------------------------------------------- /doc/uart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZipCPU/wbuart32/f43a6b83c3a70fb2ac0696a45c5545b233fb860b/doc/uart.png -------------------------------------------------------------------------------- /rtl/Makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## 3 | ## Filename: Makefile 4 | ## {{{ 5 | ## Project: wbuart32, a full featured UART with simulator 6 | ## 7 | ## Purpose: To direct the Verilator build of the SoC sources. The result 8 | ## is C++ code (built by Verilator), that is then built (herein) 9 | ## into a library. 10 | ## 11 | ## Targets: The default target, all, builds the target test, which includes 12 | ## the libraries necessary for Verilator testing. 13 | ## 14 | ## Creator: Dan Gisselquist, Ph.D. 15 | ## Gisselquist Technology, LLC 16 | ## 17 | ################################################################################ 18 | ## }}} 19 | ## Copyright (C) 2015-2024, Gisselquist Technology, LLC 20 | ## {{{ 21 | ## This program is free software (firmware): you can redistribute it and/or 22 | ## modify it under the terms of the GNU General Public License as published 23 | ## by the Free Software Foundation, either version 3 of the License, or (at 24 | ## your option) any later version. 25 | ## 26 | ## This program is distributed in the hope that it will be useful, but WITHOUT 27 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 28 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 29 | ## for more details. 30 | ## 31 | ## You should have received a copy of the GNU General Public License along 32 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no 33 | ## target there if the PDF file isn't present.) If not, see 34 | ## for a copy. 35 | ## }}} 36 | ## License: GPL, v3, as defined and found on www.gnu.org, 37 | ## {{{ 38 | ## http://www.gnu.org/licenses/gpl.html 39 | ## 40 | ################################################################################ 41 | ## 42 | .DELETE_ON_ERROR: 43 | ## }}} 44 | .PHONY: all 45 | all: test 46 | ## {{{ 47 | .DELETE_ON_ERROR: 48 | YYMMDD=`date +%Y%m%d` 49 | CXX := g++ 50 | FBDIR := . 51 | VDIRFB:= $(FBDIR)/obj_dir 52 | VERILATOR := verilator 53 | ## }}} 54 | 55 | .PHONY: test 56 | ## {{{ 57 | test: $(VDIRFB)/Vtxuart__ALL.a 58 | test: $(VDIRFB)/Vrxuart__ALL.a 59 | test: $(VDIRFB)/Vwbuart__ALL.a 60 | test: $(VDIRFB)/Vtxuartlite__ALL.a 61 | test: $(VDIRFB)/Vrxuartlite__ALL.a 62 | ## }}} 63 | 64 | $(VDIRFB)/Vrxuart__ALL.a: $(VDIRFB)/Vrxuart.cpp 65 | $(VDIRFB)/Vtxuart__ALL.a: $(VDIRFB)/Vtxuart.cpp 66 | $(VDIRFB)/Vrxuartlite__ALL.a: $(VDIRFB)/Vrxuartlite.cpp 67 | $(VDIRFB)/Vtxuartlite__ALL.a: $(VDIRFB)/Vtxuartlite.cpp 68 | $(VDIRFB)/Vwbuart__ALL.a: $(VDIRFB)/Vwbuart.cpp 69 | 70 | $(VDIRFB)/V%.mk: $(VDIRFB)/%.h 71 | $(VDIRFB)/V%.h: $(VDIRFB)/%.cpp 72 | $(VDIRFB)/V%.cpp: $(FBDIR)/%.v 73 | $(VERILATOR) --trace -MMD -Wall -cc $*.v 74 | 75 | $(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.mk 76 | cd $(VDIRFB); make -f V$*.mk 77 | 78 | tags: $(wildcard *.v) 79 | ctags *.v 80 | 81 | .PHONY: clean 82 | clean: 83 | rm -rf tags $(VDIRFB)/ 84 | 85 | DEPS := $(wildcard $(VDIRFB)/*.d) 86 | 87 | ifneq ($(MAKECMDGOALS),clean) 88 | ifneq ($(DEPS),) 89 | include $(DEPS) 90 | endif 91 | endif 92 | -------------------------------------------------------------------------------- /rtl/rxuart.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: rxuart.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: Receive and decode inputs from a single UART line. 8 | // 9 | // 10 | // To interface with this module, connect it to your system clock, 11 | // pass it the 32 bit setup register (defined below) and the UART 12 | // input. When data becomes available, the o_wr line will be asserted 13 | // for one clock cycle. On parity or frame errors, the o_parity_err 14 | // or o_frame_err lines will be asserted. Likewise, on a break 15 | // condition, o_break will be asserted. These lines are self clearing. 16 | // 17 | // There is a synchronous reset line, logic high. 18 | // 19 | // Now for the setup register. The register is 32 bits, so that this 20 | // UART may be set up over a 32-bit bus. 21 | // 22 | // i_setup[30] True if we are not using hardware flow control. This bit 23 | // is ignored within this module, as any receive hardware flow 24 | // control will need to be implemented elsewhere. 25 | // 26 | // i_setup[29:28] Indicates the number of data bits per word. This will 27 | // either be 2'b00 for an 8-bit word, 2'b01 for a 7-bit word, 2'b10 28 | // for a six bit word, or 2'b11 for a five bit word. 29 | // 30 | // i_setup[27] Indicates whether or not to use one or two stop bits. 31 | // Set this to one to expect two stop bits, zero for one. 32 | // 33 | // i_setup[26] Indicates whether or not a parity bit exists. Set this 34 | // to 1'b1 to include parity. 35 | // 36 | // i_setup[25] Indicates whether or not the parity bit is fixed. Set 37 | // to 1'b1 to include a fixed bit of parity, 1'b0 to allow the 38 | // parity to be set based upon data. (Both assume the parity 39 | // enable value is set.) 40 | // 41 | // i_setup[24] This bit is ignored if parity is not used. Otherwise, 42 | // in the case of a fixed parity bit, this bit indicates whether 43 | // mark (1'b1) or space (1'b0) parity is used. Likewise if the 44 | // parity is not fixed, a 1'b1 selects even parity, and 1'b0 45 | // selects odd. 46 | // 47 | // i_setup[23:0] Indicates the speed of the UART in terms of clocks. 48 | // So, for example, if you have a 200 MHz clock and wish to 49 | // run your UART at 9600 baud, you would take 200 MHz and divide 50 | // by 9600 to set this value to 24'd20834. Likewise if you wished 51 | // to run this serial port at 115200 baud from a 200 MHz clock, 52 | // you would set the value to 24'd1736 53 | // 54 | // Thus, to set the UART for the common setting of an 8-bit word, 55 | // one stop bit, no parity, and 115200 baud over a 200 MHz clock, you 56 | // would want to set the setup value to: 57 | // 58 | // 32'h0006c8 // For 115,200 baud, 8 bit, no parity 59 | // 32'h005161 // For 9600 baud, 8 bit, no parity 60 | // 61 | // 62 | // 63 | // Creator: Dan Gisselquist, Ph.D. 64 | // Gisselquist Technology, LLC 65 | // 66 | //////////////////////////////////////////////////////////////////////////////// 67 | // }}} 68 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 69 | // {{{ 70 | // This program is free software (firmware): you can redistribute it and/or 71 | // modify it under the terms of the GNU General Public License as published 72 | // by the Free Software Foundation, either version 3 of the License, or (at 73 | // your option) any later version. 74 | // 75 | // This program is distributed in the hope that it will be useful, but WITHOUT 76 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 77 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 78 | // for more details. 79 | // 80 | // You should have received a copy of the GNU General Public License along 81 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 82 | // target there if the PDF file isn't present.) If not, see 83 | // for a copy. 84 | // }}} 85 | // License: GPL, v3, as defined and found on www.gnu.org, 86 | // {{{ 87 | // http://www.gnu.org/licenses/gpl.html 88 | // 89 | //////////////////////////////////////////////////////////////////////////////// 90 | // 91 | `default_nettype none 92 | // }}} 93 | module rxuart #( 94 | // {{{ 95 | // 8 data bits, no parity, (at least 1) stop bit 96 | parameter [30:0] INITIAL_SETUP = 31'd868, 97 | // States: (@ baud counter == 0) 98 | // 0 First bit arrives 99 | // ..7 Bits arrive 100 | // 8 Stop bit (x1) 101 | // 9 Stop bit (x2) 102 | // c break condition 103 | // d Waiting for the channel to go high 104 | // e Waiting for the reset to complete 105 | // f Idle state 106 | localparam [3:0] RXU_BIT_ZERO = 4'h0, 107 | RXU_BIT_ONE = 4'h1, 108 | RXU_BIT_TWO = 4'h2, 109 | RXU_BIT_THREE = 4'h3, 110 | // RXU_BIT_FOUR = 4'h4, // UNUSED 111 | // RXU_BIT_FIVE = 4'h5, // UNUSED 112 | // RXU_BIT_SIX = 4'h6, // UNUSED 113 | RXU_BIT_SEVEN = 4'h7, 114 | RXU_PARITY = 4'h8, 115 | RXU_STOP = 4'h9, 116 | RXU_SECOND_STOP = 4'ha, 117 | // Unused 4'hb 118 | // Unused 4'hc 119 | RXU_BREAK = 4'hd, 120 | RXU_RESET_IDLE = 4'he, 121 | RXU_IDLE = 4'hf 122 | // }}} 123 | ) ( 124 | // {{{ 125 | input wire i_clk, i_reset, 126 | /* verilator lint_off UNUSED */ 127 | input wire [30:0] i_setup, 128 | /* verilator lint_on UNUSED */ 129 | input wire i_uart_rx, 130 | output reg o_wr, 131 | output reg [7:0] o_data, 132 | output reg o_break, 133 | output reg o_parity_err, o_frame_err, 134 | output wire o_ck_uart 135 | // }}} 136 | ); 137 | 138 | // Signal declarations 139 | // {{{ 140 | wire [23:0] clocks_per_baud, half_baud; 141 | wire [1:0] data_bits; 142 | wire use_parity, parity_even, dblstop, fixd_parity; 143 | reg [29:0] r_setup; 144 | reg [3:0] state; 145 | 146 | reg [23:0] baud_counter; 147 | reg zero_baud_counter; 148 | reg q_uart, qq_uart, ck_uart; 149 | reg [27:0] chg_counter, break_condition; 150 | reg line_synch; 151 | reg half_baud_time; 152 | reg [7:0] data_reg; 153 | reg calc_parity; 154 | reg pre_wr; 155 | 156 | assign clocks_per_baud = r_setup[23:0]; 157 | // assign hw_flow_control = !r_setup[30]; 158 | assign data_bits = r_setup[29:28]; 159 | assign dblstop = r_setup[27]; 160 | assign use_parity = r_setup[26]; 161 | assign fixd_parity = r_setup[25]; 162 | assign parity_even = r_setup[24]; 163 | assign break_condition = { r_setup[23:0], 4'h0 }; 164 | assign half_baud = { 1'h0, r_setup[23:1] }-24'h1; 165 | 166 | // }}} 167 | 168 | // ck_uart 169 | // {{{ 170 | // Since this is an asynchronous receiver, we need to register our 171 | // input a couple of clocks over to avoid any problems with 172 | // metastability. We do that here, and then ignore all but the 173 | // ck_uart wire. 174 | initial q_uart = 1'b0; 175 | initial qq_uart = 1'b0; 176 | initial ck_uart = 1'b0; 177 | always @(posedge i_clk) 178 | if (i_reset) 179 | { ck_uart, qq_uart, q_uart } <= 3'h0; 180 | else 181 | { ck_uart, qq_uart, q_uart } <= { qq_uart, q_uart, i_uart_rx }; 182 | // }}} 183 | 184 | // o_ck_uart 185 | // {{{ 186 | // In case anyone else wants this clocked, stabilized value, we 187 | // offer it on our output. 188 | assign o_ck_uart = ck_uart; 189 | // }}} 190 | 191 | // chg_counter 192 | // {{{ 193 | // Keep track of the number of clocks since the last change. 194 | // 195 | // This is used to determine if we are in either a break or an idle 196 | // condition, as discussed further below. 197 | initial chg_counter = 0; 198 | always @(posedge i_clk) 199 | if (i_reset) 200 | chg_counter <= 0; 201 | else if (qq_uart != ck_uart) 202 | chg_counter <= 0; 203 | else if (chg_counter < break_condition) 204 | chg_counter <= chg_counter + 1; 205 | // }}} 206 | 207 | // o_break 208 | // {{{ 209 | // Are we in a break condition? 210 | // 211 | // A break condition exists if the line is held low for longer than 212 | // a data word. Hence, we keep track of when the last change occurred. 213 | // If it was more than break_condition clocks ago, and the current input 214 | // value is a 0, then we're in a break--and nothing can be read until 215 | // the line idles again. 216 | initial o_break = 1'b0; 217 | always @(posedge i_clk) 218 | if (i_reset) 219 | o_break <= 1'b0; 220 | else 221 | o_break <= ((chg_counter >= break_condition)&&(~ck_uart))? 1'b1:1'b0; 222 | // }}} 223 | 224 | // line_synch 225 | // {{{ 226 | // Are we between characters? 227 | // 228 | // The opposite of a break condition is where the line is held high 229 | // for more clocks than would be in a character. When this happens, 230 | // we know we have synchronization--otherwise, we might be sampling 231 | // from within a data word. 232 | // 233 | // This logic is used later to hold the RXUART in a reset condition 234 | // until we know we are between data words. At that point, we should 235 | // be able to hold on to our synchronization. 236 | initial line_synch = 1'b0; 237 | always @(posedge i_clk) 238 | if (i_reset) 239 | line_synch <= 1'b0; 240 | else 241 | line_synch <= ((chg_counter >= break_condition)&&(ck_uart)); 242 | // }}} 243 | 244 | // half_baud_time 245 | // {{{ 246 | // Are we in the middle of a baud iterval? Specifically, are we 247 | // in the middle of a start bit? Set this to high if so. We'll use 248 | // this within our state machine to transition out of the IDLE 249 | // state. 250 | initial half_baud_time = 0; 251 | always @(posedge i_clk) 252 | if (i_reset) 253 | half_baud_time <= 1'b0; 254 | else 255 | half_baud_time <= (~ck_uart)&&(chg_counter >= {4'h0,half_baud}); 256 | // }}} 257 | 258 | // r_setup 259 | // {{{ 260 | // Allow our controlling processor to change our setup at any time 261 | // outside of receiving/processing a character. 262 | initial r_setup = INITIAL_SETUP[29:0]; 263 | always @(posedge i_clk) 264 | if (i_reset) 265 | r_setup <= INITIAL_SETUP[29:0]; 266 | else if (state >= RXU_RESET_IDLE) 267 | r_setup <= i_setup[29:0]; 268 | // }}} 269 | 270 | // state -- the monster state machine 271 | // {{{ 272 | // Our monster state machine. YIKES! 273 | // 274 | // Yeah, this may be more complicated than it needs to be. The basic 275 | // progression is: 276 | // RESET -> RESET_IDLE -> (when line is idle) -> IDLE 277 | // IDLE -> bit 0 -> bit 1 -> bit_{ndatabits} -> 278 | // (optional) PARITY -> STOP -> (optional) SECOND_STOP 279 | // -> IDLE 280 | // ANY -> (on break) BREAK -> IDLE 281 | // 282 | // There are 16 states, although all are not used. These are listed 283 | // at the top of this file. 284 | // 285 | // Logic inputs (12): (I've tried to minimize this number) 286 | // state (4) 287 | // i_reset 288 | // line_synch 289 | // o_break 290 | // ckuart 291 | // half_baud_time 292 | // zero_baud_counter 293 | // use_parity 294 | // dblstop 295 | // Logic outputs (4): 296 | // state 297 | // 298 | initial state = RXU_RESET_IDLE; 299 | always @(posedge i_clk) 300 | if (i_reset) 301 | state <= RXU_RESET_IDLE; 302 | else if (state == RXU_RESET_IDLE) 303 | begin 304 | // {{{ 305 | if (line_synch) 306 | // Goto idle state from a reset 307 | state <= RXU_IDLE; 308 | else // Otherwise, stay in this condition 'til reset 309 | state <= RXU_RESET_IDLE; 310 | // }}} 311 | end else if (o_break) 312 | begin // We are in a break condition 313 | state <= RXU_BREAK; 314 | end else if (state == RXU_BREAK) 315 | begin // Goto idle state following return ck_uart going high 316 | // {{{ 317 | if (ck_uart) 318 | state <= RXU_IDLE; 319 | else 320 | state <= RXU_BREAK; 321 | // }}} 322 | end else if (state == RXU_IDLE) 323 | begin // Idle state, independent of baud counter 324 | // {{{ 325 | if (!ck_uart && half_baud_time) 326 | begin 327 | // We are in the center of a valid start bit 328 | case (data_bits) 329 | 2'b00: state <= RXU_BIT_ZERO; 330 | 2'b01: state <= RXU_BIT_ONE; 331 | 2'b10: state <= RXU_BIT_TWO; 332 | 2'b11: state <= RXU_BIT_THREE; 333 | endcase 334 | end else // Otherwise, just stay here in idle 335 | state <= RXU_IDLE; 336 | // }}} 337 | end else if (zero_baud_counter) 338 | begin 339 | // {{{ 340 | if (state < RXU_BIT_SEVEN) 341 | // Data arrives least significant bit first. 342 | // By the time this is clocked in, it's what 343 | // you'll have. 344 | state <= state + 1; 345 | else if (state == RXU_BIT_SEVEN) 346 | state <= (use_parity) ? RXU_PARITY:RXU_STOP; 347 | else if (state == RXU_PARITY) 348 | state <= RXU_STOP; 349 | else if (state == RXU_STOP) 350 | begin // Stop (or parity) bit(s) 351 | if (!ck_uart) // On frame error, wait 4 ch idle 352 | state <= RXU_RESET_IDLE; 353 | else if (dblstop) 354 | state <= RXU_SECOND_STOP; 355 | else 356 | state <= RXU_IDLE; 357 | end else // state must equal RX_SECOND_STOP 358 | begin 359 | if (!ck_uart) // On frame error, wait 4 ch idle 360 | state <= RXU_RESET_IDLE; 361 | else 362 | state <= RXU_IDLE; 363 | end 364 | // }}} 365 | end 366 | // }}} 367 | 368 | // data_reg -- Data bit capture logic. 369 | // {{{ 370 | // This is drastically simplified from the state machine above, based 371 | // upon: 1) it doesn't matter what it is until the end of a captured 372 | // byte, and 2) the data register will flush itself of any invalid 373 | // data in all other cases. Hence, let's keep it real simple. 374 | // The only trick, though, is that if we have parity, then the data 375 | // register needs to be held through that state without getting 376 | // updated. 377 | always @(posedge i_clk) 378 | if ((zero_baud_counter)&&(state != RXU_PARITY)) 379 | data_reg <= { ck_uart, data_reg[7:1] }; 380 | // }}} 381 | 382 | // calc_parity 383 | // {{{ 384 | // Parity calculation logic 385 | // 386 | // As with the data capture logic, all that must be known about this 387 | // bit is that it is the exclusive-OR of all bits prior. The first 388 | // of those will follow idle, so we set ourselves to zero on idle. 389 | // Then, as we walk through the states of a bit, all will adjust this 390 | // value up until the parity bit, where the value will be read. Setting 391 | // it then or after will be irrelevant, so ... this should be good 392 | // and simplified. Note--we don't need to adjust this on reset either, 393 | // since the reset state will lead to the idle state where we'll be 394 | // reset before any transmission takes place. 395 | always @(posedge i_clk) 396 | if (i_reset) 397 | calc_parity <= 0; 398 | else if (state == RXU_IDLE) 399 | calc_parity <= 0; 400 | else if (zero_baud_counter) 401 | calc_parity <= calc_parity ^ ck_uart; 402 | // }}} 403 | 404 | // o_parity_err -- Parity error logic 405 | // {{{ 406 | // Set during the parity bit interval, read during the last stop bit 407 | // interval, cleared on BREAK, RESET_IDLE, or IDLE states. 408 | initial o_parity_err = 1'b0; 409 | always @(posedge i_clk) 410 | if (i_reset) 411 | o_parity_err <= 1'b0; 412 | else if ((zero_baud_counter)&&(state == RXU_PARITY)) 413 | begin 414 | if (fixd_parity) 415 | // Fixed parity bit--independent of any dat 416 | // value. 417 | o_parity_err <= (ck_uart ^ parity_even); 418 | else if (parity_even) 419 | // Parity even: The XOR of all bits including 420 | // the parity bit must be zero. 421 | o_parity_err <= (calc_parity != ck_uart); 422 | else 423 | // Parity odd: the parity bit must equal the 424 | // XOR of all the data bits. 425 | o_parity_err <= (calc_parity == ck_uart); 426 | end else if (state >= RXU_BREAK) 427 | o_parity_err <= 1'b0; 428 | // }}} 429 | 430 | // o_frame_err -- Frame error determination 431 | // {{{ 432 | // For the purpose of this controller, a frame error is defined as a 433 | // stop bit (or second stop bit, if so enabled) not being high midway 434 | // through the stop baud interval. The frame error value is 435 | // immediately read, so we can clear it under all other circumstances. 436 | // Specifically, we want it clear in RXU_BREAK, RXU_RESET_IDLE, and 437 | // most importantly in RXU_IDLE. 438 | initial o_frame_err = 1'b0; 439 | always @(posedge i_clk) 440 | if (i_reset) 441 | o_frame_err <= 1'b0; 442 | else if ((zero_baud_counter)&&((state == RXU_STOP) 443 | ||(state == RXU_SECOND_STOP))) 444 | o_frame_err <= (o_frame_err)||(~ck_uart); 445 | else if ((zero_baud_counter)||(state >= RXU_BREAK)) 446 | o_frame_err <= 1'b0; 447 | // }}} 448 | 449 | // pre_wr, o_data 450 | // {{{ 451 | // Our data bit logic doesn't need nearly the complexity of all that 452 | // work above. Indeed, we only need to know if we are at the end of 453 | // a stop bit, in which case we copy the data_reg into our output 454 | // data register, o_data. 455 | // 456 | // We would also set o_wr to be true when this is the case, but ... we 457 | // won't know if there is a frame error on the second stop bit for 458 | // another baud interval yet. So, instead, we set up the logic so that 459 | // we know on the next zero baud counter that we can write out. That's 460 | // the purpose of pre_wr. 461 | initial o_data = 8'h00; 462 | initial pre_wr = 1'b0; 463 | always @(posedge i_clk) 464 | if (i_reset) 465 | begin 466 | pre_wr <= 1'b0; 467 | o_data <= 8'h00; 468 | end else if ((zero_baud_counter)&&(state == RXU_STOP)) 469 | begin 470 | pre_wr <= 1'b1; 471 | case (data_bits) 472 | 2'b00: o_data <= data_reg; 473 | 2'b01: o_data <= { 1'b0, data_reg[7:1] }; 474 | 2'b10: o_data <= { 2'b0, data_reg[7:2] }; 475 | 2'b11: o_data <= { 3'b0, data_reg[7:3] }; 476 | endcase 477 | end else if ((zero_baud_counter)||(state == RXU_IDLE)) 478 | pre_wr <= 1'b0; 479 | // }}} 480 | 481 | // o_wr 482 | // {{{ 483 | // Create an output strobe, true for one clock only, once we know 484 | // all we need to know. o_data will be set on the last baud interval, 485 | // o_parity_err on the last parity baud interval (if it existed, 486 | // cleared otherwise, so ... we should be good to go here.) 487 | initial o_wr = 1'b0; 488 | always @(posedge i_clk) 489 | if (i_reset) 490 | o_wr <= 1'b0; 491 | else if ((zero_baud_counter)||(state == RXU_IDLE)) 492 | o_wr <= (pre_wr)&&(!i_reset); 493 | else 494 | o_wr <= 1'b0; 495 | // }}} 496 | 497 | // The baud counter 498 | // {{{ 499 | // This is used as a "clock divider" if you will, but the clock needs 500 | // to be reset before any byte can be decoded. In all other respects, 501 | // we set ourselves up for clocks_per_baud counts between baud 502 | // intervals. 503 | always @(posedge i_clk) 504 | if (i_reset) 505 | baud_counter <= INITIAL_SETUP[23:0]-1; 506 | else if (zero_baud_counter) 507 | baud_counter <= clocks_per_baud-1; 508 | else case(state) 509 | RXU_RESET_IDLE:baud_counter <= clocks_per_baud-1; 510 | RXU_BREAK: baud_counter <= clocks_per_baud-1; 511 | RXU_IDLE: baud_counter <= clocks_per_baud-1; 512 | default: baud_counter <= baud_counter-1; 513 | endcase 514 | // }}} 515 | 516 | // zero_baud_counter 517 | // {{{ 518 | // Rather than testing whether or not (baud_counter == 0) within our 519 | // (already too complicated) state transition tables, we use 520 | // zero_baud_counter to pre-charge that test on the clock 521 | // before--cleaning up some otherwise difficult timing dependencies. 522 | initial zero_baud_counter = 1'b0; 523 | always @(posedge i_clk) 524 | if (state == RXU_IDLE) 525 | zero_baud_counter <= 1'b0; 526 | else 527 | zero_baud_counter <= (baud_counter == 1); 528 | // }}} 529 | endmodule 530 | 531 | 532 | -------------------------------------------------------------------------------- /rtl/skidbuffer.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: skidbuffer.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: A basic SKID buffer. 8 | // 9 | // Skid buffers are required for high throughput AXI code, since the AXI 10 | // specification requires that all outputs be registered. This means 11 | // that, if there are any stall conditions calculated, it will take a clock 12 | // cycle before the stall can be propagated up stream. This means that 13 | // the data will need to be buffered for a cycle until the stall signal 14 | // can make it to the output. 15 | // 16 | // Handling that buffer is the purpose of this core. 17 | // 18 | // On one end of this core, you have the i_valid and i_data inputs to 19 | // connect to your bus interface. There's also a registered o_ready 20 | // signal to signal stalls for the bus interface. 21 | // 22 | // The other end of the core has the same basic interface, but it isn't 23 | // registered. This allows you to interact with the bus interfaces 24 | // as though they were combinatorial logic, by interacting with this half 25 | // of the core. 26 | // 27 | // If at any time the incoming !stall signal, i_ready, signals a stall, 28 | // the incoming data is placed into a buffer. Internally, that buffer 29 | // is held in r_data with the r_valid flag used to indicate that valid 30 | // data is within it. 31 | // 32 | // Parameters: 33 | // DW or data width 34 | // In order to make this core generic, the width of the data in the 35 | // skid buffer is parameterized 36 | // 37 | // OPT_LOWPOWER 38 | // Forces both o_data and r_data to zero if the respective *VALID 39 | // signal is also low. While this costs extra logic, it can also 40 | // be used to guarantee that any unused values aren't toggling and 41 | // therefore unnecessarily using power. 42 | // 43 | // This excess toggling can be particularly problematic if the 44 | // bus signals have a high fanout rate, or a long signal path 45 | // across an FPGA. 46 | // 47 | // OPT_OUTREG 48 | // Causes the outputs to be registered 49 | // 50 | // OPT_PASSTHROUGH 51 | // Turns the skid buffer into a passthrough. Used for formal 52 | // verification only. 53 | // 54 | // Creator: Dan Gisselquist, Ph.D. 55 | // Gisselquist Technology, LLC 56 | // 57 | //////////////////////////////////////////////////////////////////////////////// 58 | // }}} 59 | // Copyright (C) 2019-2024, Gisselquist Technology, LLC 60 | // {{{ 61 | // This program is free software (firmware): you can redistribute it and/or 62 | // modify it under the terms of the GNU General Public License as published 63 | // by the Free Software Foundation, either version 3 of the License, or (at 64 | // your option) any later version. 65 | // 66 | // This program is distributed in the hope that it will be useful, but WITHOUT 67 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 68 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 69 | // for more details. 70 | // 71 | // You should have received a copy of the GNU General Public License along 72 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 73 | // target there if the PDF file isn't present.) If not, see 74 | // for a copy. 75 | // 76 | // License: GPL, v3, as defined and found on www.gnu.org, 77 | // http://www.gnu.org/licenses/gpl.html 78 | // 79 | // 80 | //////////////////////////////////////////////////////////////////////////////// 81 | // 82 | // 83 | `default_nettype none 84 | // }}} 85 | module skidbuffer #( 86 | // {{{ 87 | parameter [0:0] OPT_LOWPOWER = 0, 88 | parameter [0:0] OPT_OUTREG = 1, 89 | // 90 | parameter [0:0] OPT_PASSTHROUGH = 0, 91 | parameter DW = 8 92 | // }}} 93 | ) ( 94 | // {{{ 95 | input wire i_clk, i_reset, 96 | input wire i_valid, 97 | output reg o_ready, 98 | input wire [DW-1:0] i_data, 99 | output reg o_valid, 100 | input wire i_ready, 101 | output reg [DW-1:0] o_data 102 | // }}} 103 | ); 104 | 105 | reg [DW-1:0] r_data; 106 | 107 | generate if (OPT_PASSTHROUGH) 108 | begin : PASSTHROUGH 109 | // {{{ 110 | always @(*) 111 | o_ready = i_ready; 112 | always @(*) 113 | o_valid = i_valid; 114 | always @(*) 115 | if (!i_valid && OPT_LOWPOWER) 116 | o_data = 0; 117 | else 118 | o_data = i_data; 119 | 120 | always @(*) 121 | r_data = 0; 122 | // }}} 123 | end else begin : LOGIC 124 | // We'll start with skid buffer itself 125 | // {{{ 126 | reg r_valid; 127 | 128 | // r_valid 129 | // {{{ 130 | initial r_valid = 0; 131 | always @(posedge i_clk) 132 | if (i_reset) 133 | r_valid <= 0; 134 | else if ((i_valid && o_ready) && (o_valid && !i_ready)) 135 | // We have incoming data, but the output is stalled 136 | r_valid <= 1; 137 | else if (i_ready) 138 | r_valid <= 0; 139 | // }}} 140 | 141 | // r_data 142 | // {{{ 143 | initial r_data = 0; 144 | always @(posedge i_clk) 145 | if (OPT_LOWPOWER && i_reset) 146 | r_data <= 0; 147 | else if (OPT_LOWPOWER && (!o_valid || i_ready)) 148 | r_data <= 0; 149 | else if ((!OPT_LOWPOWER || !OPT_OUTREG || i_valid) && o_ready) 150 | r_data <= i_data; 151 | // }}} 152 | 153 | // o_ready 154 | // {{{ 155 | always @(*) 156 | o_ready = !r_valid; 157 | // }}} 158 | 159 | // 160 | // And then move on to the output port 161 | // 162 | if (!OPT_OUTREG) 163 | begin 164 | 165 | always @(*) 166 | o_valid = !i_reset && (i_valid || r_valid); 167 | // }}} 168 | 169 | // o_data 170 | // {{{ 171 | always @(*) 172 | if (r_valid) 173 | o_data = r_data; 174 | else if (!OPT_LOWPOWER || i_valid) 175 | o_data = i_data; 176 | else 177 | o_data = 0; 178 | // }}} 179 | // }}} 180 | end else begin : REG_OUTPUT 181 | // Register our outputs 182 | // {{{ 183 | // o_valid 184 | // {{{ 185 | initial o_valid = 0; 186 | always @(posedge i_clk) 187 | if (i_reset) 188 | o_valid <= 0; 189 | else if (!o_valid || i_ready) 190 | o_valid <= (i_valid || r_valid); 191 | // }}} 192 | 193 | // o_data 194 | // {{{ 195 | initial o_data = 0; 196 | always @(posedge i_clk) 197 | if (OPT_LOWPOWER && i_reset) 198 | o_data <= 0; 199 | else if (!o_valid || i_ready) 200 | begin 201 | 202 | if (r_valid) 203 | o_data <= r_data; 204 | else if (!OPT_LOWPOWER || i_valid) 205 | o_data <= i_data; 206 | else 207 | o_data <= 0; 208 | end 209 | // }}} 210 | 211 | // }}} 212 | end 213 | // }}} 214 | end endgenerate 215 | 216 | `ifdef FORMAL 217 | `ifdef VERIFIC 218 | `define FORMAL_VERIFIC 219 | `endif 220 | `endif 221 | // 222 | `ifdef FORMAL_VERIFIC 223 | // Reset properties 224 | property RESET_CLEARS_IVALID; 225 | @(posedge i_clk) i_reset |=> !i_valid; 226 | endproperty 227 | 228 | property IDATA_HELD_WHEN_NOT_READY; 229 | @(posedge i_clk) disable iff (i_reset) 230 | i_valid && !o_ready |=> i_valid && $stable(i_data); 231 | endproperty 232 | 233 | `ifdef SKIDBUFFER 234 | assume property (IDATA_HELD_WHEN_NOT_READY); 235 | `else 236 | assert property (IDATA_HELD_WHEN_NOT_READY); 237 | `endif 238 | 239 | generate if (!OPT_PASSTHROUGH) 240 | begin 241 | 242 | assert property (@(posedge i_clk) 243 | OPT_OUTREG && i_reset |=> o_ready && !o_valid); 244 | 245 | assert property (@(posedge i_clk) 246 | !OPT_OUTREG && i_reset |-> !o_valid); 247 | 248 | // Rule #1: 249 | // Once o_valid goes high, the data cannot change until the 250 | // clock after i_ready 251 | assert property (@(posedge i_clk) 252 | disable iff (i_reset) 253 | o_valid && !i_ready 254 | |=> (o_valid && $stable(o_data))); 255 | 256 | // Rule #2: 257 | // All incoming data must either go directly to the 258 | // output port, or into the skid buffer 259 | assert property (@(posedge i_clk) 260 | disable iff (i_reset) 261 | (i_valid && o_ready 262 | && (!OPT_OUTREG || o_valid) && !i_ready) 263 | |=> (!o_ready && r_data == $past(i_data))); 264 | 265 | // Rule #3: 266 | // After the last transaction, o_valid should become idle 267 | if (!OPT_OUTREG) 268 | begin 269 | 270 | assert property (@(posedge i_clk) 271 | disable iff (i_reset) 272 | i_ready |=> (o_valid == i_valid)); 273 | 274 | end else begin 275 | 276 | assert property (@(posedge i_clk) 277 | disable iff (i_reset) 278 | i_valid && o_ready |=> o_valid); 279 | 280 | assert property (@(posedge i_clk) 281 | disable iff (i_reset) 282 | !i_valid && o_ready && i_ready |=> !o_valid); 283 | 284 | end 285 | 286 | // Rule #4 287 | // Same thing, but this time for r_valid 288 | assert property (@(posedge i_clk) 289 | !o_ready && i_ready |=> o_ready); 290 | 291 | 292 | if (OPT_LOWPOWER) 293 | begin 294 | // 295 | // If OPT_LOWPOWER is set, o_data and r_data both need 296 | // to be zero any time !o_valid or !r_valid respectively 297 | assert property (@(posedge i_clk) 298 | (OPT_OUTREG || !i_reset) && !o_valid |-> o_data == 0); 299 | 300 | assert property (@(posedge i_clk) 301 | o_ready |-> r_data == 0); 302 | 303 | // else 304 | // if OPT_LOWPOWER isn't set, we can lower our 305 | // logic count by not forcing these values to zero. 306 | end 307 | 308 | `ifdef SKIDBUFFER 309 | reg f_changed_data; 310 | 311 | // Cover test 312 | cover property (@(posedge i_clk) 313 | disable iff (i_reset) 314 | (!o_valid && !i_valid) 315 | ##1 i_valid && i_ready [*3] 316 | ##1 i_valid && !i_ready 317 | ##1 i_valid && i_ready [*2] 318 | ##1 i_valid && !i_ready [*2] 319 | ##1 i_valid && i_ready [*3] 320 | // Wait for the design to clear 321 | ##1 o_valid && i_ready [*0:5] 322 | ##1 (!o_valid && !i_valid && f_changed_data)); 323 | 324 | initial f_changed_data = 0; 325 | always @(posedge i_clk) 326 | if (i_reset) 327 | f_changed_data <= 1; 328 | else if (i_valid && $past(!i_valid || o_ready)) 329 | begin 330 | if (i_data != $past(i_data + 1)) 331 | f_changed_data <= 0; 332 | end else if (!i_valid && i_data != 0) 333 | f_changed_data <= 0; 334 | 335 | `endif // SKIDCOVER 336 | end endgenerate 337 | 338 | `endif // FORMAL_VERIFIC 339 | endmodule 340 | `ifndef YOSYS 341 | `default_nettype wire 342 | `endif 343 | -------------------------------------------------------------------------------- /rtl/txuartlite.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: txuartlite.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: Transmit outputs over a single UART line. This particular UART 8 | // implementation has been extremely simplified: it does not handle 9 | // generating break conditions, nor does it handle anything other than the 10 | // 8N1 (8 data bits, no parity, 1 stop bit) UART sub-protocol. 11 | // 12 | // To interface with this module, connect it to your system clock, and 13 | // pass it the byte of data you wish to transmit. Strobe the i_wr line 14 | // high for one cycle, and your data will be off. Wait until the 'o_busy' 15 | // line is low before strobing the i_wr line again--this implementation 16 | // has NO BUFFER, so strobing i_wr while the core is busy will just 17 | // get ignored. The output will be placed on the o_txuart output line. 18 | // 19 | // (I often set both data and strobe on the same clock, and then just leave 20 | // them set until the busy line is low. Then I move on to the next piece 21 | // of data.) 22 | // 23 | // Creator: Dan Gisselquist, Ph.D. 24 | // Gisselquist Technology, LLC 25 | // 26 | //////////////////////////////////////////////////////////////////////////////// 27 | // }}} 28 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 29 | // {{{ 30 | // This program is free software (firmware): you can redistribute it and/or 31 | // modify it under the terms of the GNU General Public License as published 32 | // by the Free Software Foundation, either version 3 of the License, or (at 33 | // your option) any later version. 34 | // 35 | // This program is distributed in the hope that it will be useful, but WITHOUT 36 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 37 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 38 | // for more details. 39 | // 40 | // You should have received a copy of the GNU General Public License along 41 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 42 | // target there if the PDF file isn't present.) If not, see 43 | // for a copy. 44 | // }}} 45 | // License: GPL, v3, as defined and found on www.gnu.org, 46 | // {{{ 47 | // http://www.gnu.org/licenses/gpl.html 48 | // 49 | //////////////////////////////////////////////////////////////////////////////// 50 | // 51 | `default_nettype none 52 | // }}} 53 | module txuartlite #( 54 | // {{{ 55 | // TIMING_BITS -- the number of bits required to represent 56 | // the number of clocks per baud. 24 should be sufficient for 57 | // most baud rates, but you can trim it down to save logic if 58 | // you would like. TB is just an abbreviation for TIMING_BITS. 59 | parameter [4:0] TIMING_BITS = 5'd24, 60 | localparam TB = TIMING_BITS, 61 | // CLOCKS_PER_BAUD -- the number of system clocks per baud 62 | // interval. 63 | parameter [(TB-1):0] CLOCKS_PER_BAUD = 8 // 24'd868 64 | // }}} 65 | ) ( 66 | // {{{ 67 | input wire i_clk, i_reset, 68 | input wire i_wr, 69 | input wire [7:0] i_data, 70 | // And the UART input line itself 71 | output reg o_uart_tx, 72 | // A line to tell others when we are ready to accept data. If 73 | // (i_wr)&&(!o_busy) is ever true, then the core has accepted 74 | // a byte for transmission. 75 | output wire o_busy 76 | // }}} 77 | ); 78 | 79 | // Register/net declarations 80 | // {{{ 81 | localparam [3:0] TXUL_BIT_ZERO = 4'h0, 82 | // TXUL_BIT_ONE = 4'h1, 83 | // TXUL_BIT_TWO = 4'h2, 84 | // TXUL_BIT_THREE = 4'h3, 85 | // TXUL_BIT_FOUR = 4'h4, 86 | // TXUL_BIT_FIVE = 4'h5, 87 | // TXUL_BIT_SIX = 4'h6, 88 | // TXUL_BIT_SEVEN = 4'h7, 89 | TXUL_STOP = 4'h8, 90 | TXUL_IDLE = 4'hf; 91 | 92 | reg [(TB-1):0] baud_counter; 93 | reg [3:0] state; 94 | reg [7:0] lcl_data; 95 | reg r_busy, zero_baud_counter; 96 | // }}} 97 | 98 | // Big state machine controlling: r_busy, state 99 | // {{{ 100 | // 101 | initial r_busy = 1'b1; 102 | initial state = TXUL_IDLE; 103 | always @(posedge i_clk) 104 | if (i_reset) 105 | begin 106 | r_busy <= 1'b1; 107 | state <= TXUL_IDLE; 108 | end else if (!zero_baud_counter) 109 | // r_busy needs to be set coming into here 110 | r_busy <= 1'b1; 111 | else if (state > TXUL_STOP) // STATE_IDLE 112 | begin 113 | state <= TXUL_IDLE; 114 | r_busy <= 1'b0; 115 | if ((i_wr)&&(!r_busy)) 116 | begin // Immediately start us off with a start bit 117 | r_busy <= 1'b1; 118 | state <= TXUL_BIT_ZERO; 119 | end 120 | end else begin 121 | // One clock tick in each of these states ... 122 | r_busy <= 1'b1; 123 | if (state <=TXUL_STOP) // start bit, 8-d bits, stop-b 124 | state <= state + 1'b1; 125 | else 126 | state <= TXUL_IDLE; 127 | end 128 | // }}} 129 | 130 | // o_busy 131 | // {{{ 132 | // 133 | // This is a wire, designed to be true is we are ever busy above. 134 | // originally, this was going to be true if we were ever not in the 135 | // idle state. The logic has since become more complex, hence we have 136 | // a register dedicated to this and just copy out that registers value. 137 | assign o_busy = (r_busy); 138 | // }}} 139 | 140 | // lcl_data 141 | // {{{ 142 | // 143 | // This is our working copy of the i_data register which we use 144 | // when transmitting. It is only of interest during transmit, and is 145 | // allowed to be whatever at any other time. Hence, if r_busy isn't 146 | // true, we can always set it. On the one clock where r_busy isn't 147 | // true and i_wr is, we set it and r_busy is true thereafter. 148 | // Then, on any zero_baud_counter (i.e. change between baud intervals) 149 | // we simple logically shift the register right to grab the next bit. 150 | initial lcl_data = 8'hff; 151 | always @(posedge i_clk) 152 | if (i_reset) 153 | lcl_data <= 8'hff; 154 | else if (i_wr && !r_busy) 155 | lcl_data <= i_data; 156 | else if (zero_baud_counter) 157 | lcl_data <= { 1'b1, lcl_data[7:1] }; 158 | // }}} 159 | 160 | // o_uart_tx 161 | // {{{ 162 | // 163 | // This is the final result/output desired of this core. It's all 164 | // centered about o_uart_tx. This is what finally needs to follow 165 | // the UART protocol. 166 | // 167 | initial o_uart_tx = 1'b1; 168 | always @(posedge i_clk) 169 | if (i_reset) 170 | o_uart_tx <= 1'b1; 171 | else if (i_wr && !r_busy) 172 | o_uart_tx <= 1'b0; // Set the start bit on writes 173 | else if (zero_baud_counter) // Set the data bit. 174 | o_uart_tx <= lcl_data[0]; 175 | // }}} 176 | 177 | // Baud counter 178 | // {{{ 179 | // All of the above logic is driven by the baud counter. Bits must last 180 | // CLOCKS_PER_BAUD in length, and this baud counter is what we use to 181 | // make certain of that. 182 | // 183 | // The basic logic is this: at the beginning of a bit interval, start 184 | // the baud counter and set it to count CLOCKS_PER_BAUD. When it gets 185 | // to zero, restart it. 186 | // 187 | // However, comparing a 28'bit number to zero can be rather complex-- 188 | // especially if we wish to do anything else on that same clock. For 189 | // that reason, we create "zero_baud_counter". zero_baud_counter is 190 | // nothing more than a flag that is true anytime baud_counter is zero. 191 | // It's true when the logic (above) needs to step to the next bit. 192 | // Simple enough? 193 | // 194 | // I wish we could stop there, but there are some other (ugly) 195 | // conditions to deal with that offer exceptions to this basic logic. 196 | // 197 | // 1. When the user has commanded a BREAK across the line, we need to 198 | // wait several baud intervals following the break before we start 199 | // transmitting, to give any receiver a chance to recognize that we are 200 | // out of the break condition, and to know that the next bit will be 201 | // a stop bit. 202 | // 203 | // 2. A reset is similar to a break condition--on both we wait several 204 | // baud intervals before allowing a start bit. 205 | // 206 | // 3. In the idle state, we stop our counter--so that upon a request 207 | // to transmit when idle we can start transmitting immediately, rather 208 | // than waiting for the end of the next (fictitious and arbitrary) baud 209 | // interval. 210 | // 211 | // When (i_wr)&&(!r_busy)&&(state == TXUL_IDLE) then we're not only in 212 | // the idle state, but we also just accepted a command to start writing 213 | // the next word. At this point, the baud counter needs to be reset 214 | // to the number of CLOCKS_PER_BAUD, and zero_baud_counter set to zero. 215 | // 216 | // The logic is a bit twisted here, in that it will only check for the 217 | // above condition when zero_baud_counter is false--so as to make 218 | // certain the STOP bit is complete. 219 | initial zero_baud_counter = 1'b1; 220 | initial baud_counter = 0; 221 | always @(posedge i_clk) 222 | if (i_reset) 223 | begin 224 | zero_baud_counter <= 1'b1; 225 | baud_counter <= 0; 226 | end else begin 227 | zero_baud_counter <= (baud_counter == 1); 228 | 229 | if (state == TXUL_IDLE) 230 | begin 231 | baud_counter <= 0; 232 | zero_baud_counter <= 1'b1; 233 | if ((i_wr)&&(!r_busy)) 234 | begin 235 | baud_counter <= CLOCKS_PER_BAUD - 1'b1; 236 | zero_baud_counter <= 1'b0; 237 | end 238 | end else if (!zero_baud_counter) 239 | baud_counter <= baud_counter - 1'b1; 240 | else if (state > TXUL_STOP) 241 | begin 242 | baud_counter <= 0; 243 | zero_baud_counter <= 1'b1; 244 | end else if (state == TXUL_STOP) 245 | // Need to complete this state one clock early, so 246 | // we can release busy one clock before the stop bit 247 | // is complete, so we can start on the next byte 248 | // exactly 10*CLOCKS_PER_BAUD clocks after we started 249 | // the last one 250 | baud_counter <= CLOCKS_PER_BAUD - 2; 251 | else // All other states 252 | baud_counter <= CLOCKS_PER_BAUD - 1'b1; 253 | end 254 | // }}} 255 | //////////////////////////////////////////////////////////////////////////////// 256 | //////////////////////////////////////////////////////////////////////////////// 257 | //////////////////////////////////////////////////////////////////////////////// 258 | // 259 | // FORMAL METHODS 260 | // {{{ 261 | //////////////////////////////////////////////////////////////////////////////// 262 | //////////////////////////////////////////////////////////////////////////////// 263 | //////////////////////////////////////////////////////////////////////////////// 264 | `ifdef FORMAL 265 | // Declarations 266 | `ifdef TXUARTLITE 267 | `define ASSUME assume 268 | `else 269 | `define ASSUME assert 270 | `endif 271 | reg f_past_valid, f_last_clk; 272 | reg [(TB-1):0] f_baud_count; 273 | reg [9:0] f_txbits; 274 | reg [3:0] f_bitcount; 275 | reg [7:0] f_request_tx_data; 276 | wire [3:0] subcount; 277 | 278 | // Setup 279 | // {{{ 280 | initial f_past_valid = 1'b0; 281 | always @(posedge i_clk) 282 | f_past_valid <= 1'b1; 283 | 284 | initial `ASSUME(!i_wr); 285 | always @(posedge i_clk) 286 | if ((f_past_valid)&&($past(i_wr))&&($past(o_busy))) 287 | begin 288 | `ASSUME(i_wr == $past(i_wr)); 289 | `ASSUME(i_data == $past(i_data)); 290 | end 291 | // }}} 292 | 293 | // Check the baud counter 294 | // {{{ 295 | always @(posedge i_clk) 296 | assert(zero_baud_counter == (baud_counter == 0)); 297 | 298 | always @(posedge i_clk) 299 | if (f_past_valid && !$past(i_reset) && $past(baud_counter != 0) 300 | && $past(state != TXUL_IDLE)) 301 | assert(baud_counter == $past(baud_counter - 1'b1)); 302 | 303 | always @(posedge i_clk) 304 | if (f_past_valid && !$past(i_reset) && !$past(zero_baud_counter) 305 | && $past(state != TXUL_IDLE)) 306 | assert($stable(o_uart_tx)); 307 | 308 | initial f_baud_count = 1'b0; 309 | always @(posedge i_clk) 310 | if (zero_baud_counter) 311 | f_baud_count <= 0; 312 | else 313 | f_baud_count <= f_baud_count + 1'b1; 314 | 315 | always @(posedge i_clk) 316 | assert(f_baud_count < CLOCKS_PER_BAUD); 317 | 318 | always @(posedge i_clk) 319 | if (baud_counter != 0) 320 | assert(o_busy); 321 | // }}} 322 | 323 | // {{{ 324 | initial f_txbits = 0; 325 | always @(posedge i_clk) 326 | if (zero_baud_counter) 327 | f_txbits <= { o_uart_tx, f_txbits[9:1] }; 328 | 329 | always @(posedge i_clk) 330 | if (f_past_valid && !$past(i_reset)&& !$past(zero_baud_counter) 331 | && !$past(state==TXUL_IDLE)) 332 | assert(state == $past(state)); 333 | 334 | initial f_bitcount = 0; 335 | always @(posedge i_clk) 336 | if ((!f_past_valid)||(!$past(f_past_valid))) 337 | f_bitcount <= 0; 338 | else if ((state == TXUL_IDLE)&&(zero_baud_counter)) 339 | f_bitcount <= 0; 340 | else if (zero_baud_counter) 341 | f_bitcount <= f_bitcount + 1'b1; 342 | 343 | always @(posedge i_clk) 344 | assert(f_bitcount <= 4'ha); 345 | 346 | always @(*) 347 | if (!o_busy) 348 | assert(zero_baud_counter); 349 | 350 | always @(posedge i_clk) 351 | if ((i_wr)&&(!o_busy)) 352 | f_request_tx_data <= i_data; 353 | 354 | assign subcount = 10-f_bitcount; 355 | always @(posedge i_clk) 356 | if (f_bitcount > 0) 357 | assert(!f_txbits[subcount]); 358 | 359 | always @(posedge i_clk) 360 | if (f_bitcount == 4'ha) 361 | begin 362 | assert(f_txbits[8:1] == f_request_tx_data); 363 | assert( f_txbits[9]); 364 | end 365 | 366 | always @(posedge i_clk) 367 | assert((state <= TXUL_STOP + 1'b1)||(state == TXUL_IDLE)); 368 | 369 | always @(posedge i_clk) 370 | if ((f_past_valid)&&($past(f_past_valid))&&($past(o_busy))) 371 | cover(!o_busy); 372 | // }}} 373 | 374 | `endif // FORMAL 375 | `ifdef VERIFIC_SVA 376 | reg [7:0] fsv_data; 377 | 378 | // 379 | // Grab a copy of the data any time we are sent a new byte to transmit 380 | // We'll use this in a moment to compare the item transmitted against 381 | // what is supposed to be transmitted 382 | // 383 | always @(posedge i_clk) 384 | if ((i_wr)&&(!o_busy)) 385 | fsv_data <= i_data; 386 | 387 | // 388 | // One baud interval 389 | // {{{ 390 | // 391 | // 1. The UART output is constant at DAT 392 | // 2. The internal state remains constant at ST 393 | // 3. CKS = the number of clocks per bit. 394 | // 395 | // Everything stays constant during the CKS clocks with the exception 396 | // of (zero_baud_counter), which is *only* raised on the last clock 397 | // interval 398 | sequence BAUD_INTERVAL(CKS, DAT, SR, ST); 399 | ((o_uart_tx == DAT)&&(state == ST) 400 | &&(lcl_data == SR) 401 | &&(!zero_baud_counter))[*(CKS-1)] 402 | ##1 (o_uart_tx == DAT)&&(state == ST) 403 | &&(lcl_data == SR) 404 | &&(zero_baud_counter); 405 | endsequence 406 | // }}} 407 | 408 | // 409 | // One byte transmitted 410 | // {{{ 411 | // 412 | // DATA = the byte that is sent 413 | // CKS = the number of clocks per bit 414 | // 415 | sequence SEND(CKS, DATA); 416 | BAUD_INTERVAL(CKS, 1'b0, DATA, 4'h0) 417 | ##1 BAUD_INTERVAL(CKS, DATA[0], {{(1){1'b1}},DATA[7:1]}, 4'h1) 418 | ##1 BAUD_INTERVAL(CKS, DATA[1], {{(2){1'b1}},DATA[7:2]}, 4'h2) 419 | ##1 BAUD_INTERVAL(CKS, DATA[2], {{(3){1'b1}},DATA[7:3]}, 4'h3) 420 | ##1 BAUD_INTERVAL(CKS, DATA[3], {{(4){1'b1}},DATA[7:4]}, 4'h4) 421 | ##1 BAUD_INTERVAL(CKS, DATA[4], {{(5){1'b1}},DATA[7:5]}, 4'h5) 422 | ##1 BAUD_INTERVAL(CKS, DATA[5], {{(6){1'b1}},DATA[7:6]}, 4'h6) 423 | ##1 BAUD_INTERVAL(CKS, DATA[6], {{(7){1'b1}},DATA[7:7]}, 4'h7) 424 | ##1 BAUD_INTERVAL(CKS, DATA[7], 8'hff, 4'h8) 425 | ##1 BAUD_INTERVAL(CKS-1, 1'b1, 8'hff, 4'h9); 426 | endsequence 427 | // }}} 428 | 429 | // 430 | // Transmit one byte 431 | // {{{ 432 | // Once the byte is transmitted, make certain we return to 433 | // idle 434 | // 435 | assert property ( 436 | @(posedge i_clk) 437 | (i_wr)&&(!o_busy) 438 | |=> ((o_busy) throughout SEND(CLOCKS_PER_BAUD,fsv_data)) 439 | ##1 (!o_busy)&&(o_uart_tx)&&(zero_baud_counter)); 440 | // }}} 441 | 442 | // {{{ 443 | assume property ( 444 | @(posedge i_clk) 445 | (i_wr)&&(o_busy) |=> 446 | (i_wr)&&($stable(i_data))); 447 | 448 | // 449 | // Make certain that o_busy is true any time zero_baud_counter is 450 | // non-zero 451 | // 452 | always @(*) 453 | assert((o_busy)||(zero_baud_counter) ); 454 | 455 | // If and only if zero_baud_counter is true, baud_counter must be zero 456 | // Insist on that relationship here. 457 | always @(*) 458 | assert(zero_baud_counter == (baud_counter == 0)); 459 | 460 | // To make certain baud_counter stays below CLOCKS_PER_BAUD 461 | always @(*) 462 | assert(baud_counter < CLOCKS_PER_BAUD); 463 | 464 | // 465 | // Insist that we are only ever in a valid state 466 | always @(*) 467 | assert((state <= TXUL_STOP+1'b1)||(state == TXUL_IDLE)); 468 | // }}} 469 | 470 | `endif // Verific SVA 471 | // }}} 472 | endmodule 473 | -------------------------------------------------------------------------------- /rtl/ufifo.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Filename: ufifo.v 4 | // {{{ 5 | // Project: wbuart32, a full featured UART with simulator 6 | // 7 | // Purpose: A synchronous data FIFO, designed for supporting the Wishbone 8 | // UART. Particular features include the ability to read and 9 | // write on the same clock, while maintaining the correct output FIFO 10 | // parameters. Two versions of the FIFO exist within this file, separated 11 | // by the RXFIFO parameter's value. One, where RXFIFO = 1, produces status 12 | // values appropriate for reading and checking a read FIFO from logic, 13 | // whereas the RXFIFO = 0 applies to writing to the FIFO from bus logic 14 | // and reading it automatically any time the transmit UART is idle. 15 | // 16 | // Creator: Dan Gisselquist, Ph.D. 17 | // Gisselquist Technology, LLC 18 | // 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // }}} 21 | // Copyright (C) 2015-2024, Gisselquist Technology, LLC 22 | // {{{ 23 | // This program is free software (firmware): you can redistribute it and/or 24 | // modify it under the terms of the GNU General Public License as published 25 | // by the Free Software Foundation, either version 3 of the License, or (at 26 | // your option) any later version. 27 | // 28 | // This program is distributed in the hope that it will be useful, but WITHOUT 29 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or 30 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31 | // for more details. 32 | // 33 | // You should have received a copy of the GNU General Public License along 34 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no 35 | // target there if the PDF file isn't present.) If not, see 36 | // for a copy. 37 | // }}} 38 | // License: GPL, v3, as defined and found on www.gnu.org, 39 | // {{{ 40 | // http://www.gnu.org/licenses/gpl.html 41 | // 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // 45 | `default_nettype none 46 | // }}} 47 | module ufifo #( 48 | // {{{ 49 | parameter BW=8, // Byte/data width 50 | parameter [3:0] LGFLEN=4, 51 | parameter [0:0] RXFIFO=1'b1, 52 | localparam FLEN=(1< for a copy. 39 | // }}} 40 | // License: GPL, v3, as defined and found on www.gnu.org, 41 | // {{{ 42 | // http://www.gnu.org/licenses/gpl.html 43 | // 44 | //////////////////////////////////////////////////////////////////////////////// 45 | // 46 | // }}} 47 | 48 | 49 | // Ideally, UART_SETUP is defined somewhere. I commonly like to define 50 | // it to CLKRATE / BAUDRATE, to give me 8N1 performance. 4MB is useful 51 | // to me, so 100MHz / 4M = 25 could be the setup. You can also use 52 | // 200MHz / 4MB = 50 ... it all depends upon your clock. 53 | `define UART_SETUP 31'd25 54 | reg [30:0] uart_setup; 55 | initial uart_setup = `UART_SETUP; 56 | always @(posedge i_clk) 57 | if ((i_wb_stb)&&(i_wb_addr == `UART_SETUP_ADDR)) 58 | uart_setup[30:0] <= i_wb_data[30:0]; 59 | 60 | // 61 | // First the UART receiver 62 | // 63 | wire rx_stb, rx_break, rx_perr, rx_ferr, ck_uart; 64 | wire [7:0] rx_data_port; 65 | rxuart #(UART_SETUP) rx(i_clk, 1'b0, uart_setup, i_rx, 66 | rx_stb, rx_data_port, rx_break, 67 | rx_perr, rx_ferr, ck_uart); 68 | 69 | wire [31:0] rx_data; 70 | reg [11:0] r_rx_data; 71 | always @(posedge i_clk) 72 | if (rx_stb) 73 | begin 74 | r_rx_data[11] <= (r_rx_data[11])||(rx_break); 75 | r_rx_data[10] <= (r_rx_data[10])||(rx_ferr); 76 | r_rx_data[ 9] <= (r_rx_data[ 9])||(rx_perr); 77 | r_rx_data[7:0]<= rx_data_port; 78 | end else if ((i_wb_stb)&&(i_wb_we) 79 | &&(i_wb_addr == `UART_RX_ADDR)) 80 | begin 81 | r_rx_data[11] <= (rx_break)&& (!i_wb_data[11]); 82 | r_rx_data[10] <= (rx_ferr) && (!i_wb_data[10]); 83 | r_rx_data[ 9] <= (rx_perr) && (!i_wb_data[ 9]); 84 | end 85 | always @(posedge i_clk) 86 | if(((i_wb_stb)&&(!i_wb_we)&&(i_wb_addr == `UART_RX_ADDR)) 87 | ||(rx_stb)) 88 | r_rx_data[8] <= !rx_stb; 89 | assign o_rts_n = r_rx_data[8]; 90 | assign rx_data = { 20'h00, r_rx_data }; 91 | assign rx_int = !r_rx_data[8]; 92 | 93 | // Transmit hardware flow control, the cts line 94 | wire cts_n; 95 | // Set this cts value to zero if you aren't ever going to use H/W flow 96 | // control, otherwise set it to the value coming in from the external 97 | // i_cts_n pin. 98 | assign cts_n = i_cts_n; 99 | 100 | // 101 | // Then the UART transmitter 102 | // 103 | // 104 | // 105 | // Now onto the transmitter itself 106 | wire tx_busy; 107 | reg [7:0] r_tx_data; 108 | reg r_tx_stb, r_tx_break; 109 | wire [31:0] tx_data; 110 | txuart #(UART_SETUP) tx(i_clk, 1'b0, uart_setup, 111 | r_tx_break, r_tx_stb, r_tx_data, 112 | cts_n, o_tx, tx_busy); 113 | always @(posedge i_clk) 114 | if ((i_wb_stb)&&(i_wb_addr == 5'h0f)) 115 | begin 116 | r_tx_stb <= (!r_tx_break)&&(!i_wb_data[8]); 117 | r_tx_data <= i_wb_data[7:0]; 118 | r_tx_break<= i_wb_data[9]; 119 | end else if (!tx_busy) 120 | begin 121 | r_tx_stb <= 1'b0; 122 | r_tx_data <= 8'h0; 123 | end 124 | assign tx_data = { 16'h00, cts_n, 3'h0, 125 | ck_uart, o_tx, r_tx_break, tx_busy, 126 | r_tx_data }; 127 | assign tx_int = ~tx_busy; 128 | 129 | always @(posedge i_clk) 130 | case(i_wb_addr) 131 | `UART_SETUP_ADDR: o_wb_data <= { 1'b0, uart_setup }; 132 | `UART_RX_ADDR : o_wb_data <= rx_data; 133 | `UART_TX_ADDR : o_wb_data <= tx_data; 134 | // 135 | // The rest of these address slots are left open here for 136 | // whatever else you might wish to connect to this bus/STB 137 | // line 138 | default: o_wb_data <= 32'h00; 139 | endcase 140 | 141 | assign o_wb_stall = 1'b0; 142 | always @(posedge i_clk) 143 | o_wb_ack <= (i_wb_stb); 144 | 145 | // Interrupts sent to the board from here 146 | assign o_board_ints = { rx_int, tx_int /* any other from this module */}; 147 | 148 | -------------------------------------------------------------------------------- /wbuart32.core: -------------------------------------------------------------------------------- 1 | CAPI=1 2 | [main] 3 | description = A full featured UART with Simulator 4 | simulators = verilator 5 | 6 | [fileset rtl] 7 | files = 8 | rtl/rxuartlite.v 9 | rtl/txuartlite.v 10 | rtl/rxuart.v 11 | rtl/txuart.v 12 | rtl/ufifo.v 13 | rtl/wbuart.v 14 | file_type = verilogSource 15 | 16 | [verilator] 17 | verilator_options = 18 | tb_toplevel = bench/cpp/linetest.cpp 19 | top_module = linetest 20 | source_type = CPP 21 | src_files = bench/cpp/linetest.cpp bench/cpp/uartsim.cpp 22 | include_files = bench/cpp/uartsim.h 23 | 24 | [fileset tb_files] 25 | files = bench/verilog/linetest.v 26 | usage = verilator 27 | file_type = verilogSource 28 | scope = private 29 | 30 | --------------------------------------------------------------------------------