├── doc
├── spec.pdf
├── uart.png
├── gpl-3.0.pdf
├── gfx
│ ├── ambiguous.png
│ └── logic-timing.png
├── src
│ ├── GT.eps
│ └── gqtekspec.cls
└── Makefile
├── bench
├── formal
│ ├── .gitignore
│ ├── txuart.sby
│ ├── ufifo.sby
│ ├── txuartlite.sby
│ ├── rxuartlite.sby
│ ├── axiluart.sby
│ ├── report.html
│ ├── axiluart.gtkw
│ ├── Makefile
│ └── genreport.pl
├── cpp
│ ├── .gitignore
│ ├── README.md
│ ├── speech.txt
│ ├── helloworld.cpp
│ ├── uartsim.h
│ ├── mkspeech.cpp
│ ├── uartsim.cpp
│ ├── linetest.cpp
│ ├── Makefile
│ └── speechtest.cpp
├── README.md
└── verilog
│ ├── README.md
│ ├── Makefile
│ ├── helloworld.v
│ ├── echotest.v
│ ├── linetest.v
│ └── speechfifo.v
├── .gitignore
├── wbuart32.core
├── Makefile
├── rtl
├── Makefile
├── wbuart-insert.v
├── skidbuffer.v
├── ufifo.v
├── txuartlite.v
└── rxuart.v
└── README.md
/doc/spec.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZipCPU/wbuart32/HEAD/doc/spec.pdf
--------------------------------------------------------------------------------
/doc/uart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZipCPU/wbuart32/HEAD/doc/uart.png
--------------------------------------------------------------------------------
/doc/gpl-3.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZipCPU/wbuart32/HEAD/doc/gpl-3.0.pdf
--------------------------------------------------------------------------------
/doc/gfx/ambiguous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZipCPU/wbuart32/HEAD/doc/gfx/ambiguous.png
--------------------------------------------------------------------------------
/doc/gfx/logic-timing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZipCPU/wbuart32/HEAD/doc/gfx/logic-timing.png
--------------------------------------------------------------------------------
/bench/formal/.gitignore:
--------------------------------------------------------------------------------
1 | rxuartlite_*/
2 | txuartlite_*/
3 | ufifo_*/
4 | ctrtest
5 | txuart
6 | axiluart_*/
7 |
--------------------------------------------------------------------------------
/bench/cpp/.gitignore:
--------------------------------------------------------------------------------
1 | mkspeech
2 | helloworld
3 | helloworldlite
4 | linetest
5 | linetestlite
6 | speechtest
7 | speechtestlite
8 | *.vcd
9 | obj-pc/*
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/formal/report.html:
--------------------------------------------------------------------------------
1 |
Formal Verification Report
2 |
3 | Wishbone UART Verification Report
4 | 20240112
5 |
6 | | Status | Component | Proof | Component description |
7 |
8 | | Pass | axiluart | _prf | AXI-Lite UART peripheral |
9 | | 6 Cover points | axiluart | _cvr |
10 | | Pass | axiluart | _prfs |
11 | | 6 Cover points | axiluart | _cvrs |
12 |
13 | | Pass | rxuartlite | _prf | UART Receiver, lite version |
14 | | 13 Cover points | rxuartlite | _cvr |
15 |
16 | | 1 Cover points | txuartlite | _cvr | UART Transmitter, lite version |
17 | | Pass | txuartlite | _prf |
18 |
19 | | Pass | ufifo | _prf | A synchronous FIFO supporting the UART |
20 | | 3 Cover points | ufifo | _cvr |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/rtl/wbuart-insert.v:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: wbuart-insert.v
4 | // {{{
5 | // Project: wbuart32, a full featured UART with simulator
6 | //
7 | // Purpose: This is not a module file. It is an example of the types of
8 | // lines and connections which can be used to connect this UART
9 | // to a local wishbone bus. It was drawn from a working file, and
10 | // modified here for show, so ... let me know if I messed anything up
11 | // along the way.
12 | //
13 | // Why isn't this a full module file? Because I tend to lump all of my
14 | // single cycle I/O peripherals into one module file. It makes the logic
15 | // simpler. This particular file was extracted from the fastio.v file
16 | // within the openarty project.
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 |
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 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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 | | Status | Component | Proof | Component description |
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("| DIR $dent |
\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("| $dent matches $prf |
\n");
204 | ## }}}
205 |
206 | ## Get the resulting status
207 | $st = getstatus($dent);
208 | # print("| STATUS = $st |
\n");
209 |
210 | ## Fill out one entry of our table
211 | ## {{{
212 | my $tail;
213 | if ($firstd) {
214 | print "
\n";
215 | $tail = "$prf | $subprf | $desc{$prf} | \n";
216 | $firstd = 0;
217 | } else {
218 | $tail = "$prf | $subprf | \n";
219 | }
220 | if ($st =~ /PASS/) {
221 | print "| 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} |
\n";
252 | }
253 | }
254 |
255 | ## Finish the HTML log file
256 | ## {{{
257 | print <<"EOM";
258 |
259 |
260 | EOM
261 | ## }}}
262 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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.
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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------