├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── bits ├── README.md └── exercises.py ├── docs ├── _config.yml ├── _layouts │ └── default.html ├── bg.png ├── counter.png ├── dff.dia ├── dff1.png ├── dff2.png ├── dff3-0.png ├── dff3-1.png ├── fpga.md ├── gates.dia ├── gates.pdf ├── index.md ├── traffic.png └── verilog.md └── verilog ├── Makefile ├── adder.v ├── adder_tb.v ├── blinky_bx.v ├── blinky_icebreaker.v ├── blinky_icestick.v ├── button.v ├── counter.v ├── counter_tb.v ├── dff.v ├── dff_tb.v ├── oled_pattern.v ├── oled_pattern_color.v ├── oled_play.v ├── serial.v ├── serial_tb.v ├── spoilers ├── adder.v ├── counter.v ├── keypad.v ├── serial.v ├── traffic.v └── traffic2.v ├── traffic.v ├── traffic_tb.v ├── uart.py └── uart_hello.v /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.out 3 | *.vcd 4 | *.d 5 | build/ 6 | /docs/_site 7 | /docs/.sass-cache 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "verilog/fpga-tools"] 2 | path = verilog/fpga-tools 3 | url = https://github.com/pwmarcz/fpga-tools 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Paweł Marczewski 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FPGA tutorial 2 | 3 | See the tutorial at [pwmarcz.github.io/fpga-tutorial/](https://pwmarcz.github.io/fpga-tutorial/), 4 | or just look into the [docs](docs/) directory. 5 | 6 | The code is MIT licensed (see LICENSE) unless otherwise stated in the 7 | file. Patches welcome! 8 | -------------------------------------------------------------------------------- /bits/README.md: -------------------------------------------------------------------------------- 1 | # Bit operations 2 | 3 | Here are a few exercises on bit operations. 4 | 5 | ## Running the solutions 6 | 7 | Edit `exercises.py`. Then load the code in Python interpreter: 8 | 9 | python3 -i exercises.py 10 | 11 | >>> hex(replace_lowest_byte(0xabcd, 12)) 12 | '0x0' 13 | 14 | ## Running the tests 15 | 16 | I recommend `pytest`. You can install it using: 17 | 18 | pip3 install --user pytest 19 | 20 | Then just run: 21 | 22 | pytest --doctest-modules -v exercises.py 23 | 24 | This will run all the examples in the file. 25 | 26 | ### Cheatsheet 27 | 28 | and: a & b 29 | or: a | b 30 | xor: a ^ b 31 | not: ~a 32 | 33 | shift left: a << b 34 | shift right: a >> b 35 | 36 | You can write the numbers as hexadecimal and binary: 37 | 38 | 0x12EF, 0xabcd, 0b10101010 39 | 40 | Octal (`Oo666`) is also supported but you shouldn't need it. 41 | 42 | Printing the numbers to hexadecimal and binary: 43 | 44 | >>> hex(127) 45 | 0x7f 46 | 47 | >>> bin(42) 48 | 0b101010 49 | 50 | You can also insert _ for readability: 51 | 52 | 0b1010_1111_0000_0001 53 | 54 | ### Useful links 55 | 56 | - [Bit Manipulation](https://www.youtube.com/watch?v=7jkIUgLC29I) video by Make 57 | School 58 | - [HackerEarth: Basics of bit manipulation](https://www.hackerearth.com/practice/basic-programming/bit-manipulation/basics-of-bit-manipulation/tutorial/) 59 | -------------------------------------------------------------------------------- /bits/exercises.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | You can run all the examples below using: 4 | 5 | pytest --doctest-modules -v exercises.py 6 | ''' 7 | 8 | 9 | def combine_two_bytes(b1, b2): 10 | ''' 11 | Combine two bytes into a word: 12 | 13 | >>> hex(combine_two_bytes(0xff, 0x12)) 14 | '0xff12' 15 | 16 | >>> hex(combine_two_bytes(0, 0x32)) 17 | '0x32' 18 | ''' 19 | 20 | return 0 21 | 22 | 23 | def split_ip_address(ip): 24 | ''' 25 | Split a 4-byte number (IP address) into four numbers. 26 | 27 | >>> split_ip_address(0xc0a80164) 28 | (192, 168, 1, 100) 29 | 30 | >>> split_ip_address(0x7f000001) 31 | (127, 0, 0, 1) 32 | 33 | >>> split_ip_address(0x08080808) 34 | (8, 8, 8, 8) 35 | ''' 36 | 37 | return (0, 0, 0, 0) 38 | 39 | 40 | def flip_bit(a, n): 41 | ''' 42 | Flip the Nth bit in a number (where 0 is the least significant bit). 43 | 44 | >>> bin(flip_bit(0b11111, 1)) 45 | '0b11101' 46 | 47 | >>> bin(flip_bit(0b10000, 2)) 48 | '0b10100' 49 | ''' 50 | 51 | return 0 52 | 53 | 54 | def clear_bit(a, n): 55 | ''' 56 | Clear the Nth bit in a number (where 0 is the least significant bit). 57 | 58 | >>> bin(clear_bit(0b11111, 1)) 59 | '0b11101' 60 | 61 | >>> bin(clear_bit(0b11011, 2)) 62 | '0b11011' 63 | ''' 64 | 65 | return 0 66 | 67 | 68 | def count_bits(a): 69 | ''' 70 | Count how many bits are set in a number. 71 | 72 | >>> count_bits(0) 73 | 0 74 | 75 | >>> count_bits(0x7FFF) 76 | 15 77 | 78 | >>> count_bits(0b101010) 79 | 3 80 | ''' 81 | 82 | return 0 83 | 84 | 85 | def replace_lowest_byte(a, b): 86 | ''' 87 | Replace the lowest byte of a with b. 88 | 89 | >>> hex(replace_lowest_byte(0xabcd, 0)) 90 | '0xab00' 91 | 92 | >>> hex(replace_lowest_byte(0xabcd, 0x12)) 93 | '0xab12' 94 | ''' 95 | 96 | return 0 97 | 98 | 99 | def bit_mask(n): 100 | ''' 101 | Return a number consisting of 1s in N lowest positions. 102 | 103 | >>> bin(bit_mask(4)) 104 | '0b1111' 105 | 106 | >>> bin(bit_mask(7)) 107 | '0b1111111' 108 | ''' 109 | 110 | return 0 111 | 112 | 113 | def n_lowest(a, n): 114 | ''' 115 | Truncate a number to N lowest bits. 116 | 117 | >>> bin(n_lowest(0b100100, 3)) 118 | '0b100' 119 | 120 | >>> hex(n_lowest(0xdeadbeef, 16)) 121 | '0xbeef' 122 | ''' 123 | 124 | return 0 125 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate 2 | title: FPGA tutorial 3 | defaults: 4 | - scope: 5 | path: "" # an empty string here means all files in the project 6 | values: 7 | layout: "default" 8 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 40 | {{ page.title }} | {{ site.title }} 41 | 42 | 43 | 44 | 45 | 46 |
47 |
48 | View on GitHub 49 | 50 |

{{ site.title | default: site.github.repository_name }}

51 |
52 |
53 | 54 | 55 |
56 |
57 | {{ content }} 58 |
59 |
60 | 61 | 62 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /docs/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/bg.png -------------------------------------------------------------------------------- /docs/counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/counter.png -------------------------------------------------------------------------------- /docs/dff.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/dff.dia -------------------------------------------------------------------------------- /docs/dff1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/dff1.png -------------------------------------------------------------------------------- /docs/dff2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/dff2.png -------------------------------------------------------------------------------- /docs/dff3-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/dff3-0.png -------------------------------------------------------------------------------- /docs/dff3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/dff3-1.png -------------------------------------------------------------------------------- /docs/fpga.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FPGA 3 | --- 4 | 5 | # FPGA 6 | 7 | We'll be working in the `verilog` directory. 8 | 9 | ## Setup 10 | 11 | 1. You will need Verilog setup from the [previous step](verilog.html). Remember 12 | to also initialize the Git submodule with libraries: 13 | 14 | git submodule update --init 15 | 16 | 2. Then, install the [Icestorm toolchain](http://www.clifford.at/icestorm/). The 17 | easiest way is using the [apio](https://github.com/FPGAwars/apio) project: 18 | 19 | pip3 install --user apio 20 | apio install icestorm 21 | 22 | This will download and unpack the necessary software in your home directory 23 | (under `~/.apio`). If you want to run the tools directly (not only from 24 | Makefile), add the toolchain to your `PATH`, for instance in your `.bashrc`: 25 | 26 | export PATH="$HOME/.apio/packages/toolchain-icestorm/bin/:$PATH" 27 | 28 | 3. Under Linux, add yourself to the `dialout` group so that you can connect to the 29 | chip without sudo: (TODO: This doesn't seem to work for everyone, use 30 | `USE_SUDO=1`) 31 | 32 | sudo adduser $USER dialout 33 | 34 | You will need to log out and log in again. 35 | 36 | 4. Now try uploading a design. Connect the Icestick board, and run: 37 | 38 | make flash V=blinky_icestick.v 39 | 40 | If for some reason you need sudo, append `USE_SUDO=1`. 41 | 42 | If you encounter problems under Mac OS X, see [Project IceStorm – Notes for 43 | Installing on OSX](http://www.clifford.at/icestorm/notes_osx.html). 44 | You will probably need to unload Apple's FTDI driver: 45 | 46 | sudo kextunload com.apple.driver.AppleUSBFTDI 47 | 48 | 5. For the TinyFPGA BX board, you need to additionally do the following: 49 | 50 | pip3 install --user tinyprog 51 | apio drivers --serial-enable 52 | 53 | ## Building and flashing 54 | 55 | To upload a design, use `make flash`. For example: 56 | 57 | make flash V=blinky_icestick.v 58 | 59 | For the TinyFPGA BX module, you need to set `BOARD=bx` flag: 60 | 61 | make flash V=blinky_bx.v BOARD=bx 62 | 63 | Same for the IceBreaker module: 64 | 65 | make flash V=blinky_icebreaker.v BOARD=icebreaker 66 | 67 | (Append `USE_SUDO=1` if you need to use sudo). 68 | 69 | The build process has the following steps: 70 | 71 | 1. Logic synthesis, using `yosys`. This produces a `.blif` file with your 72 | design compiled down to components available on the FPGA chip (look-up 73 | tables, flip-flops, block RAMs, etc.) 74 | 2. Place and route, using `arachne-pnr`. This produces `.asc` and then `.bin` 75 | files containing the final chip configuration (a bitstream). 76 | 3. Programming the chip, using `iceprog` / `tinyprog`. This uploads the `.bin` 77 | to the chip over USB. 78 | 79 | ## Pins 80 | 81 | You can find the available pins in 82 | [fpga-tools/pcf](https://github.com/pwmarcz/fpga-tools/tree/master/pcf) directory. Your module 83 | will need to reference these. 84 | 85 | Here are the pinouts for reference: 86 | 87 | - [iCEstick pinout](http://www.pighixxx.net/portfolio-items/icestick/) 88 | - [TinyFPGA BX pinout](https://www.crowdsupply.com/tinyfpga/tinyfpga-bx/updates/manufacturing-continues) 89 | - [IceBreaker pinout](https://raw.githubusercontent.com/icebreaker-fpga/icebreaker/master/img/icebreaker-v1_0b-legend.jpg) 90 | 91 | ## Ideas 92 | 93 | Here is a list of ideas that you can implement. You will find some hints 94 | regarding different parts in the next section. 95 | 96 | - **Counter**: Implement a counter that increases every second. The Icestick 97 | has 5 LEDs, you can use them to show an increasing 5-bit number. 98 | - Try connecting the segment display. 99 | - Connect a button. Make the counter increase not with time, but every time 100 | the button is pressed. Add a reset button. 101 | - **Traffic lights**: Implement the traffic lights example from the previous 102 | chapter. You will need three LEDs (don't forget the resistors!) and a button. 103 | - **Fade LEDs in and out** by implementing pulse-width modulation. 104 | - **Serial link**: Use the chip to communicate with computer over the serial 105 | link. 106 | - Memory buffer: Implement a chip that has a small memory buffer and responds 107 | to "read" and "write" commands. 108 | - **Screens**: Draw something on the screen. Create an animation. Send a 109 | picture over the serial link and draw it. 110 | - Pong game? 111 | - Game of Life demo. 112 | - Display text. [Unscii 8x8 bitmap fonts](http://pelulamu.net/unscii/) might 113 | come in handy, you can download the fonts in a hex format which is 114 | basically a one byte, one row bitmap. And here is a font [converted to 115 | column-by-column](https://github.com/pwmarcz/fpga-experiments/blob/master/font.mem) 116 | already. 117 | 118 | ## Parts 119 | 120 | Here are some parts you can use in your projects. 121 | 122 | ### Clock 123 | 124 | The Icestick has a 12 MHz clock signal, the BX a 16 MHz one. For changes that a 125 | human can notice, you will need to divide it to create a slower clock. See the 126 | `blinky` example. 127 | 128 | It's also possible to [get a faster clock using a 129 | PLL](https://stackoverflow.com/questions/43890771/how-to-get-a-faster-clock-in-verilog-on-a-lattice-icestick), 130 | but I haven't tried that yet. The `icetime` tool should tell you the maximum 131 | frequency for your design (run `make time`). Use `icepll` to generate the 132 | right parameters for the PLL module. 133 | 134 | ### LEDs 135 | 136 | The Icestick has 5 LEDs, the BX has one. You can turn them on and off just by 137 | specifying the pins in module output. 138 | 139 | You can connect your own LEDs as well, just make sure to connect the right 140 | resistors. The voltage on pins is 3.3 V. 141 | 142 | ### Buttons and switches 143 | 144 | You will need a pull-down or pull-up resistor. See for instance the [button 145 | example for Arduino](https://www.arduino.cc/en/Tutorial/Button). 146 | 147 | You can also use a an internal pull-up from FPGA. See `button.v` on how to do 148 | that. 149 | 150 | ### Seven-segment display 151 | 152 | Here is a [spec sheet for the 153 | display](https://botland.com.pl/index.php?controller=attachment&id_attachment=1629). Ours 154 | has a common anode for all 4 digits. You will need to display the digits one at a time. Here is [a blog post on multiplexing 7 segment display](https://www.electronicsblog.net/4-digits-7-segments-led-display-multiplexing-with-arduino/). 155 | 156 | (TODO add more info once we try that) 157 | 158 | ### Serial link (UART) 159 | 160 | You can use the chip on Icestick to communicate with your computer over a 161 | serial connection (exposed as a second USB device; visible under `/dev/ttyUSB1` 162 | under Linux). 163 | 164 | See `uart_hello.v` for a simple program that sends "Hello, world!" 165 | repeatedly. You can use `uart.py` to receive the data. Here is the 166 | [documentation for pySerial 167 | library](https://pythonhosted.org/pyserial/pyserial_api.html). Remember to set 168 | the baud rate correctly on both ends! 169 | 170 | You can also use a serial terminal such as `gtkterm` (see for instance 171 | [Communicate with hardware using USB cable for 172 | Ubuntu](https://elinux.org/Communicate_with_hardware_using_USB_cable_for_Ubuntu)). 173 | 174 | Note that the module we're using, `uart.v`, is a [third-party software 175 | developed by Tim Goddard](https://github.com/cyrozap/osdvu). 176 | 177 | ### OLED displays 178 | 179 | I have two OLED screens: 180 | 181 | - "Two-color" (actually monochrome) 128x64 screen. The data is laid out in 8 182 | rows of 128 bytes each. Each row describes a 128x8 strip, each byte is a 1x8 183 | segment. 184 | - 65536-color 96x64 screen. Each pixel is 16 bits. Note that this is more 185 | memory that Icestick has on board (12 KB; the Icestick's block RAMs hold 8 KB 186 | total). 187 | 188 | See `oled_pattern.v` and `oled_pattern_color.v` for details on how to use. 189 | 190 | You might want to load some initial data into memory. You can use the 191 | [`$readmemh` 192 | function](https://timetoexplore.net/blog/initialize-memory-in-verilog) to do 193 | that. 194 | 195 | ## Links 196 | 197 | - [open-fpga-verilog-tutorial](https://github.com/Obijuan/open-fpga-verilog-tutorial/wiki/Chapter-0%3A-you-are-leaving-the-private-sector) - 198 | an excellent tutorial series, translated from Spanish 199 | - [ice40-examples](https://github.com/nesl/ice40_examples) 200 | - [migen](https://github.com/m-labs/migen) - a circuit generator in Python 201 | - [Lattice iCE40 LP/HX Family Data Sheet](http://www.latticesemi.com/view_document?document_id=49312) 202 | - [fpga4fun](https://www.fpga4fun.com/) - various project ideas: VGA, HDMI, SDRAM controller... 203 | - [Initializing memory in Verilog](https://timetoexplore.net/blog/initialize-memory-in-verilog) 204 | - [ICE40 layout viewer](https://knielsen.github.io/ice40_viewer/ice40_viewer.html), renders your .asc file 205 | -------------------------------------------------------------------------------- /docs/gates.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/gates.pdf -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FPGA tutorial 3 | --- 4 | 5 | Here are some materials for my FPGA workshop. The workshop uses the open source 6 | Icestorm toolchain. The hardware is a few Lattice boards (because that's what I 7 | have), as well as some peripherals like OLED displays. 8 | 9 | The code is MIT licensed (see LICENSE) unless otherwise stated in the 10 | file. Patches welcome! 11 | 12 | See also [fpga-experiments](https://github.com/pwmarcz/fpga-experiments) which 13 | is a very messy sandbox where I try out all this stuff. 14 | 15 | This tutorial has the following parts: 16 | 17 | ## [NandGame](http://nandgame.com/) 18 | 19 | Play the excellent [NandGame](http://nandgame.com/). Try to get at least to 20 | "Data Flip-Flop". 21 | 22 | ## [Bit operations](https://github.com/pwmarcz/fpga-tutorial/tree/master/bits) 23 | 24 | If you are not familiar with bit operations, learn a bit about them. There 25 | are some links and exercises in the [bits](https://github.com/pwmarcz/fpga-tutorial/tree/master/bits) directory. 26 | 27 | ## [Verilog](verilog.html) 28 | 29 | Move on to Verilog language. 30 | 31 | ## [FPGA](fpga.html) 32 | 33 | Finally, we get to play with real hardware. 34 | -------------------------------------------------------------------------------- /docs/traffic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwmarcz/fpga-tutorial/a5a191823e13d6c97c52b940e91614e8f663a1ac/docs/traffic.png -------------------------------------------------------------------------------- /docs/verilog.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Verilog 3 | --- 4 | 5 | # Verilog 6 | 7 | We'll be working in the `verilog` directory. 8 | 9 | There are some solutions in `verilog/spoilers`, but as the name suggests, you 10 | shouldn't look there before trying to solve the exercises yourself. 11 | 12 | ## Prerequisites 13 | 14 | First, initialize the Git submodule with libraries: 15 | 16 | git submodule update --init 17 | 18 | You will need the following: 19 | 20 | - An editor that understands Verilog. Atom or Sublime Text should be fine. 21 | - [Icarus Verilog](http://iverilog.icarus.com/). Your system should have it 22 | packaged: 23 | - `apt install iverilog` 24 | - `brew install icarus-verilog` 25 | - ... 26 | - Optionally [GTKWave](http://gtkwave.sourceforge.net/). This should also be 27 | available from your system. 28 | 29 | ## Makefile targets 30 | 31 | To run `adder_tb.v`, use: 32 | 33 | make run V=adder_tb.v 34 | 35 | To run `adder.v` and view the results in GTKWave, use: 36 | 37 | make sim V=adder_tb.v 38 | 39 | ## Adders 40 | 41 | ### On paper 42 | 43 | We'll try to add some binary numbers (101010 + 111). How does it work? Draw a 44 | single bit adder circuit, and connect 4 of them to have a 4-bit adder. 45 | 46 | Now we move on to hexadecimal addition. Try adding 7FFA + 3048. How does a 47 | single 4-bit adder look like, and how do we connect more of them? 48 | 49 | Let's look closer at a 4-bit adder. The adder will have the following ports: 50 | - input numbers (4 bit): `x`, `y`, 51 | - carry-in: `c_in`, 52 | - sum (4 bit): `s`, 53 | - carry-out: `c_out`. 54 | 55 | Trace what it will do for some inputs (for instance, 10 + 8). How would we 56 | write the adder in pseudocode? 57 | 58 | Now, let's try to design the same for decimal digits and BCD ([binary-coded 59 | decimals](https://en.wikipedia.org/wiki/Binary-coded_decimal)). What kind of 60 | inputs and outputs we'll have? Again, let's write pseudocode. 61 | 62 | ### In Verilog 63 | 64 | In `adder.v`, there is a 4-bit and 8-bit adder implemented. Run the 65 | testbench (`make run V=adder_tb.v`) and see the values. View the 66 | waveform (`make sim V=adder_tb.v`). 67 | 68 | Now, try to implement a BCD adder. Expand it to build a 4-digit (16-bit) BCD 69 | adder. Test it using the provided testbench. 70 | 71 | ## Latch and flip-flop 72 | 73 | Let's go back to [NAND game](http://www.nandgame.com/) and examine latch and 74 | data flip-flop. 75 | 76 | There is a simple data flip-flop (DFF) implemented in `dff.v`. Let's read it, 77 | and draw a wave diagram. 78 | 79 | Modify the testbench (`dff_tb.v`) to check if it works as it should. 80 | 81 | Now, create a data flip-flop with an `en` (enable) input. The value should 82 | change only if `en` is set to 1. Test it using the provided testbench. 83 | 84 | ```verilog 85 | module dff_en(input wire clk, 86 | input wire en, 87 | input wire data, 88 | output wire out); 89 | ``` 90 | 91 | ## Counter 92 | 93 | Implement a counter: 94 | 95 | ```verilog 96 | module counter(input wire clk, 97 | input wire en, 98 | input wire rst, 99 | output reg [3:0] count); 100 | ``` 101 | 102 | You can use the provided `counter.v` and `counter_tb.v`. 103 | 104 | The counter should increase on a positive clock edge whenever `en` (enable) is 105 | set, and reset to 0 whenever `rst` (reset) is set: 106 | 107 | 115 | 116 | ## Clock divider 117 | 118 | Given a clock signal, output a clock signal that is 4 times slower. 119 | 120 | ```verilog 121 | module clock_divider(input wire clk_in, 122 | output wire clk_out); 123 | ``` 124 | 125 | In other words, we should get: 126 | 127 | 135 | 136 | Can you do the same, but 1024 times slower? (1024 = 2 to the 10th power, or 137 | `1 << 10`). 138 | 139 | ## Traffic light controller 140 | 141 | ```verilog 142 | module traffic(input wire clk, 143 | input wire go, 144 | output wire red, 145 | output wire yellow, 146 | output wire green); 147 | ``` 148 | 149 | You can use the provided `traffic.v` and `traffic_tb.v`. 150 | 151 | - Initially, the `red` light should be lit (1). 152 | - When `go` is set to 1, you should light up `red` and `yellow` for 3 cycles, 153 | then switch to `green`. 154 | - When `go` is set back to 0, you should light `yellow` for 3 cycles, then 155 | switch to `red`. 156 | 157 | 172 | 173 | ## Parallel to serial 174 | 175 | Write a module that receives an 8-bit value and converts it to single bits. 176 | 177 | ```verilog 178 | module serial(input wire clk, 179 | input wire in, 180 | input wire [7:0] data, 181 | output wire ready, 182 | output wire out); 183 | ``` 184 | 185 | - Normally, `out` should be 0. 186 | - The user should raise `in` to 1 for a single cycle, and set `data` to a 187 | desired value in the same cycle. After that, `in` will go back to 0. 188 | - Then, during the following 8 cycles, `out` should contain consecutive bits 189 | of `data` (highest to lowest). 190 | - After that, `out` should go back to 0. 191 | - `ready` should be 1 whenever we're not sending, and 0 when we're sending. 192 | 193 | 204 | 205 | ## Memory module 206 | 207 | Implement a 256-byte memory module with read and write ports. 208 | 209 | ```verilog 210 | module memory(input wire clk, 211 | input wire ren, 212 | input wire [7:0] raddr, 213 | output reg [7:0] rdata, 214 | input wire wen, 215 | input wire [7:0] waddr, 216 | input wire [7:0] wdata); 217 | ``` 218 | 219 | - When `ren` (read enable) is set, in the next cycle set `rdata` to the byte at 220 | `raddr` address. 221 | - When `wen` (write enable) is set, in the next cycle set the byte at `waddr` 222 | address to `wdata`. 223 | - Both operations (read and write) can happen in the same cycle. 224 | 225 | Write a test bench. What will be the result of reading uninitialized memory? 226 | How to initialize the memory to 0? 227 | 228 | 239 | 240 | Hint: You can use a `$display` statement to print debug messages while the 241 | module is working (for instance, `"Storing byte XX at address YY"`). 242 | 243 | ## Links 244 | 245 | - [Verilog cheatsheet](https://www.cl.cam.ac.uk/teaching/0910/ECAD+Arch/files/verilogcheatsheet.pdf) (PDF) 246 | - [HDLBits](https://hdlbits.01xz.net/wiki/Problem_sets) - online, interactive Verilog exercises 247 | - [Verilog Beginner's Tutorial](http://zipcpu.com/tutorial/) by ZipCPU author 248 | -------------------------------------------------------------------------------- /verilog/Makefile: -------------------------------------------------------------------------------- 1 | include fpga-tools/fpga.mk 2 | -------------------------------------------------------------------------------- /verilog/adder.v: -------------------------------------------------------------------------------- 1 | module adder4(input wire [3:0] x, 2 | input wire [3:0] y, 3 | input wire c_in, 4 | output wire [3:0] s, 5 | output wire c_out); 6 | assign s = x + y + c_in; 7 | assign c_out = (x + y + c_in) >= 16; 8 | endmodule 9 | 10 | module adder8(input wire [7:0] x, 11 | input wire [7:0] y, 12 | input wire c_in, 13 | output wire [7:0] s, 14 | output wire c_out); 15 | wire [3:0] s0; 16 | wire [3:0] s1; 17 | wire c0; 18 | adder4 a0(x[3:0], y[3:0], c_in, s0, c0); 19 | adder4 a1(x[7:4], y[7:4], c0, s1, c_out); 20 | assign s[3:0] = s0; 21 | assign s[7:4] = s1; 22 | endmodule 23 | -------------------------------------------------------------------------------- /verilog/adder_tb.v: -------------------------------------------------------------------------------- 1 | `include "adder.v" 2 | 3 | module Top; 4 | reg [7:0] x; 5 | reg [7:0] y; 6 | reg c_in; 7 | wire [7:0] s; 8 | wire c_out; 9 | 10 | adder8 a(x, y, c_in, s, c_out); 11 | 12 | initial 13 | begin 14 | $monitor($time, " x = %x, y = %x, c_in = %x, s = %x, c_out = %x", 15 | x, y, c_in, s, c_out); 16 | $dumpfile(`VCD_FILE); 17 | $dumpvars; 18 | 19 | x <= 'h00; y <= 'h00; c_in <= 1; // sum = 'h01 20 | #5 x <= 'h80; y <= 'h7F; c_in <= 1; // sum = 'h100 21 | #5 x <= 'hA0; y <= 'h0B; c_in <= 0; // sum = 'hAB 22 | #5 x <= 'h08; y <= 'h18; c_in <= 0; // sum = 'h20 23 | #5 x <= 'h7F; y <= 'hA0; c_in <= 0; // sum = 'h11F 24 | #5 $finish; 25 | end 26 | endmodule // Top 27 | -------------------------------------------------------------------------------- /verilog/blinky_bx.v: -------------------------------------------------------------------------------- 1 | 2 | // Adapted from the official example: 3 | // https://github.com/tinyfpga/TinyFPGA-BX/blob/master/apio_template/top.v 4 | 5 | module top(input wire CLK, 6 | output wire LED); 7 | 8 | parameter n = 26; 9 | reg [n-1:0] clk_counter = 0; 10 | 11 | always @(posedge CLK) begin 12 | clk_counter <= clk_counter + 1; 13 | end 14 | 15 | // SOS pattern 16 | wire[31:0] blink_pattern = 32'b101010001110111011100010101; 17 | 18 | assign LED = blink_pattern[clk_counter[n-1:n-5]]; 19 | endmodule 20 | -------------------------------------------------------------------------------- /verilog/blinky_icebreaker.v: -------------------------------------------------------------------------------- 1 | 2 | module top(input wire CLK, 3 | output wire LED1, 4 | output wire LED2, 5 | output wire LED3, 6 | output wire LED4, 7 | output wire LED5); 8 | 9 | parameter n = 26; 10 | reg [n-1:0] clk_counter = 0; 11 | 12 | always @(posedge CLK) begin 13 | clk_counter <= clk_counter + 1; 14 | end 15 | 16 | // Display 5 highest bits of counter with LEDs. 17 | assign LED1 = clk_counter[n-5]; 18 | assign LED2 = clk_counter[n-4]; 19 | assign LED3 = clk_counter[n-3]; 20 | assign LED4 = clk_counter[n-2]; 21 | assign LED5 = clk_counter[n-1]; 22 | endmodule 23 | -------------------------------------------------------------------------------- /verilog/blinky_icestick.v: -------------------------------------------------------------------------------- 1 | 2 | module top(input wire CLK, 3 | output wire LED0, 4 | output wire LED1, 5 | output wire LED2, 6 | output wire LED3, 7 | output wire LED4); 8 | 9 | parameter n = 26; 10 | reg [n-1:0] clk_counter = 0; 11 | 12 | always @(posedge CLK) begin 13 | clk_counter <= clk_counter + 1; 14 | end 15 | 16 | // Display 5 highest bits of counter with LEDs. 17 | assign LED0 = clk_counter[n-5]; 18 | assign LED1 = clk_counter[n-4]; 19 | assign LED2 = clk_counter[n-3]; 20 | assign LED3 = clk_counter[n-2]; 21 | assign LED4 = clk_counter[n-1]; 22 | endmodule 23 | -------------------------------------------------------------------------------- /verilog/button.v: -------------------------------------------------------------------------------- 1 | 2 | // This shows how to configure internal pull-up. 3 | // Connect button to ground and to the input pin. 4 | 5 | module top(input wire PIO1_02, 6 | output wire LED0, 7 | output wire LED1, 8 | output wire LED2, 9 | output wire LED3, 10 | output wire LED4); 11 | wire pin; 12 | 13 | pullup pu(PIO1_02, pin); 14 | 15 | // Check both 'pin' and '~pin' to make sure both button states work 16 | // correctly. 17 | assign LED0 = ~pin; 18 | assign LED1 = ~pin; 19 | assign LED2 = ~pin; 20 | assign LED3 = ~pin; 21 | assign LED4 = pin; 22 | endmodule 23 | 24 | module pullup(input wire package_pin, 25 | input wire data_in); 26 | // PIN_TYPE: _ 27 | SB_IO #(.PIN_TYPE(6'b0000_01), 28 | .PULLUP(1'b1)) 29 | io(.PACKAGE_PIN(package_pin), .D_IN_0(data_in)); 30 | endmodule 31 | -------------------------------------------------------------------------------- /verilog/counter.v: -------------------------------------------------------------------------------- 1 | module counter(input wire clk, 2 | input wire en, 3 | input wire rst, 4 | output reg [3:0] count); 5 | // TODO 6 | endmodule 7 | -------------------------------------------------------------------------------- /verilog/counter_tb.v: -------------------------------------------------------------------------------- 1 | `include "counter.v" 2 | 3 | module Top; 4 | reg clk = 1; 5 | reg en = 0; 6 | reg rst = 0; 7 | wire [3:0] count; 8 | 9 | counter c(clk, en, rst, count); 10 | 11 | initial 12 | forever #1 clk = ~clk; 13 | 14 | initial 15 | begin 16 | $monitor($time, " clk = %b, en = %b, rst = %b, count = %b", 17 | clk, en, rst, count); 18 | $dumpfile(`VCD_FILE); 19 | $dumpvars; 20 | 21 | #2 en <= 0; rst <= 1; 22 | #2 en <= 0; rst <= 0; 23 | #2 en <= 1; rst <= 0; 24 | #4 en <= 1; rst <= 1; 25 | #2 en <= 1; rst <= 0; 26 | #10 en <= 0; rst <= 0; 27 | #4 $finish; 28 | end 29 | endmodule // Top 30 | -------------------------------------------------------------------------------- /verilog/dff.v: -------------------------------------------------------------------------------- 1 | module dff(input wire clk, 2 | input wire data, 3 | output wire out); 4 | reg stored; 5 | // You can also just declare "output reg out" above. 6 | assign out = stored; 7 | 8 | always @(posedge clk) begin 9 | stored <= data; 10 | end 11 | endmodule 12 | -------------------------------------------------------------------------------- /verilog/dff_tb.v: -------------------------------------------------------------------------------- 1 | `include "dff.v" 2 | 3 | module Top; 4 | reg clk; 5 | reg data; 6 | wire out; 7 | 8 | dff dff0(clk, data, out); 9 | 10 | initial 11 | begin 12 | $monitor($time, " clk = %b, data = %b, out = %b", 13 | clk, data, out); 14 | $dumpfile(`VCD_FILE); 15 | $dumpvars; 16 | 17 | // Your test code here: 18 | clk <= 0; data <= 0; 19 | // TODO 20 | 21 | #2 $finish; 22 | end 23 | endmodule // Top 24 | -------------------------------------------------------------------------------- /verilog/oled_pattern.v: -------------------------------------------------------------------------------- 1 | `include "fpga-tools/components/oled.v" 2 | 3 | // Draw a 8x8-pixel checkerboard. 4 | 5 | module pattern(input wire clk, 6 | input wire read, 7 | input wire [5:0] row_idx, 8 | input wire [6:0] column_idx, 9 | output reg [7:0] data, 10 | output reg ack); 11 | 12 | wire page_odd = row_idx & 1; 13 | wire column_field_odd = ((column_idx >> 3) & 1); 14 | wire field_black = page_odd ^ column_field_odd; 15 | wire column_odd = column_idx & 1; 16 | 17 | always @(posedge clk) begin 18 | ack <= 0; 19 | if (read) begin 20 | ack <= 1; 21 | if (field_black) 22 | data <= 8'b00000000; 23 | else if (column_odd) 24 | data <= 8'b10101010; 25 | else 26 | data <= 8'b01010101; 27 | end 28 | end 29 | endmodule 30 | 31 | module top(input wire CLK, 32 | output wire PIO1_02, 33 | output wire PIO1_03, 34 | output wire PIO1_04, 35 | output wire PIO1_05, 36 | output wire PIO1_06); 37 | 38 | wire read; 39 | wire [5:0] row_idx; 40 | wire [6:0] column_idx; 41 | wire [7:0] data; 42 | wire ack; 43 | 44 | oled o(.clk(CLK), 45 | .pin_din(PIO1_02), 46 | .pin_clk(PIO1_03), 47 | .pin_cs(PIO1_04), 48 | .pin_dc(PIO1_05), 49 | .pin_res(PIO1_06), 50 | .read(read), 51 | .row_idx(row_idx), 52 | .column_idx(column_idx), 53 | .data(data), 54 | .ack(ack)); 55 | 56 | pattern p(.clk(CLK), 57 | .read(read), 58 | .row_idx(row_idx), 59 | .column_idx(column_idx), 60 | .data(data), 61 | .ack(ack)); 62 | endmodule 63 | -------------------------------------------------------------------------------- /verilog/oled_pattern_color.v: -------------------------------------------------------------------------------- 1 | `include "fpga-tools/components/oled.v" 2 | 3 | module pattern(input wire clk, 4 | input wire read, 5 | input wire [5:0] row_idx, 6 | input wire [6:0] column_idx, 7 | output reg [15:0] data_rgb, 8 | output reg ack); 9 | 10 | wire [4:0] r = row_idx >> 1; 11 | wire [5:0] g = column_idx >> 1; 12 | wire [4:0] b = 63 - (row_idx >> 1); 13 | wire [15:0] rgb = {r, g, b}; 14 | 15 | always @(posedge clk) begin 16 | ack <= 0; 17 | if (read) begin 18 | ack <= 1; 19 | data_rgb <= rgb; 20 | end 21 | end 22 | endmodule 23 | 24 | module top(input wire CLK, 25 | output wire PIO1_02, 26 | output wire PIO1_03, 27 | output wire PIO1_04, 28 | output wire PIO1_05, 29 | output wire PIO1_06); 30 | 31 | wire read; 32 | wire [5:0] row_idx; 33 | wire [6:0] column_idx; 34 | wire [15:0] data_rgb; 35 | wire ack; 36 | 37 | oled #(.color(1)) 38 | o(.clk(CLK), 39 | .pin_din(PIO1_02), 40 | .pin_clk(PIO1_03), 41 | .pin_cs(PIO1_04), 42 | .pin_dc(PIO1_05), 43 | .pin_res(PIO1_06), 44 | .read(read), 45 | .row_idx(row_idx), 46 | .column_idx(column_idx), 47 | .data_rgb(data_rgb), 48 | .ack(ack)); 49 | 50 | pattern p(.clk(CLK), 51 | .read(read), 52 | .row_idx(row_idx), 53 | .column_idx(column_idx), 54 | .data_rgb(data_rgb), 55 | .ack(ack)); 56 | endmodule 57 | -------------------------------------------------------------------------------- /verilog/oled_play.v: -------------------------------------------------------------------------------- 1 | `include "fpga-tools/components/uart.v" 2 | `include "fpga-tools/components/oled.v" 3 | 4 | `define BAUD_RATE 115300 5 | 6 | module uart_display(input wire clk, 7 | input wire d_read, 8 | // input wire [2:0] d_page_idx, 9 | // input wire [6:0] d_column_idx, 10 | output reg [7:0] d_data, 11 | output reg d_ack, 12 | input wire uart_received, 13 | input wire [7:0] uart_rx_byte); 14 | 15 | localparam DISPLAY_SIZE = 128*8; 16 | 17 | reg [7:0] data[0:DISPLAY_SIZE-1]; 18 | reg [9:0] data_write_idx = 0; 19 | reg [9:0] data_read_idx = 0; 20 | 21 | reg byte_num = 0; 22 | reg [7:0] data_count = 0; 23 | reg [7:0] data_byte; 24 | 25 | always @(posedge clk) begin 26 | if (uart_received) begin 27 | if (byte_num == 0) begin 28 | data_count <= uart_rx_byte; 29 | byte_num <= 1; 30 | end else begin 31 | data_byte <= uart_rx_byte; 32 | data[data_write_idx] <= uart_rx_byte; 33 | data_write_idx <= (data_write_idx + 1) % DISPLAY_SIZE; 34 | byte_num <= 0; 35 | end 36 | end // if (uart_received) 37 | 38 | if (byte_num == 0 && data_count > 0) begin 39 | data[data_write_idx] <= data_byte; 40 | data_write_idx <= (data_write_idx + 1) % DISPLAY_SIZE; 41 | data_count <= data_count - 1; 42 | end 43 | 44 | if (d_read) begin 45 | d_data <= data[data_read_idx]; 46 | d_ack <= 1; 47 | data_read_idx <= (data_read_idx + 1) % DISPLAY_SIZE; 48 | end else begin 49 | d_ack <= 0; 50 | end 51 | end 52 | endmodule 53 | 54 | module top(input wire iCE_CLK, 55 | input wire RS232_Rx_TTL, 56 | output wire PIO1_02, 57 | output wire PIO1_03, 58 | output wire PIO1_04, 59 | output wire PIO1_05, 60 | output wire PIO1_06); 61 | 62 | wire d_read; 63 | // wire [2:0] d_page_idx; 64 | // wire [6:0] d_column_idx; 65 | wire [7:0] d_data; 66 | wire d_ack; 67 | 68 | wire uart_received; 69 | wire [7:0] uart_rx_byte; 70 | 71 | oled o(.clk(iCE_CLK), 72 | .pin_din(PIO1_02), 73 | .pin_clk(PIO1_03), 74 | .pin_cs(PIO1_04), 75 | .pin_dc(PIO1_05), 76 | .pin_res(PIO1_06), 77 | .read(d_read), 78 | // .page_idx(d_page_idx), 79 | // .column_idx(d_column_idx), 80 | .data(d_data), 81 | .ack(d_ack)); 82 | 83 | uart #(.baud_rate(`BAUD_RATE), .sys_clk_freq(12000000)) 84 | uart0(.clk(iCE_CLK), // The master clock for this module 85 | .rst(1'b0), // Synchronous reset 86 | .rx(RS232_Rx_TTL), // Incoming serial line 87 | // .tx(RS232_Tx_TTL), // Outgoing serial line 88 | .transmit(1'b0), // Signal to transmit 89 | // .tx_byte(tx_byte), // Byte to transmit 90 | .received(uart_received), // Indicated that a byte has been received 91 | .rx_byte(uart_rx_byte) // Byte received 92 | // .is_receiving(is_receiving), // Low when receive line is idle 93 | // .is_transmitting(is_transmitting),// Low when transmit line is idle 94 | // .recv_error(recv_error) // Indicates error in receiving packet. 95 | ); 96 | 97 | uart_display ud(.clk(iCE_CLK), 98 | .d_read(d_read), 99 | .d_data(d_data), 100 | .d_ack(d_ack), 101 | .uart_received(uart_received), 102 | .uart_rx_byte(uart_rx_byte)); 103 | 104 | endmodule 105 | -------------------------------------------------------------------------------- /verilog/serial.v: -------------------------------------------------------------------------------- 1 | module serial(input wire clk, 2 | input wire in, 3 | input wire [7:0] data, 4 | output wire ready, 5 | output wire out); 6 | // TODO 7 | endmodule 8 | -------------------------------------------------------------------------------- /verilog/serial_tb.v: -------------------------------------------------------------------------------- 1 | `include "serial.v" 2 | 3 | module Top; 4 | reg clk = 1; 5 | reg in = 0; 6 | reg [7:0] data; 7 | wire ready; 8 | wire out; 9 | 10 | serial s(.clk(clk), .in(in), .data(data), .ready(ready), .out(out)); 11 | 12 | initial 13 | forever #1 clk = ~clk; 14 | 15 | initial 16 | begin 17 | $monitor($time, " clk = %b, in = %b, data = %b, ready = %b, out = %b", 18 | clk, in, data, ready, out); 19 | $dumpfile(`VCD_FILE); 20 | $dumpvars; 21 | 22 | #2 in <= 1; data <= 8'b10101101; 23 | #2 in <= 0; data <= 'bx; 24 | #20 $finish; 25 | end 26 | endmodule // Top 27 | -------------------------------------------------------------------------------- /verilog/spoilers/adder.v: -------------------------------------------------------------------------------- 1 | module adder4(input wire [3:0] x, 2 | input wire [3:0] y, 3 | input wire c_in, 4 | output wire [3:0] s, 5 | output wire c_out); 6 | assign s = x + y + c_in; 7 | assign c_out = (x + y + c_in) >= 16; 8 | endmodule 9 | 10 | module adder8(input wire [7:0] x, 11 | input wire [7:0] y, 12 | input wire c_in, 13 | output wire [7:0] s, 14 | output wire c_out); 15 | wire [3:0] s0; 16 | wire [3:0] s1; 17 | wire c0; 18 | adder4 a0(x[3:0], y[3:0], c_in, s0, c0); 19 | adder4 a1(x[7:4], y[7:4], c0, s1, c_out); 20 | assign s[3:0] = s0; 21 | assign s[7:4] = s1; 22 | endmodule 23 | 24 | module adder_bcd(input wire [3:0] x, 25 | input wire [3:0] y, 26 | input wire c_in, 27 | output wire [3:0] s, 28 | output wire c_out); 29 | wire [4:0] total = x + y + c_in; 30 | assign c_out = total >= 10; 31 | assign s = total - c_out * 10; 32 | endmodule 33 | 34 | module adder2_bcd(input wire [7:0] x, 35 | input wire [7:0] y, 36 | input wire c_in, 37 | output wire [7:0] s, 38 | output wire c_out); 39 | wire c0; 40 | adder_bcd a0(x[3:0], y[3:0], c_in, s[3:0], c0); 41 | adder_bcd a1(x[7:4], y[7:4], c0, s[7:4], c_out); 42 | endmodule 43 | -------------------------------------------------------------------------------- /verilog/spoilers/counter.v: -------------------------------------------------------------------------------- 1 | module counter(input wire clk, 2 | input wire en, 3 | input wire rst, 4 | output reg [3:0] count); 5 | always @(posedge clk) begin 6 | if (rst) 7 | count <= 0; 8 | else if (en) 9 | count <= count + 1; 10 | end 11 | endmodule 12 | -------------------------------------------------------------------------------- /verilog/spoilers/keypad.v: -------------------------------------------------------------------------------- 1 | module keypad(input wire clk, 2 | output reg [3:0] column_pins, 3 | input wire [3:0] row_pins, 4 | output reg [15:0] keys); 5 | 6 | reg [1:0] column = 0; 7 | 8 | initial begin 9 | column_pins = 4'b1110; 10 | keys = 0; 11 | end 12 | 13 | integer i; 14 | 15 | always @(posedge clk) begin 16 | for (i = 0; i < 4; i++) 17 | keys[i*4 + column] <= (row_pins[i] == 0); 18 | column <= (column + 1) % 4; 19 | column_pins <= (column_pins << 1) + (column_pins >> 3); 20 | end 21 | endmodule 22 | 23 | module pullup(output wire pin, output wire d_in); 24 | SB_IO #(.PIN_TYPE(6'b1), .PULLUP(1'b1)) io(.PACKAGE_PIN(pin), .D_IN_0(d_in)); 25 | endmodule 26 | 27 | module top(input wire iCE_CLK, 28 | input wire PIO1_02, 29 | input wire PIO1_03, 30 | input wire PIO1_04, 31 | input wire PIO1_05, 32 | output wire PIO1_06, 33 | output wire PIO1_07, 34 | output wire PIO1_08, 35 | output wire PIO1_09, 36 | output wire LED0, 37 | output wire LED1, 38 | output wire LED2, 39 | output wire LED3, 40 | output wire LED4); 41 | 42 | wire [3:0] row_pins; 43 | wire [3:0] column_pins; 44 | wire [15:0] keys; 45 | 46 | keypad k(iCE_CLK, column_pins, row_pins, keys); 47 | 48 | assign column_pins = {PIO1_09, PIO1_08, PIO1_07, PIO1_06}; 49 | pullup io1(PIO1_02, row_pins[0]); 50 | pullup io2(PIO1_03, row_pins[1]); 51 | pullup io3(PIO1_04, row_pins[2]); 52 | pullup io4(PIO1_05, row_pins[3]); 53 | 54 | integer i; 55 | reg [3:0] key = 0; 56 | 57 | always @(posedge iCE_CLK) begin 58 | key <= 0; 59 | for (i = 0; i < 16; i++) 60 | if (keys[i]) 61 | key <= i; 62 | end 63 | 64 | assign LED4 = !(|keys); 65 | assign LED0 = key[3]; 66 | assign LED1 = key[2]; 67 | assign LED2 = key[1]; 68 | assign LED3 = key[0]; 69 | endmodule 70 | -------------------------------------------------------------------------------- /verilog/spoilers/serial.v: -------------------------------------------------------------------------------- 1 | module serial(input wire clk, 2 | input wire in, 3 | input wire [7:0] data, 4 | output wire ready, 5 | output wire out); 6 | 7 | reg [3:0] counter = 0; 8 | reg [7:0] shift = 0; 9 | assign ready = counter > 0; 10 | assign out = shift[7]; 11 | 12 | always @(posedge clk) begin 13 | if (in) begin 14 | shift <= data; 15 | counter <= 8; 16 | end else if (counter) begin 17 | counter <= counter - 1; 18 | shift <= shift << 1; 19 | end 20 | end 21 | endmodule 22 | -------------------------------------------------------------------------------- /verilog/spoilers/traffic.v: -------------------------------------------------------------------------------- 1 | module traffic(input wire clk, 2 | input wire go, 3 | output wire red, 4 | output wire yellow, 5 | output wire green); 6 | // 0: stop, 1: starting, 2: stopping, 3: go 7 | reg [1:0] state = 0; 8 | reg [1:0] counter; 9 | assign red = (state == 0 || state == 1); 10 | assign yellow = (state == 1 || state == 2); 11 | assign green = (state == 3); 12 | 13 | always @(posedge clk) begin 14 | case (state) 15 | 0: begin 16 | if (go) begin 17 | state <= 1; 18 | counter <= 2; 19 | end 20 | end 21 | 1: begin 22 | if (counter == 0) 23 | state <= 3; 24 | else 25 | counter <= counter - 1; 26 | end 27 | 2: begin 28 | if (counter == 0) 29 | state <= 0; 30 | else 31 | counter <= counter - 1; 32 | end 33 | 3: if (!go) begin 34 | state <= 2; 35 | counter <= 2; 36 | end 37 | endcase 38 | end 39 | endmodule 40 | -------------------------------------------------------------------------------- /verilog/spoilers/traffic2.v: -------------------------------------------------------------------------------- 1 | module traffic(input wire clk, 2 | input wire go, 3 | output reg red, 4 | output reg yellow, 5 | output reg green); 6 | // 0: stop, 1: starting, 2: stopping, 3: go 7 | reg [1:0] state = 0; 8 | reg [1:0] counter; 9 | 10 | always @(*) 11 | case (state) 12 | 0: {red, yellow, green} = 3'b100; 13 | 1: {red, yellow, green} = 3'b110; 14 | 2: {red, yellow, green} = 3'b010; 15 | 3: {red, yellow, green} = 3'b101; 16 | endcase 17 | 18 | always @(posedge clk) 19 | case (state) 20 | 0: begin 21 | if (go) begin 22 | state <= 1; 23 | counter <= 2; 24 | end 25 | end 26 | 1: begin 27 | if (counter == 0) 28 | state <= 3; 29 | else 30 | counter <= counter - 1; 31 | end 32 | 2: begin 33 | if (counter == 0) 34 | state <= 0; 35 | else 36 | counter <= counter - 1; 37 | end 38 | 3: if (!go) begin 39 | state <= 2; 40 | counter <= 2; 41 | end 42 | endcase 43 | 44 | endmodule 45 | -------------------------------------------------------------------------------- /verilog/traffic.v: -------------------------------------------------------------------------------- 1 | module traffic(input wire clk, 2 | input wire go, 3 | output wire red, 4 | output wire yellow, 5 | output wire green); 6 | // TODO 7 | endmodule 8 | -------------------------------------------------------------------------------- /verilog/traffic_tb.v: -------------------------------------------------------------------------------- 1 | `include "traffic.v" 2 | 3 | module Top; 4 | reg clk = 1; 5 | reg go = 0; 6 | wire red, yellow, green; 7 | 8 | traffic t(clk, go, red, yellow, green); 9 | 10 | initial 11 | forever #1 clk = ~clk; 12 | 13 | initial 14 | begin 15 | $monitor($time, " clk = %b, go = %b, red = %b, yellow = %b, green = %b", 16 | clk, go, red, yellow, green); 17 | $dumpfile(`VCD_FILE); 18 | $dumpvars; 19 | 20 | #4 go <= 1; 21 | #12 go <= 0; 22 | #12 $finish; 23 | end 24 | endmodule // Top 25 | -------------------------------------------------------------------------------- /verilog/uart.py: -------------------------------------------------------------------------------- 1 | 2 | # pip3 install --user pyserial 3 | # https://pyserial.readthedocs.io/en/latest/pyserial_api.html 4 | import serial 5 | 6 | baud_rate = 9600 7 | timeout = 0.2 8 | 9 | with serial.Serial('/dev/ttyUSB1', baud_rate, timeout=timeout) as ser: 10 | try: 11 | while True: 12 | data = ser.read(20) 13 | print(data.decode('ascii'), end='', flush=True) 14 | except KeyboardInterrupt: 15 | print() 16 | print('Interrupted') 17 | -------------------------------------------------------------------------------- /verilog/uart_hello.v: -------------------------------------------------------------------------------- 1 | `include "fpga-tools/components/uart.v" 2 | 3 | module uart_node(input wire clk, 4 | input wire is_receiving, 5 | input wire is_transmitting, 6 | output reg transmit = 0, 7 | output reg [7:0] tx_byte, 8 | input wire received, 9 | input wire [7:0] rx_byte); 10 | 11 | parameter n = 13; 12 | parameter greeting = "Hello World!\n"; 13 | wire [7:0] data[0:n-1]; 14 | reg [3:0] idx; 15 | 16 | // Initialize data with a string. Sadly, Verilog string literals are just 17 | // huge numbers, so a conversion is necessary. 18 | generate 19 | genvar i; 20 | for (i = 0; i < n; i = i + 1) begin 21 | assign data[i] = greeting[8*(n-i)-1 : 8*(n-i)-8]; 22 | end 23 | endgenerate 24 | 25 | 26 | always @(posedge clk) begin 27 | // Only raise transmit for 1 cycle 28 | if (transmit) 29 | transmit <= 0; 30 | 31 | if (!transmit && !is_transmitting) begin 32 | transmit <= 1; 33 | tx_byte <= data[idx]; 34 | if (idx == n - 1) 35 | idx <= 0; 36 | else 37 | idx <= idx + 1; 38 | end 39 | end 40 | 41 | endmodule 42 | 43 | 44 | module top(input wire CLK, 45 | input wire RS232_Rx_TTL, 46 | output wire RS232_Tx_TTL, 47 | output wire LED4); 48 | 49 | parameter baud_rate = 9600; 50 | 51 | wire reset = 0; 52 | wire transmit; 53 | wire [7:0] tx_byte; 54 | wire received; 55 | wire [7:0] rx_byte; 56 | wire is_receiving; 57 | wire is_transmitting; 58 | wire recv_error; 59 | 60 | uart #(.baud_rate(9600), .sys_clk_freq(12000000)) 61 | uart0(.clk(CLK), // The master clock for this module 62 | .rst(reset), // Synchronous reset 63 | .rx(RS232_Tx_TTL), // Incoming serial line 64 | .tx(RS232_Tx_TTL), // Outgoing serial line 65 | .transmit(transmit), // Signal to transmit 66 | .tx_byte(tx_byte), // Byte to transmit 67 | .received(received), // Indicated that a byte has been received 68 | .rx_byte(rx_byte), // Byte received 69 | .is_receiving(is_receiving), // Low when receive line is idle 70 | .is_transmitting(is_transmitting),// Low when transmit line is idle 71 | .recv_error(recv_error) // Indicates error in receiving packet. 72 | ); 73 | 74 | uart_node un(.clk(CLK), 75 | .is_receiving(is_receiving), 76 | .is_transmitting(is_transmitting), 77 | .transmit(transmit), 78 | .tx_byte(tx_byte), 79 | .received(received), 80 | .rx_byte(rx_byte)); 81 | 82 | assign LED4 = (is_transmitting); 83 | endmodule 84 | --------------------------------------------------------------------------------