├── 7series.txt ├── Basys3_Master.xdc ├── FAQ.md ├── LICENSE ├── MacM1.md ├── Makefile ├── Nexys-A7-Master.xdc ├── README.md ├── Setup.md ├── figures ├── cover-small.jpg ├── decoder.svg ├── heap_timing.svg ├── mux.svg └── synchronizer.svg ├── lab1 ├── Basys3Hello.xdc ├── NexsysA7Hello.xdc ├── README.md ├── build.sbt └── src │ ├── main │ └── scala │ │ └── Hello.scala │ └── test │ └── scala │ └── HelloSpec.scala ├── lab10 ├── README.md ├── build.sbt └── src │ ├── main │ ├── scala │ │ └── VendingMachine.scala │ └── verilog │ │ ├── VendingA.v │ │ └── VendingB.v │ └── test │ └── scala │ └── VendingTester.scala ├── lab2 ├── README.md ├── build.sbt ├── majority.xdc └── src │ ├── main │ └── scala │ │ ├── AddSub.scala │ │ ├── Decoder.scala │ │ ├── Majority.scala │ │ └── Mux2.scala │ └── test │ └── scala │ ├── AddSubSpec.scala │ ├── DecoderSpec.scala │ ├── MajoritySpec.scala │ └── Mux2Spec.scala ├── lab3 ├── README.md ├── build.sbt └── src │ ├── main │ └── scala │ │ ├── Accu.scala │ │ ├── Count15.scala │ │ ├── Count6.scala │ │ ├── Delay.scala │ │ ├── Mux2.scala │ │ ├── Mux4.scala │ │ └── UseMux2.scala │ └── test │ └── scala │ ├── AccuSpec.scala │ ├── Count15Spec.scala │ ├── Count6Spec.scala │ ├── DelaySpec.scala │ ├── Mux2Spec.scala │ ├── Mux4Spec.scala │ └── UseMux2Spec.scala ├── lab4 ├── README.md ├── build.sbt └── src │ ├── main │ └── scala │ │ ├── Mux5.scala │ │ └── heap │ │ ├── Fetcher.scala │ │ ├── Heap.scala │ │ ├── HeapControl.scala │ │ ├── HeapMemory.scala │ │ ├── Heapifier.scala │ │ ├── MaxFinder.scala │ │ ├── Swapper.scala │ │ └── package.scala │ └── test │ └── scala │ ├── HeapTest.scala │ └── Mux5Test.scala ├── lab5 ├── README.md ├── build.sbt ├── sevenseg-cnt.xdc ├── sevenseg.xdc └── src │ ├── main │ └── scala │ │ ├── CountSevenSeg.scala │ │ └── SevenSegDecoder.scala │ └── test │ └── scala │ ├── SevenSegCountSpec.scala │ └── SevenSegDecoderSpec.scala ├── lab6 ├── README.md ├── build.sbt ├── display.xdc └── src │ ├── main │ └── scala │ │ ├── Display.scala │ │ ├── DisplayMultiplexer.scala │ │ └── SevenSegDec.scala │ └── test │ └── scala │ ├── DisplaySimulation.scala │ └── DisplaySpec.scala ├── lab7 ├── README.md ├── build.sbt ├── serial.xdc ├── serialA7.xdc └── src │ └── main │ └── scala │ └── SerialPort.scala └── vending ├── README.md ├── basys-vending.jpg ├── build.sbt ├── src ├── main │ └── scala │ │ └── VendingMachine.scala └── test │ └── scala │ ├── VendingSimulation.scala │ └── VendingTester.scala ├── vending-nexys.xdc └── vending.xdc /7series.txt: -------------------------------------------------------------------------------- 1 | 2 | # File: 7series.txt 3 | interface ftdi 4 | ftdi_device_desc "Digilent USB Device" 5 | ftdi_vid_pid 0x0403 0x6010 6 | # channel 1 does not have any functionality 7 | ftdi_channel 0 8 | # just TCK TDI TDO TMS, no reset 9 | ftdi_layout_init 0x0088 0x008b 10 | reset_config none 11 | adapter_khz 10000 12 | 13 | source [find cpld/xilinx-xc7.cfg] 14 | source [find cpld/jtagspi.cfg] 15 | init 16 | 17 | puts [irscan xc7.tap 0x09] 18 | puts [drscan xc7.tap 32 0] 19 | 20 | puts "Programming FPGA..." 21 | pld load 0 Hello.bit 22 | exit 23 | -------------------------------------------------------------------------------- /Basys3_Master.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Basys3 rev B board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | set_property IOSTANDARD LVCMOS33 [get_ports *] 7 | 8 | 9 | ## Clock signal 10 | set_property PACKAGE_PIN W5 [get_ports clock] 11 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 12 | 13 | ## Switches 14 | set_property PACKAGE_PIN V17 [get_ports {io_sw[0]}] 15 | set_property PACKAGE_PIN V16 [get_ports {io_sw[1]}] 16 | set_property PACKAGE_PIN W16 [get_ports {io_sw[2]}] 17 | set_property PACKAGE_PIN W17 [get_ports {io_sw[3]}] 18 | #set_property PACKAGE_PIN W15 [get_ports {sw[4]}] 19 | #set_property PACKAGE_PIN V15 [get_ports {sw[5]}] 20 | #set_property PACKAGE_PIN W14 [get_ports {sw[6]}] 21 | #set_property PACKAGE_PIN W13 [get_ports {sw[7]}] 22 | #set_property PACKAGE_PIN V2 [get_ports {sw[8]}] 23 | #set_property PACKAGE_PIN T3 [get_ports {sw[9]}] 24 | #set_property PACKAGE_PIN T2 [get_ports {sw[10]}] 25 | #set_property PACKAGE_PIN R3 [get_ports {sw[11]}] 26 | #set_property PACKAGE_PIN W2 [get_ports {sw[12]}] 27 | #set_property PACKAGE_PIN U1 [get_ports {sw[13]}] 28 | #set_property PACKAGE_PIN T1 [get_ports {sw[14]}] 29 | #set_property PACKAGE_PIN R2 [get_ports {sw[15]}] 30 | 31 | 32 | ## LEDs 33 | set_property PACKAGE_PIN U16 [get_ports {io_led[0]}] 34 | set_property PACKAGE_PIN E19 [get_ports {io_led[1]}] 35 | set_property PACKAGE_PIN U19 [get_ports {io_led[2]}] 36 | set_property PACKAGE_PIN V19 [get_ports {io_led[3]}] 37 | #set_property PACKAGE_PIN W18 [get_ports {led[4]}] 38 | #set_property PACKAGE_PIN U15 [get_ports {led[5]}] 39 | #set_property PACKAGE_PIN U14 [get_ports {led[6]}] 40 | #set_property PACKAGE_PIN V14 [get_ports {led[7]}] 41 | #set_property PACKAGE_PIN V13 [get_ports {led[8]}] 42 | #set_property PACKAGE_PIN V3 [get_ports {led[9]}] 43 | #set_property PACKAGE_PIN W3 [get_ports {led[10]}] 44 | #set_property PACKAGE_PIN U3 [get_ports {led[11]}] 45 | #set_property PACKAGE_PIN P3 [get_ports {led[12]}] 46 | #set_property PACKAGE_PIN N3 [get_ports {led[13]}] 47 | #set_property PACKAGE_PIN P1 [get_ports {led[14]}] 48 | #set_property PACKAGE_PIN L1 [get_ports {led[15]}] 49 | 50 | 51 | ##Buttons 52 | #set_property PACKAGE_PIN U18 [get_ports btnC] 53 | #set_property PACKAGE_PIN T18 [get_ports btnU] 54 | #set_property PACKAGE_PIN W19 [get_ports btnL] 55 | # btnR proposed as reset 56 | #set_property PACKAGE_PIN T17 [get_ports btnR] 57 | set_property PACKAGE_PIN T17 [get_ports reset] 58 | #set_property PACKAGE_PIN U17 [get_ports btnD] 59 | 60 | 61 | ##7 segment display 62 | #set_property PACKAGE_PIN W7 [get_ports {io_seg[0]}] 63 | #set_property PACKAGE_PIN W6 [get_ports {io_seg[1]}] 64 | #set_property PACKAGE_PIN U8 [get_ports {io_seg[2]}] 65 | #set_property PACKAGE_PIN V8 [get_ports {io_seg[3]}] 66 | #set_property PACKAGE_PIN U5 [get_ports {io_seg[4]}] 67 | #set_property PACKAGE_PIN V5 [get_ports {io_seg[5]}] 68 | #set_property PACKAGE_PIN U7 [get_ports {io_seg[6]}] 69 | #set_property PACKAGE_PIN V7 [get_ports io_dp] 70 | #set_property PACKAGE_PIN U2 [get_ports {io_an[0]}] 71 | #set_property PACKAGE_PIN U4 [get_ports {io_an[1]}] 72 | #set_property PACKAGE_PIN V4 [get_ports {io_an[2]}] 73 | #set_property PACKAGE_PIN W4 [get_ports {io_an[3]}] 74 | 75 | 76 | ##VGA Connector 77 | #set_property PACKAGE_PIN G19 [get_ports {vgaRed[0]}] 78 | #set_property PACKAGE_PIN H19 [get_ports {vgaRed[1]}] 79 | #set_property PACKAGE_PIN J19 [get_ports {vgaRed[2]}] 80 | #set_property PACKAGE_PIN N19 [get_ports {vgaRed[3]}] 81 | #set_property PACKAGE_PIN N18 [get_ports {vgaBlue[0]}] 82 | #set_property PACKAGE_PIN L18 [get_ports {vgaBlue[1]}] 83 | #set_property PACKAGE_PIN K18 [get_ports {vgaBlue[2]}] 84 | #set_property PACKAGE_PIN J18 [get_ports {vgaBlue[3]}] 85 | #set_property PACKAGE_PIN J17 [get_ports {vgaGreen[0]}] 86 | #set_property PACKAGE_PIN H17 [get_ports {vgaGreen[1]}] 87 | #set_property PACKAGE_PIN G17 [get_ports {vgaGreen[2]}] 88 | #set_property PACKAGE_PIN D17 [get_ports {vgaGreen[3]}] 89 | #set_property PACKAGE_PIN P19 [get_ports Hsync] 90 | #set_property PACKAGE_PIN R19 [get_ports Vsync] 91 | 92 | 93 | ##USB-RS232 Interface 94 | #set_property PACKAGE_PIN B18 [get_ports RsRx] 95 | #set_property PACKAGE_PIN A18 [get_ports RsTx] 96 | 97 | 98 | ##USB HID (PS/2) 99 | #set_property PACKAGE_PIN C17 [get_ports PS2Clk] 100 | #set_property PULLUP true [get_ports PS2Clk] 101 | #set_property PACKAGE_PIN B17 [get_ports PS2Data] 102 | #set_property PULLUP true [get_ports PS2Data] 103 | 104 | 105 | ##Pmod Header JA 106 | #set_property PACKAGE_PIN J1 [get_ports {JA[0]}] 107 | #set_property PACKAGE_PIN L2 [get_ports {JA[1]}] 108 | #set_property PACKAGE_PIN J2 [get_ports {JA[2]}] 109 | #set_property PACKAGE_PIN G2 [get_ports {JA[3]}] 110 | #set_property PACKAGE_PIN H1 [get_ports {JA[4]}] 111 | #set_property PACKAGE_PIN K2 [get_ports {JA[5]}] 112 | #set_property PACKAGE_PIN H2 [get_ports {JA[6]}] 113 | #set_property PACKAGE_PIN G3 [get_ports {JA[7]}] 114 | 115 | 116 | ##Pmod Header JB 117 | #set_property PACKAGE_PIN A14 [get_ports {JB[0]}] 118 | #set_property PACKAGE_PIN A16 [get_ports {JB[1]}] 119 | #set_property PACKAGE_PIN B15 [get_ports {JB[2]}] 120 | #set_property PACKAGE_PIN B16 [get_ports {JB[3]}] 121 | 122 | ## Pmod in lower row 123 | # BTN0 124 | #set_property PACKAGE_PIN A15 [get_ports {JB[4]}] 125 | # BTN1 126 | #set_property PACKAGE_PIN A17 [get_ports {JB[5]}] 127 | # BTN2 128 | #set_property PACKAGE_PIN C15 [get_ports {JB[6]}] 129 | # BTN3 - use as manual clock 130 | #set_property PACKAGE_PIN C16 [get_ports {JB[7]}] 131 | 132 | 133 | ##Pmod Header JC 134 | #set_property PACKAGE_PIN K17 [get_ports {JC[0]}] 135 | #set_property PACKAGE_PIN M18 [get_ports {JC[1]}] 136 | #set_property PACKAGE_PIN N17 [get_ports {JC[2]}] 137 | #set_property PACKAGE_PIN P18 [get_ports {JC[3]}] 138 | #set_property PACKAGE_PIN L17 [get_ports {JC[4]}] 139 | #set_property PACKAGE_PIN M19 [get_ports {JC[5]}] 140 | #set_property PACKAGE_PIN P17 [get_ports {JC[6]}] 141 | #set_property PACKAGE_PIN R18 [get_ports {JC[7]}] 142 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # Digital Electronics 2 FAQ 2 | 3 | ## Chisel 4 | 5 | Here some common issues with Chisel constructs. 6 | 7 | ### Extracting a bitfield 8 | You can extract a subset of wires from a bus x like this: 9 | 10 | x(n, m) 11 | 12 | This will extract wire n down to m both included. It is important to know that n >= m, otherwise Chisel will throw a hard to understand error. 13 | 14 | ### Missing ```.W``` 15 | 16 | One possible error when defining constants with a dedicated width is missing the ```.W``` 17 | specifier for a width. E.g., ```1.U(32)``` will not define a 32-bit wide constant representing 1. 18 | Instead, the expression ```(32)``` is interpreted as bit extraction from position 32, which results 19 | in a single bit constant of 0. Probably not what the original intention of the programmer was. 20 | 21 | 22 | ## Error msgs 23 | 24 | 25 | ### firrtl.passes.CheckFlows$WrongFlow: @[cmdx.sc xx:xx]: [module xxxx] Expression _T is used as a SinkFlow but can only be used as a SourceFlow. 26 | 27 | You can't bind some wires of a output bus. Either none or all in one expression. A workaround is to declare a bus where you can bind part of the wires. Then bind this bus to the output bus 28 | 29 | ### scala.MatchError: List(UInt\(0) ... UInt\(y)) (of class scala.collection.immutable.$colon$colon) 30 | This error message usually indicates that you have declared an Enum with a wrong indication of number of elements. 31 | 32 | ### Cannot reassign to read-only 33 | This most likely happens when you are trying to assign a subfield of a bus. 34 | ```scala 35 | class someClass extends Module { 36 | val io = IO(new Bundle { 37 | val y = Output(2.W) 38 | }) 39 | //This is not legal Chisel3-code 40 | io.y(0) := 0.U 41 | io.y(1) := 1.U 42 | 43 | } 44 | ``` 45 | To get around this, use *extraction and concatenation*, see the following [SO post](https://stackoverflow.com/questions/40950073/chisel-3-assignment-to-bit-range). 46 | 47 | Alternatively, unpack your bus into a vector of booleans, modify it, and then repack it as a bus again, see the following entry from [the Chisel Cookbook](https://github.com/freechipsproject/chisel3/wiki/Cookbook#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint) ("How do I do subword assignement?") 48 | 49 | ### Understanding very long stack traces 50 | You may sometimes meet a very long stack trace when you've made an error. This occurs when the error is not Chisel-specific but it is a Scala error. When you meet the long stack traces, most error msgs will be indented. Scroll up from the bottom, until you meet an unindented message 51 | ``` 52 | Exception in thread "main" ... 53 | (lots of indented messages) 54 | Caused by: (THE REAL ERROR MESSAGE) 55 | (more indented messages) 56 | ``` 57 | In the second section of indented messages, you may see links highlighted in blue. These will take you to the portions of your code where the error has occured. 58 | 59 | ### IndexOutOfBoundsException 60 | Might occur when you're trying to do a sub-field assignment (see above) on a vector. 61 | ```scala 62 | //Not valid code, do not copy 63 | val myVec := Wire(Vec(1, UInt(16.W))) 64 | myVec(2) := 0.U 65 | ``` 66 | When accessing the above vector with 'myVec(2)', Chisel attempts to select the second vector myVec, and not the second bit of myVec(1). 67 | 68 | ### Enum 69 | 70 | A wrong number n in Enum(n) for FSM states can give a long error log. 71 | 72 | ## IntelliJ 73 | 74 | ### My file list is gone 75 | Look on the very left of IntelliJ, and click "Project" to reopen your file view. 76 | 77 | ### My terminal disappeared 78 | Select View > Tool Windows > Terminal, or type `Alt + F12` to reopen it. Alternatively, just use the "sbt shell". Commands run through the sbt shell should *not* be prefixed with `sbt` (instead of typing `sbt "run"`, simply write `run` and hit enter. 79 | 80 | ## Vivado 81 | 82 | ### Error "Bitstream Generation failed" 83 | 84 | Comes from a missing pin assignment in the .xdc file. Look for the blue text in the warning/error messages, this will tell you what pins are unconstrained. 85 | 86 | ### Unable to connect to Basys3 board 87 | Follow the instructions at [this link](https://www.xilinx.com/support/answers/59128.html). Make sure that you open your shell/command prompt as admin, and then navigate to the correct folder. I did not need to supply any command line arguments for this to work. 88 | 89 | 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Technical University of Denmark 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /MacM1.md: -------------------------------------------------------------------------------- 1 | 2 | # Mac M1 (Apple Silicon) 3 | 4 | Using a Mac with Apple Silicon 5 | 6 | * Using Parallel to create a Windows 11 for ARM VM 7 | * Installed Vivado 8 | * Windows is missing the FTDI drivers - install Adapt from Digilent will add the missing drivers 9 | * Use Windows 11 Arm version to generate bitstream 10 | * With the drivers Vivado can configure and Putty can listen to the serial port 11 | * Configure from Mac with open OCD 12 | * see https://github.com/byu-cpe/BYU-Computing-Tutorials/wiki/Program-7-Series-FPGA-from-a-Mac-or-Linux-Without-Xilinx 13 | * Run it as sudo 14 | * Configuration (several A7 boards, e.g., Basys3, NexysA7) is in `7series.txt`: 15 | ``` 16 | # File: 7series.txt 17 | interface ftdi 18 | ftdi_device_desc "Digilent USB Device" 19 | ftdi_vid_pid 0x0403 0x6010 20 | # channel 1 does not have any functionality 21 | ftdi_channel 0 22 | # just TCK TDI TDO TMS, no reset 23 | ftdi_layout_init 0x0088 0x008b 24 | reset_config none 25 | adapter_khz 10000 26 | 27 | source [find cpld/xilinx-xc7.cfg] 28 | source [find cpld/jtagspi.cfg] 29 | init 30 | 31 | puts [irscan xc7.tap 0x09] 32 | puts [drscan xc7.tap 32 0] 33 | 34 | puts "Programming FPGA..." 35 | pld load 0 Hello.bit 36 | exit 37 | ``` 38 | * Get the .bit file (from the Windows machine) and set the name in the `7series.txt` 39 | * Configure with: `openocd -f 7series.txt` 40 | * On the Mac: `ls -l /dev/cu.*` 41 | * Serial port: `screen /dev/cu.usbserial-.... 115200` 42 | 43 | 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | doit: 3 | echo "Not much useful to be done here" 4 | 5 | clean: 6 | # git clean -fd 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lab Material for Chisel in Digital Electronics 2 2 | 3 | This repository provides lab material for the 4 | [Digital Electronics course (02139)](http://www2.imm.dtu.dk/courses/02139/) at DTU. 5 | Although this lab is customized for the DTU course, it can also serve as 6 | introduction lab for digital design with [Chisel](https://chisel.eecs.berkeley.edu/). 7 | 8 | The lab is based on: 9 | [Digital Design with Chisel](http://www.imm.dtu.dk/~masca/chisel-book.html), by Martin Schoeberl. 10 | 11 | [![Book Cover](figures/cover-small.jpg)](http://www.imm.dtu.dk/~masca/chisel-book.html) 12 | 13 | To use this material you can: 14 | (1) download the repo as a .zip file, 15 | (2) clone the repo to have all material offline (using it also for your solutions), 16 | (3) fork the repo (and clone locally), to be able to contribute back with changes, 17 | or (4) simply just browse it online on GitHub. 18 | 19 | Best is to have all the tools installed on your laptop, 20 | see also: [Setup.md](Setup.md) 21 | 22 | We collect frequently asked questions in the [FAQ.md](FAQ.md). 23 | 24 | **Contributions:** We are happily accepting contributions in the form of 25 | pull requests. Even the fix of a small typo is appreciated. 26 | 27 | ## Lab Overview 28 | 29 | The following list gives an overview of all lab sessions and assignments. 30 | For the Vending Machine related labs please show them to a TA to get a tick. 31 | 32 | * [Lab 1: Hello World in Chisel](lab1) 33 | * [Lab 2: Combinational Circuits in Chisel](lab2) 34 | * [Lab 3: Components and Small Sequential Circuits](lab3) 35 | * [Lab 4: A Simple Tester](lab4) 36 | * [Lab 5: Seven Segment Decoder and Test](lab5) 37 | * [Lab 6: Multiplexed Seven-Segment Display](lab6) 38 | * [Lab 7: Using an External Component: a Serial Port](lab7) 39 | * [Lab 10: Testing the Vending Machine](lab10) 40 | * [Lab 11, 12: The Vending Machine](vending) 41 | 42 | 43 | ## Resources 44 | 45 | * [Setup.md](Setup.md) installation instructions 46 | * [Basys3_Master.xdc](Basys3_Master.xdc) constraint file for pin definition and clock 47 | * [IntelliJ for Scala](https://docs.scala-lang.org/getting-started-intellij-track/getting-started-with-scala-in-intellij.html) 48 | * [Vivado WebPACK](https://www.xilinx.com/products/design-tools/vivado/vivado-webpack.html) 49 | * [The Chisel Jupyter Notebooks](https://mybinder.org/v2/gh/freechipsproject/chisel-bootcamp/master) An online introduction to the Scala language and Chisel. 50 | * [The Chisel Cookbook](https://github.com/freechipsproject/chisel3/wiki/Cookbook) Large FAQ and introduction to Chisel 51 | * [Basys 3](https://reference.digilentinc.com/reference/programmable-logic/basys-3/start?redirect=1) 52 | -------------------------------------------------------------------------------- /Setup.md: -------------------------------------------------------------------------------- 1 | 2 | # Tool Setup 3 | 4 | This documents describes how to setup all tools on Linux/Ubuntu 5 | and on Windows. 6 | Here is a summary of the tools we need: 7 | 8 | * [Java OpenJDK 8 or later (up to 21)](https://adoptopenjdk.net/) 9 | * [sbt](https://www.scala-sbt.org/) 10 | * [IntelliJ](https://www.jetbrains.com/idea/download/) (the free Community version) 11 | * Vivado (e.g. 2023.1) 12 | * Windows: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_Unified_2023.1_0507_1903_Win64.exe 13 | * Linux: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_Unified_2023.1_0507_1903_Lin64.bin 14 | * [GTKWave](http://gtkwave.sourceforge.net/) 15 | * make, git (for command line usage) (alternatively, a GUI Git client, see the section further down) 16 | 17 | ## Ubuntu Virtual Machine 18 | 19 | The easiest way to get all tools installed is to use the Ubuntu virtual machine provided at: 20 | 21 | * [Ubuntu VM](https://patmos-download.compute.dtu.dk/de2lab.ova) 22 | 23 | The user is ```de2lab``` and the password is ```de2lab```. You need the free [Virtual Box](https://www.virtualbox.org/wiki/Downloads) 24 | for this virtual machine. Note, that this VM is BIG. The downloaded file is 43 GB and the extracted virtual machine fills around 77 GB. 25 | 26 | Use the *File* >> *Import Appliance...* option in Virtual Box, to extract the virtual machine from the image. Then start the virtual machine. 27 | In order to bridge the USB connection to your FPGA into the virtual machine, go to *devices* >> *USB* in the top of the virtual machine window 28 | and select the FPGA in the menu. 29 | 30 | 31 | ## Chisel 32 | 33 | Chisel is *just* a library for Scala. And Scala is just a language that executes 34 | on the Java virtual machine (JVM) and uses the Java library. Therefore, you need to have 35 | [Java OpenJDK 8 or later (max 21)](https://adoptopenjdk.net/) installed on your laptop. 36 | 37 | For working on the command line you should also install 38 | [sbt](https://www.scala-sbt.org/), the Scala build tool. 39 | Please note that installing sbt will make the IntelliJ-build process a lot easier as well. 40 | 41 | A nice editor for Chisel/Scala is 42 | [IntelliJ](https://www.jetbrains.com/idea/download/). At the first start 43 | of IntelliJ download the Scala plugin (at Download featured plugins). 44 | 45 | ## Vivado 46 | 47 | Vivado is the synthesize tool from Xilinx for the Basys3 FPGA board. 48 | The WebPACK edition is freely available at: 49 | https://www.xilinx.com/products/design-tools/vivado/vivado-webpack.html 50 | 51 | * Download [Vivado WebPACK](https://www.xilinx.com/products/design-tools/vivado/vivado-webpack.html) 52 | * You need to register with Xilinx 53 | * To save some space you can deselect all devices except Artix-7 54 | * For Linux the installer executable can be run with ```bash Xilinx...``` 55 | * see 56 | [Digilent Installation](https://reference.digilentinc.com/vivado/installing-vivado/start) 57 | for instructions 58 | * Install cable drivers and Digilent board files (according to the above instructions) 59 | 60 | ## Ubuntu/Linux 61 | 62 | This is the log when I prepared the Ubuntu virtual machine for the DE 2 lab. It may be helpful to setup 63 | your Linux system for the DE 2 lab. 64 | 65 | * Install Ubuntu 18.04 LTS, max disc set to 80 GB and 4 GB for memory 66 | * uid: de2lab, pwd: de2lab 67 | * Set time and time zone (important for further installation!) 68 | * Settings - Power - Blank screen: never, Privacy - Aut. Screen Lock - OFF 69 | * Copy the chisel book onto the desktop 70 | * That is my current snapshot 71 | * Install Vivado (in home folder) 72 | * Install cable drivers 73 | * Get digilent board definitions 74 | * Install Java JDK and other tools with: 75 | * ```sudo apt install openjdk-8-jdk git make gtkwave``` 76 | * Install sbt according to the instructions from [sbt download](https://www.scala-sbt.org/download.html) 77 | * Install IntelliJ and the Scala plugin with a launch shortcut in favorites 78 | * Shortcut to GtkWave on desktop 79 | 80 | Instead of running the apt commands manually you can also run the provided ```setup.sh```. 81 | 82 | ## Windows 10 83 | 84 | * Install Vivado (see above) and the Digilent board files 85 | * Install OpenJDK 8 or later (up to 17) from [AdoptOpenJDK](https://adoptopenjdk.net/) 86 | * Install [sbt](https://www.scala-sbt.org/) 87 | * Install [IntelliJ](https://www.jetbrains.com/idea/download/) 88 | * The community edition 89 | * Include Create Desktop Shortcut 90 | * Start IntelliJ to finish the setup 91 | * Select the light UI theme (if you prefer) 92 | * On the featured plugins select Install for Scala 93 | * When importing a project, select the JDK you installed before 94 | * On Project JDK select *New* 95 | * Select *JDK* 96 | * Select the path to your OpenJDK 8 installation, usually something like ```C:\Program Files\AdoptOpenJDK\jdk-8.0.232.09-hotspot\``` 97 | * Download the [GTKWave binaries](https://sourceforge.net/projects/gtkwave/files/) 98 | * Select the latest release that matches the pattern ```gtkwave-{release number}-bin-win32``` 99 | * Extract the downloaded ```.zip``` into a directory of choice 100 | * Run the executable ```gtkwave.exe``` in the folder ```gtkwave\bin\``` 101 | * Put a link to the executable on the desktop 102 | * Copy the PDF of the [Chisel Book](http://www.imm.dtu.dk/~masca/chisel-book.html) on the desktop 103 | * Install a [git client](https://git-scm.com/download/win) 104 | * If you have no prior experience using git, check the followings links for an introduction to the git workflow and the advantages of version-control systems. [1](https://www.youtube.com/watch?v=SWYqp7iY_Tc), [2](https://www.freecodecamp.org/news/what-is-git-and-how-to-use-it-c341b049ae61/). 105 | Do note that most git tutorials emphasize command line usage, but this is by no means a must. There exist several great GUI git clients, examples of which are [Github Desktop](https://desktop.github.com/) and [Fork](https://fork.dev/). 106 | 107 | 108 | The installation can be checked with the first exercise in the lab. Or a quick, partial 109 | check with following commands in the Windows Powershell: 110 | 111 | ``` 112 | javac 113 | sbt 114 | ``` 115 | 116 | ## macOS 117 | 118 | Vivado is not supported under macOS, however, the Chisel tool flow runs fine 119 | on the Mac. You can simulate your design on the Mac and use a virtual machine 120 | (e.g., with Ubuntu) to synthesize your design with Vivado. 121 | 122 | * Install OpenJDK 8 or later (up to 17) from [AdoptOpenJDK](https://adoptopenjdk.net/) 123 | * Install sbt with ```brew install sbt``` 124 | * Install [GTKWave](http://gtkwave.sourceforge.net/) 125 | * For MacOS 14 following installation is possible: 126 | * `brew install --HEAD randomplum/gtkwave/gtkwave` 127 | * see [this issue](https://github.com/gtkwave/gtkwave/issues/250) 128 | * Install [IntelliJ](https://www.jetbrains.com/idea/download/) 129 | * The community edition 130 | * Include Create Desktop Shortcut 131 | * Start IntelliJ to finish the setup 132 | * Select the light UI theme (if you prefer) 133 | * On the featured plugins select Install for Scala 134 | * When importing a project, select the JDK you installed before 135 | * On Project JDK select *New* 136 | * Select *JDK* 137 | * Select the path to your OpenJDK installation 138 | 139 | 140 | ## Mac with Arm chip (M1, M2, or M3) 141 | 142 | * To run Vivado on a Mac with an Arm chip see [MacM1.md](MacM1.md). 143 | 144 | ## Common Error 145 | 146 | Here we collect common issues when installing the tools. Also refer to the [FAQ](FAQ.md) 147 | 148 | -------------------------------------------------------------------------------- /figures/cover-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schoeberl/chisel-lab/9b1fae8d9dc2581debd688ca6c3e17ba894c14c7/figures/cover-small.jpg -------------------------------------------------------------------------------- /figures/decoder.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xmla1Decodera0b0b1b2b3 256 | -------------------------------------------------------------------------------- /figures/mux.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xmla 76 | y 88 | sel 113 | b 138 | -------------------------------------------------------------------------------- /figures/synchronizer.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xmlSynchronous circuit 125 | External world 134 | btn 146 | btnSync 158 | -------------------------------------------------------------------------------- /lab1/Basys3Hello.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a .xdc for the Basys3 rev B board 2 | ## Cut down to the Minimum for the Hello World example 3 | 4 | set_property IOSTANDARD LVCMOS33 [get_ports *] 5 | 6 | ## Clock signal 7 | set_property PACKAGE_PIN W5 [get_ports clock] 8 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 9 | 10 | ## LED and reset button 11 | set_property PACKAGE_PIN U16 [get_ports {io_led}] 12 | set_property PACKAGE_PIN T17 [get_ports reset] 13 | -------------------------------------------------------------------------------- /lab1/NexsysA7Hello.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Nexys A7-100T 2 | ## Cut down to the Minimum for the Hello World example 3 | 4 | set_property IOSTANDARD LVCMOS33 [get_ports *] 5 | 6 | ## Clock signal 7 | set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clock }]; # IO_L12P_T1_MRCC_35 Sch=clk100mhz 8 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clock}]; 9 | 10 | ## LEDs 11 | set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { io_led }]; # IO_L18P_T2_A24_15 Sch=io_led 12 | 13 | ##Buttons 14 | set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L4N_T0_D05_14 Sch=btnu 15 | -------------------------------------------------------------------------------- /lab1/README.md: -------------------------------------------------------------------------------- 1 | # Lab 1: Hello World in Chisel 2 | 3 | The lab session will show you a Hello World example (a blinking LED) in Chisel. 4 | We will explore the tools needed for the Chisel based design flow. 5 | 6 | After the lab you will have a good overview of the tools used to 7 | edit and compile a hardware design coded in Chisel. 8 | You will be able to synthesize this design and configure the FPGA board. 9 | 10 | We assume that you have downloaded the complete lab material from GitHub 11 | and it is placed in folder ```chisel-lab```. 12 | 13 | ## Background Reading 14 | 15 | * This lab is loosely based on Chapter 1 of 16 | *[Digital Design with Chisel](http://www.imm.dtu.dk/~masca/chisel-book.html)* 17 | 18 | ## Exploring and Compiling the Hello World Component 19 | 20 | With IntelliJ import the lab1 project as follows: 21 | 22 | * Start IntelliJ 23 | * When you start IntelliJ the first time, click *Import Project*, otherwise select *File - New - Project from Existing Sources...* 24 | * Select *sbt* 25 | * Navigate to ```.../chisel-lab/lab1``` and select the file ```build.sbt```, press *Open* 26 | * Select the JDK 1.8 (or later) 27 | * On Project JDK select *New* 28 | * Select *JDK* 29 | * Select the path to your OpenJDK 8 installation, something like ```C:\Program Files\AdoptOpenJDK\jdk-8.0.232.09-hotspot\''' 30 | * Press OK on the next dialog box 31 | 32 | This importing from the project may take some time at the first import, as Scala and Chisel files need to be downloaded. Wait until it is finished. 33 | 34 | > If you have an IntelliJ project already open, you can create a new project with: 35 | > *File - New - Project from Existing Sources...* 36 | 37 | Then navigate to the Chisel component ```Hello``` by following in the Project navigator along: *lab1 - src - main - scala - Hello*. Open ```Hello``` with a double click. 38 | 39 | This is a complete Chisel component including generation of a slower logical time 40 | to drive a blinking LED at 1 Hz from the 100 MHz clock from the Basys3 board. 41 | Do not get intimidated by those about 20 lines of code, you will soon understand the 42 | details. Today's lab topic is to get the tool flow working down to a configured FPGA. 43 | 44 | Open the terminal at the bottom of the IntelliJ window start the build process with: 45 | ``` 46 | sbt run 47 | ``` 48 | to compile and run your project. 49 | 50 | In the *Run* window you should see something like: 51 | ``` 52 | [info] Running HelloMain 53 | Hello World, I will now generate the Verilog files! 54 | [info] [0.001] Elaborating design... 55 | [info] [2.205] Done elaborating. 56 | Total FIRRTL Compile Time: 916.6 ms 57 | [success] Total time: 22 s, completed Jul 22, 2019 11:09:25 AM 58 | ``` 59 | This is the output of the Chisel compiler und runtime. To see that the program 60 | runs we provide a friendly greeting message, starting with the famous "Hallo World". 61 | If your design contains errors, you will see error messages in this window. 62 | 63 | Running the Chisel program generates a Verilog file (```Hello.v```) that we 64 | use for synthesizing our design for an FPGA. The content of this file is not 65 | important, but for curiosity you might open it right from within IntelliJ. 66 | 67 | **CLI Alternative:** 68 | 69 | If you do not like to use an IDE, you can work at the command line 70 | (shell, terminal). Use a program editor of you choice and open ```Hello.scala``` 71 | found at ```.../lab1/src/main/scala/Hello.scala```. 72 | You compile and run the *Hello World* in Chisel from the command line with a simple: 73 | 74 | ```bash 75 | sbt run 76 | ``` 77 | 78 | **End CLI Alternative** 79 | 80 | ## Synthesizing and Configuring the FPGA with Vivado. 81 | 82 | We use the Xilinx tool 83 | [Vivado](https://www.xilinx.com/products/design-tools/vivado/vivado-webpack.html) 84 | to synthesize our design and configure the Basys3 board. 85 | 86 | The process is described in detail in the document 87 | *A digital circuit design flow guide using VHDL and Xilinx Vivado 88 | targeting a Digilent BASYS 3 FPGA board* from last semester. 89 | Please use that document (from the first semester). 90 | The following list is only a brief summary. 91 | 92 | ### Vivado Project Creation 93 | 94 | * Open Vivado 95 | * Click *Create Project* 96 | * Click *Next* 97 | * Pick a name and a location and click *Next* 98 | * You might place your project under ```chisel-lab/lab1``` 99 | * Click *Next* to accept an *RTL Project* 100 | * In the next dialog box click *Add Files* and navigate to ```Hello.v``` and add it 101 | * At the *Add Constraints* dialog box clock *Add Files* and select 102 | ```Basis3Hello.xdc``` and press *OK*. 103 | * For the following labs you will need to edit the constraints file derived 104 | from the Basys3 Master constraints file. 105 | * Click *Next* 106 | * In the *Default Part* dialog box select *Boards* and the *Basys3*, press *Next* 107 | * Press *Finish* to create the project 108 | 109 | ### Synthesize and Configure the FPGA Board 110 | 111 | We are just a few clicks away from running our great *Hello World* design in 112 | the Basys3 board. 113 | 114 | * Connect your Basis3 board with the USB cable to your laptop 115 | * Click on *Generate Bitstream* at the bottom of the *Project Manager* to 116 | start synthesis, implementation, and bitstream generation 117 | * This process may take some time (minutes) 118 | * Configure your FPGA with *Program Device* under *Open Hardware Manager* 119 | * Open hardware manager after bitfile generation 120 | * Open target, Auto Connect 121 | * Program device 122 | 123 | You should now see an LED blinking at 1 Hz. 124 | 125 | **Congratulation! You have build your first digital design in Chisel** 126 | 127 | After this lengthy setup, the next run of the design flow should be smooth. 128 | Try to change the ```CNT_MAX``` constant to a slightly smaller value 129 | (e.g., 50000000 instead of 100000000) to change the blinking frequency. 130 | Run the Chisel code in IntelliJ again and synthesize and configure again 131 | with Vivado. The LED should now blink at a different frequency. 132 | Faster or slower? At what frequency? 133 | 134 | ### Simulation Without an FPGA Board 135 | 136 | If it happens that you do not have access to an FPGA board, you can run the 137 | blinking LED in simulation. To avoid to simulate for 100000000 clock cycles 138 | change the factor in ```Hello.scala``` on following line from: 139 | 140 | ``` 141 | val CNT_MAX = (100000000 / 2 - 1).U; 142 | ``` 143 | to 144 | ``` 145 | val CNT_MAX = (50000 / 2 - 1).U; 146 | ``` 147 | and run the simulation with 148 | ``` 149 | sbt test 150 | ``` 151 | You should see in the terminal a *simulation* of the blinking LED. 152 | 153 | -------------------------------------------------------------------------------- /lab1/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" -------------------------------------------------------------------------------- /lab1/src/main/scala/Hello.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Blinking LED: the hardware version of Hello World 3 | * 4 | * Copyright: 2013, Technical University of Denmark, DTU Compute 5 | * Author: Martin Schoeberl (martin@jopdesign.com) 6 | * 7 | */ 8 | 9 | import chisel3._ 10 | 11 | class Hello extends Module { 12 | val io = IO(new Bundle { 13 | val led = Output(UInt(1.W)) 14 | }) 15 | val CNT_MAX = (100000000 / 2 - 1).U 16 | 17 | val cntReg = RegInit(0.U(32.W)) 18 | val blkReg = RegInit(0.U(1.W)) 19 | 20 | cntReg := cntReg + 1.U 21 | when(cntReg === CNT_MAX) { 22 | cntReg := 0.U 23 | blkReg := ~blkReg 24 | } 25 | io.led := blkReg 26 | } 27 | 28 | /** 29 | * An object extending App to generate the Verilog code. 30 | */ 31 | object HelloMain extends App { 32 | println("Hello World, I will now generate the Verilog file!") 33 | emitVerilog(new Hello()) 34 | } 35 | -------------------------------------------------------------------------------- /lab1/src/test/scala/HelloSpec.scala: -------------------------------------------------------------------------------- 1 | import chiseltest._ 2 | import org.scalatest.flatspec.AnyFlatSpec 3 | 4 | class HelloSpec extends AnyFlatSpec with ChiselScalatestTester { 5 | 6 | "Hello" should "pass" in { 7 | test(new Hello()) { dut => 8 | var ledStatus = -1 9 | println("Start the blinking LED") 10 | dut.clock.setTimeout(0) 11 | for (i <- 0 until 100) { 12 | dut.clock.step(10000) 13 | val ledNow = dut.io.led.peekInt().toInt 14 | val s = if (ledNow == 0) "o" else "*" 15 | if (ledStatus != ledNow) { 16 | System.out.println(s) 17 | ledStatus = ledNow 18 | } 19 | } 20 | println("End the blinking LED") 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /lab10/README.md: -------------------------------------------------------------------------------- 1 | # Lab 10: Testing the Vending Machine (Optional) 2 | 3 | In this lab you will write tests for a vending machine. 4 | You are given two implementations of a vending machine as 5 | black boxes. One is correctly implementing the specification, 6 | one contains an error. Find out with your tests which one is 7 | correct and what is the error in the other implementation. 8 | 9 | Note, that for this test you need to have Verilator installed: 10 | https://www.veripool.org/verilator/ 11 | 12 | And Verilator needs a C compiler installed. 13 | 14 | **Due to the requirement of Verilator installation, this lab is 15 | optional. However, it is nevertheless good to work on a test for 16 | you vending machine early on.** 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lab10/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | scalaVersion := "2.13.14" 10 | val chiselVersion = "6.5.0" 11 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 12 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 13 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" -------------------------------------------------------------------------------- /lab10/src/main/scala/VendingMachine.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | class BlackVendingA() extends HasBlackBoxPath { 5 | val io = IO(new Bundle { 6 | val price = Input(UInt(5.W)) 7 | val coin2 = Input(Bool()) 8 | val coin5 = Input(Bool()) 9 | val buy = Input(Bool()) 10 | val releaseCan = Output(Bool()) 11 | val alarm = Output(Bool()) 12 | val seg = Output(UInt(7.W)) 13 | val an = Output(UInt(4.W)) 14 | }) 15 | addPath("./src/main/verilog/VendingA.v") 16 | } 17 | 18 | class BlackVendingB() extends HasBlackBoxPath { 19 | val io = IO(new Bundle { 20 | val price = Input(UInt(5.W)) 21 | val coin2 = Input(Bool()) 22 | val coin5 = Input(Bool()) 23 | val buy = Input(Bool()) 24 | val releaseCan = Output(Bool()) 25 | val alarm = Output(Bool()) 26 | val seg = Output(UInt(7.W)) 27 | val an = Output(UInt(4.W)) 28 | }) 29 | addPath("./src/main/verilog/VendingB.v") 30 | } 31 | 32 | 33 | class VendingMachine(maxCount: Int) extends Module { 34 | val io = IO(new Bundle { 35 | val price = Input(UInt(5.W)) 36 | val coin2 = Input(Bool()) 37 | val coin5 = Input(Bool()) 38 | val buy = Input(Bool()) 39 | val releaseCan = Output(Bool()) 40 | val alarm = Output(Bool()) 41 | val seg = Output(UInt(7.W)) 42 | val an = Output(UInt(4.W)) 43 | }) 44 | 45 | // Switch between the two vending machines here. 46 | val vending = Module(new BlackVendingA) 47 | // val vending = Module(new BlackVendingB) 48 | vending.io <> io 49 | } 50 | 51 | // generate Verilog 52 | object VendingMachine extends App { 53 | emitVerilog(new VendingMachine(100000)) 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /lab10/src/main/verilog/VendingA.v: -------------------------------------------------------------------------------- 1 | module VendingMachine( 2 | input clock, 3 | input reset, 4 | input [4:0] io_price, 5 | input io_coin2, 6 | input io_coin5, 7 | input io_buy, 8 | output io_releaseCan, 9 | output io_alarm, 10 | output [6:0] io_seg, 11 | output [3:0] io_an 12 | ); 13 | `ifdef RANDOMIZE_REG_INIT 14 | reg [31:0] _RAND_0; 15 | reg [31:0] _RAND_1; 16 | reg [31:0] _RAND_2; 17 | reg [31:0] _RAND_3; 18 | reg [31:0] _RAND_4; 19 | reg [31:0] _RAND_5; 20 | reg [31:0] _RAND_6; 21 | reg [31:0] _RAND_7; 22 | reg [31:0] _RAND_8; 23 | reg [31:0] _RAND_9; 24 | reg [31:0] _RAND_10; 25 | `endif // RANDOMIZE_REG_INIT 26 | reg coin2_REG; // @[VendingMachine.scala 16:38] 27 | reg coin2_REG_1; // @[VendingMachine.scala 16:30] 28 | reg coin2_REG_2; // @[VendingMachine.scala 17:37] 29 | wire coin2 = coin2_REG_1 & ~coin2_REG_2; // @[VendingMachine.scala 17:27] 30 | reg coin5_REG; // @[VendingMachine.scala 16:38] 31 | reg coin5_REG_1; // @[VendingMachine.scala 16:30] 32 | reg coin5_REG_2; // @[VendingMachine.scala 17:37] 33 | wire coin5 = coin5_REG_1 & ~coin5_REG_2; // @[VendingMachine.scala 17:27] 34 | reg buySync_REG; // @[VendingMachine.scala 16:38] 35 | reg buySync; // @[VendingMachine.scala 16:30] 36 | reg buy_REG; // @[VendingMachine.scala 17:37] 37 | wire buy = buySync & ~buy_REG; // @[VendingMachine.scala 17:27] 38 | wire [7:0] price = {3'h0,io_price}; // @[Cat.scala 31:58] 39 | reg [7:0] regSum; // @[VendingMachine.scala 37:23] 40 | reg [2:0] stateReg; // @[VendingMachine.scala 39:25] 41 | wire enough = regSum >= price; // @[VendingMachine.scala 41:23] 42 | wire [2:0] _GEN_0 = coin2 ? 3'h1 : stateReg; // @[VendingMachine.scala 45:19 46:18 39:25] 43 | wire _T_1 = 3'h1 == stateReg; // @[VendingMachine.scala 43:21] 44 | wire _T_2 = 3'h2 == stateReg; // @[VendingMachine.scala 43:21] 45 | wire _T_3 = 3'h3 == stateReg; // @[VendingMachine.scala 43:21] 46 | wire [2:0] _GEN_4 = ~buySync ? 3'h0 : stateReg; // @[VendingMachine.scala 69:22 39:25 69:33] 47 | wire [2:0] _GEN_6 = 3'h6 == stateReg ? _GEN_4 : stateReg; // @[VendingMachine.scala 43:21 39:25] 48 | wire [2:0] _GEN_7 = 3'h5 == stateReg ? 3'h6 : _GEN_6; // @[VendingMachine.scala 43:21 72:16] 49 | wire [2:0] _GEN_8 = 3'h4 == stateReg ? _GEN_4 : _GEN_7; // @[VendingMachine.scala 43:21] 50 | wire [2:0] _GEN_9 = 3'h3 == stateReg ? 3'h4 : _GEN_8; // @[VendingMachine.scala 43:21 66:16] 51 | wire [7:0] _add_T = {3'h0,io_price}; // @[VendingMachine.scala 83:35] 52 | wire [7:0] _add_T_3 = 8'sh0 - $signed(_add_T); // @[VendingMachine.scala 83:27] 53 | wire [7:0] _GEN_13 = _T_3 ? $signed(_add_T_3) : $signed(8'sh0); // @[VendingMachine.scala 80:20 83:20] 54 | wire [7:0] _GEN_14 = _T_2 ? $signed(8'sh5) : $signed(_GEN_13); // @[VendingMachine.scala 80:20 82:21] 55 | wire [7:0] add = _T_1 ? $signed(8'sh2) : $signed(_GEN_14); // @[VendingMachine.scala 80:20 81:21] 56 | wire [7:0] _regSum_T_4 = $signed(regSum) + $signed(add); // @[VendingMachine.scala 85:35] 57 | assign io_releaseCan = stateReg == 3'h4; // @[VendingMachine.scala 87:29] 58 | assign io_alarm = stateReg == 3'h6; // @[VendingMachine.scala 88:24] 59 | assign io_seg = 7'h0; // @[VendingMachine.scala 99:10] 60 | assign io_an = 4'h0; // @[VendingMachine.scala 100:9] 61 | always @(posedge clock) begin 62 | coin2_REG <= io_coin2; // @[VendingMachine.scala 16:38] 63 | coin2_REG_1 <= coin2_REG; // @[VendingMachine.scala 16:30] 64 | coin2_REG_2 <= coin2_REG_1; // @[VendingMachine.scala 17:37] 65 | coin5_REG <= io_coin5; // @[VendingMachine.scala 16:38] 66 | coin5_REG_1 <= coin5_REG; // @[VendingMachine.scala 16:30] 67 | coin5_REG_2 <= coin5_REG_1; // @[VendingMachine.scala 17:37] 68 | buySync_REG <= io_buy; // @[VendingMachine.scala 16:38] 69 | buySync <= buySync_REG; // @[VendingMachine.scala 16:30] 70 | buy_REG <= buySync; // @[VendingMachine.scala 17:37] 71 | if (reset) begin // @[VendingMachine.scala 37:23] 72 | regSum <= 8'h0; // @[VendingMachine.scala 37:23] 73 | end else begin 74 | regSum <= _regSum_T_4; // @[VendingMachine.scala 85:10] 75 | end 76 | if (reset) begin // @[VendingMachine.scala 39:25] 77 | stateReg <= 3'h0; // @[VendingMachine.scala 39:25] 78 | end else if (3'h0 == stateReg) begin // @[VendingMachine.scala 43:21] 79 | if (buy) begin // @[VendingMachine.scala 51:17] 80 | if (enough) begin // @[VendingMachine.scala 52:23] 81 | stateReg <= 3'h3; // @[VendingMachine.scala 53:20] 82 | end else begin 83 | stateReg <= 3'h5; // @[VendingMachine.scala 55:20] 84 | end 85 | end else if (coin5) begin // @[VendingMachine.scala 48:19] 86 | stateReg <= 3'h2; // @[VendingMachine.scala 49:18] 87 | end else begin 88 | stateReg <= _GEN_0; 89 | end 90 | end else if (3'h1 == stateReg) begin // @[VendingMachine.scala 43:21] 91 | stateReg <= 3'h0; // @[VendingMachine.scala 60:16] 92 | end else if (3'h2 == stateReg) begin // @[VendingMachine.scala 43:21] 93 | stateReg <= 3'h0; // @[VendingMachine.scala 63:16] 94 | end else begin 95 | stateReg <= _GEN_9; 96 | end 97 | end 98 | // Register and memory initialization 99 | `ifdef RANDOMIZE_GARBAGE_ASSIGN 100 | `define RANDOMIZE 101 | `endif 102 | `ifdef RANDOMIZE_INVALID_ASSIGN 103 | `define RANDOMIZE 104 | `endif 105 | `ifdef RANDOMIZE_REG_INIT 106 | `define RANDOMIZE 107 | `endif 108 | `ifdef RANDOMIZE_MEM_INIT 109 | `define RANDOMIZE 110 | `endif 111 | `ifndef RANDOM 112 | `define RANDOM $random 113 | `endif 114 | `ifdef RANDOMIZE_MEM_INIT 115 | integer initvar; 116 | `endif 117 | `ifndef SYNTHESIS 118 | `ifdef FIRRTL_BEFORE_INITIAL 119 | `FIRRTL_BEFORE_INITIAL 120 | `endif 121 | initial begin 122 | `ifdef RANDOMIZE 123 | `ifdef INIT_RANDOM 124 | `INIT_RANDOM 125 | `endif 126 | `ifndef VERILATOR 127 | `ifdef RANDOMIZE_DELAY 128 | #`RANDOMIZE_DELAY begin end 129 | `else 130 | #0.002 begin end 131 | `endif 132 | `endif 133 | `ifdef RANDOMIZE_REG_INIT 134 | _RAND_0 = {1{`RANDOM}}; 135 | coin2_REG = _RAND_0[0:0]; 136 | _RAND_1 = {1{`RANDOM}}; 137 | coin2_REG_1 = _RAND_1[0:0]; 138 | _RAND_2 = {1{`RANDOM}}; 139 | coin2_REG_2 = _RAND_2[0:0]; 140 | _RAND_3 = {1{`RANDOM}}; 141 | coin5_REG = _RAND_3[0:0]; 142 | _RAND_4 = {1{`RANDOM}}; 143 | coin5_REG_1 = _RAND_4[0:0]; 144 | _RAND_5 = {1{`RANDOM}}; 145 | coin5_REG_2 = _RAND_5[0:0]; 146 | _RAND_6 = {1{`RANDOM}}; 147 | buySync_REG = _RAND_6[0:0]; 148 | _RAND_7 = {1{`RANDOM}}; 149 | buySync = _RAND_7[0:0]; 150 | _RAND_8 = {1{`RANDOM}}; 151 | buy_REG = _RAND_8[0:0]; 152 | _RAND_9 = {1{`RANDOM}}; 153 | regSum = _RAND_9[7:0]; 154 | _RAND_10 = {1{`RANDOM}}; 155 | stateReg = _RAND_10[2:0]; 156 | `endif // RANDOMIZE_REG_INIT 157 | `endif // RANDOMIZE 158 | end // initial 159 | `ifdef FIRRTL_AFTER_INITIAL 160 | `FIRRTL_AFTER_INITIAL 161 | `endif 162 | `endif // SYNTHESIS 163 | endmodule 164 | -------------------------------------------------------------------------------- /lab10/src/main/verilog/VendingB.v: -------------------------------------------------------------------------------- 1 | module VendingMachine( 2 | input clock, 3 | input reset, 4 | input [4:0] io_price, 5 | input io_coin2, 6 | input io_coin5, 7 | input io_buy, 8 | output io_releaseCan, 9 | output io_alarm, 10 | output [6:0] io_seg, 11 | output [3:0] io_an 12 | ); 13 | `ifdef RANDOMIZE_REG_INIT 14 | reg [31:0] _RAND_0; 15 | reg [31:0] _RAND_1; 16 | reg [31:0] _RAND_2; 17 | reg [31:0] _RAND_3; 18 | reg [31:0] _RAND_4; 19 | reg [31:0] _RAND_5; 20 | reg [31:0] _RAND_6; 21 | reg [31:0] _RAND_7; 22 | reg [31:0] _RAND_8; 23 | reg [31:0] _RAND_9; 24 | reg [31:0] _RAND_10; 25 | `endif // RANDOMIZE_REG_INIT 26 | reg coin2_REG; // @[VendingMachine.scala 16:38] 27 | reg coin2_REG_1; // @[VendingMachine.scala 16:30] 28 | reg coin2_REG_2; // @[VendingMachine.scala 17:37] 29 | wire coin2 = coin2_REG_1 & ~coin2_REG_2; // @[VendingMachine.scala 17:27] 30 | reg coin5_REG; // @[VendingMachine.scala 16:38] 31 | reg coin5_REG_1; // @[VendingMachine.scala 16:30] 32 | reg coin5_REG_2; // @[VendingMachine.scala 17:37] 33 | wire coin5 = coin5_REG_1 & ~coin5_REG_2; // @[VendingMachine.scala 17:27] 34 | reg buySync_REG; // @[VendingMachine.scala 16:38] 35 | reg buySync; // @[VendingMachine.scala 16:30] 36 | reg buy_REG; // @[VendingMachine.scala 17:37] 37 | wire buy = buySync & ~buy_REG; // @[VendingMachine.scala 17:27] 38 | wire [7:0] price = {3'h0,io_price}; // @[Cat.scala 31:58] 39 | reg [7:0] regSum; // @[VendingMachine.scala 37:23] 40 | reg [2:0] stateReg; // @[VendingMachine.scala 39:25] 41 | wire enough = regSum >= price; // @[VendingMachine.scala 41:23] 42 | wire [2:0] _GEN_0 = coin2 ? 3'h1 : stateReg; // @[VendingMachine.scala 45:19 46:18 39:25] 43 | wire _T_1 = 3'h1 == stateReg; // @[VendingMachine.scala 43:21] 44 | wire _T_2 = 3'h2 == stateReg; // @[VendingMachine.scala 43:21] 45 | wire _T_3 = 3'h3 == stateReg; // @[VendingMachine.scala 43:21] 46 | wire [2:0] _GEN_4 = ~buySync ? 3'h0 : stateReg; // @[VendingMachine.scala 69:22 39:25 69:33] 47 | wire [2:0] _GEN_6 = 3'h6 == stateReg ? _GEN_4 : stateReg; // @[VendingMachine.scala 43:21 39:25] 48 | wire [2:0] _GEN_7 = 3'h5 == stateReg ? 3'h6 : _GEN_6; // @[VendingMachine.scala 43:21 72:16] 49 | wire [2:0] _GEN_8 = 3'h4 == stateReg ? _GEN_4 : _GEN_7; // @[VendingMachine.scala 43:21] 50 | wire [2:0] _GEN_9 = 3'h3 == stateReg ? 3'h4 : _GEN_8; // @[VendingMachine.scala 43:21 66:16] 51 | wire [7:0] _add_T = {3'h0,io_price}; // @[VendingMachine.scala 83:35] 52 | wire [7:0] _add_T_3 = 8'sh0 - $signed(_add_T); // @[VendingMachine.scala 83:27] 53 | wire [7:0] _GEN_13 = _T_3 ? $signed(_add_T_3) : $signed(8'sh0); // @[VendingMachine.scala 80:20 83:20] 54 | wire [7:0] _GEN_14 = _T_2 ? $signed(8'sh3) : $signed(_GEN_13); // @[VendingMachine.scala 80:20 82:21] 55 | wire [7:0] add = _T_1 ? $signed(8'sh2) : $signed(_GEN_14); // @[VendingMachine.scala 80:20 81:21] 56 | wire [7:0] _regSum_T_4 = $signed(regSum) + $signed(add); // @[VendingMachine.scala 85:35] 57 | assign io_releaseCan = stateReg == 3'h4; // @[VendingMachine.scala 87:29] 58 | assign io_alarm = stateReg == 3'h6; // @[VendingMachine.scala 88:24] 59 | assign io_seg = 7'h0; // @[VendingMachine.scala 99:10] 60 | assign io_an = 4'h0; // @[VendingMachine.scala 100:9] 61 | always @(posedge clock) begin 62 | coin2_REG <= io_coin2; // @[VendingMachine.scala 16:38] 63 | coin2_REG_1 <= coin2_REG; // @[VendingMachine.scala 16:30] 64 | coin2_REG_2 <= coin2_REG_1; // @[VendingMachine.scala 17:37] 65 | coin5_REG <= io_coin5; // @[VendingMachine.scala 16:38] 66 | coin5_REG_1 <= coin5_REG; // @[VendingMachine.scala 16:30] 67 | coin5_REG_2 <= coin5_REG_1; // @[VendingMachine.scala 17:37] 68 | buySync_REG <= io_buy; // @[VendingMachine.scala 16:38] 69 | buySync <= buySync_REG; // @[VendingMachine.scala 16:30] 70 | buy_REG <= buySync; // @[VendingMachine.scala 17:37] 71 | if (reset) begin // @[VendingMachine.scala 37:23] 72 | regSum <= 8'h0; // @[VendingMachine.scala 37:23] 73 | end else begin 74 | regSum <= _regSum_T_4; // @[VendingMachine.scala 85:10] 75 | end 76 | if (reset) begin // @[VendingMachine.scala 39:25] 77 | stateReg <= 3'h0; // @[VendingMachine.scala 39:25] 78 | end else if (3'h0 == stateReg) begin // @[VendingMachine.scala 43:21] 79 | if (buy) begin // @[VendingMachine.scala 51:17] 80 | if (enough) begin // @[VendingMachine.scala 52:23] 81 | stateReg <= 3'h3; // @[VendingMachine.scala 53:20] 82 | end else begin 83 | stateReg <= 3'h5; // @[VendingMachine.scala 55:20] 84 | end 85 | end else if (coin5) begin // @[VendingMachine.scala 48:19] 86 | stateReg <= 3'h2; // @[VendingMachine.scala 49:18] 87 | end else begin 88 | stateReg <= _GEN_0; 89 | end 90 | end else if (3'h1 == stateReg) begin // @[VendingMachine.scala 43:21] 91 | stateReg <= 3'h0; // @[VendingMachine.scala 60:16] 92 | end else if (3'h2 == stateReg) begin // @[VendingMachine.scala 43:21] 93 | stateReg <= 3'h0; // @[VendingMachine.scala 63:16] 94 | end else begin 95 | stateReg <= _GEN_9; 96 | end 97 | end 98 | // Register and memory initialization 99 | `ifdef RANDOMIZE_GARBAGE_ASSIGN 100 | `define RANDOMIZE 101 | `endif 102 | `ifdef RANDOMIZE_INVALID_ASSIGN 103 | `define RANDOMIZE 104 | `endif 105 | `ifdef RANDOMIZE_REG_INIT 106 | `define RANDOMIZE 107 | `endif 108 | `ifdef RANDOMIZE_MEM_INIT 109 | `define RANDOMIZE 110 | `endif 111 | `ifndef RANDOM 112 | `define RANDOM $random 113 | `endif 114 | `ifdef RANDOMIZE_MEM_INIT 115 | integer initvar; 116 | `endif 117 | `ifndef SYNTHESIS 118 | `ifdef FIRRTL_BEFORE_INITIAL 119 | `FIRRTL_BEFORE_INITIAL 120 | `endif 121 | initial begin 122 | `ifdef RANDOMIZE 123 | `ifdef INIT_RANDOM 124 | `INIT_RANDOM 125 | `endif 126 | `ifndef VERILATOR 127 | `ifdef RANDOMIZE_DELAY 128 | #`RANDOMIZE_DELAY begin end 129 | `else 130 | #0.002 begin end 131 | `endif 132 | `endif 133 | `ifdef RANDOMIZE_REG_INIT 134 | _RAND_0 = {1{`RANDOM}}; 135 | coin2_REG = _RAND_0[0:0]; 136 | _RAND_1 = {1{`RANDOM}}; 137 | coin2_REG_1 = _RAND_1[0:0]; 138 | _RAND_2 = {1{`RANDOM}}; 139 | coin2_REG_2 = _RAND_2[0:0]; 140 | _RAND_3 = {1{`RANDOM}}; 141 | coin5_REG = _RAND_3[0:0]; 142 | _RAND_4 = {1{`RANDOM}}; 143 | coin5_REG_1 = _RAND_4[0:0]; 144 | _RAND_5 = {1{`RANDOM}}; 145 | coin5_REG_2 = _RAND_5[0:0]; 146 | _RAND_6 = {1{`RANDOM}}; 147 | buySync_REG = _RAND_6[0:0]; 148 | _RAND_7 = {1{`RANDOM}}; 149 | buySync = _RAND_7[0:0]; 150 | _RAND_8 = {1{`RANDOM}}; 151 | buy_REG = _RAND_8[0:0]; 152 | _RAND_9 = {1{`RANDOM}}; 153 | regSum = _RAND_9[7:0]; 154 | _RAND_10 = {1{`RANDOM}}; 155 | stateReg = _RAND_10[2:0]; 156 | `endif // RANDOMIZE_REG_INIT 157 | `endif // RANDOMIZE 158 | end // initial 159 | `ifdef FIRRTL_AFTER_INITIAL 160 | `FIRRTL_AFTER_INITIAL 161 | `endif 162 | `endif // SYNTHESIS 163 | endmodule 164 | -------------------------------------------------------------------------------- /lab10/src/test/scala/VendingTester.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class VendingTester extends AnyFlatSpec with ChiselScalatestTester { 6 | "Vending machine test" should "pass" in { 7 | test(new VendingMachine(20)).withAnnotations(Seq(WriteVcdAnnotation, VerilatorBackendAnnotation)) { c => 8 | // test(new VendingMachine(20)).withAnnotations(Seq(WriteVcdAnnotation, IcarusBackendAnnotation)) { c => 9 | 10 | def pay2 = { 11 | c.io.coin2.poke(true.B) 12 | c.clock.step(5) 13 | c.io.coin2.poke(false.B) 14 | c.clock.step(4) 15 | } 16 | 17 | c.io.price.poke(7.U) 18 | pay2 19 | // continue here 20 | // Should we be able to buy a soda now? 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /lab2/README.md: -------------------------------------------------------------------------------- 1 | # Lab 2: Combinational Circuits in Chisel 2 | 3 | The lab session will show you how to describe combinational circuits 4 | with Chisel. You get modules, where you need to add the description of 5 | combinational circuits. You will run unit tests to test your circuit. 6 | Optional you can also synthesize your circuit for an FPGA and test it 7 | with the FPGA board. 8 | 9 | Having the tests before the implementation is called test driven 10 | development and is common in software development, but it is also good practice 11 | in hardware design. This time the tests are given to you, in a later lab session 12 | you will write your own tests. 13 | 14 | After the lab you will know how to use the few constructs to describe 15 | common combinational building blocks, such as mulitplexer, encoder, 16 | decoder, and function tables in Chisel. 17 | 18 | We assume that you have downloaded the complete lab material from GitHub 19 | and it is placed in folder ```chisel-lab```. 20 | 21 | ## Background Reading 22 | 23 | * This lab is loosely based on Chapter 2 and 5 of 24 | *[Digital Design with Chisel](http://www.imm.dtu.dk/~masca/chisel-book.html)* 25 | 26 | ## Compiling and Testing of Combinational Circuits 27 | 28 | Today's lab topic is to describe selected combinational building blocks in Chisel. 29 | We provide the testing code for your circuits. You have completed all exercises 30 | when all tests (run with ```sbt test```) complete without an error. 31 | 32 | With IntelliJ import the lab2 project as follows: 33 | 34 | * Start IntelliJ 35 | * Click *Import Project*, or on a running IntelliJ: *File - New - 36 | Project from Existing Source...* 37 | * Navigate to ```.../chisel-lab/lab2``` and select the file ```build.sbt```, press *Open* 38 | * Make sure to select a JDK 1.8 or later 39 | * Press OK on the next dialog box 40 | 41 | ### A Majority Voter 42 | 43 | We start as first exercise with a relative simple circuit, a majority voter. 44 | 45 | Navigate to the Chisel component ```Majority``` by following in the Project navigator along: *lab2 - src - main - scala - Majority*. 46 | Open ```Majority``` with a double click. 47 | 48 | This is a Chisel component that shall implement the majority voting of three 49 | signals (```a```, ```b```, and ```c```). Majority voting means that the output of 50 | the circuit is the majority of the inputs, e.g., if ```a==1```, ```b==0```, and 51 | ```c==1``` the result shall be ```1```. See Dally 3.6 for a solution in VHDL. 52 | Your task is to implement that circuit in Chisel. 53 | 54 | 55 | Open the terminal at the bottom of the IntelliJ window and run: 56 | ``` 57 | sbt test 58 | ``` 59 | to compile and test your project. 60 | 61 | In the *Run* window you should see several tests failing, similar to: 62 | ``` 63 | [info] *** 4 TESTS FAILED *** 64 | [error] Failed: Total 6, Failed 4, Errors 0, Passed 2 65 | ``` 66 | 67 | For the majority circuit we provide three *tests*: 68 | 69 | 1. ```MajorityPrinter```: A test that simply prints the logic table of the 70 | circuit. This form of test is helpful for debugging, but not for 71 | automated regression tests. 72 | 1. ```MajoritySimple```: A too simple test that covers only some cases 73 | and will succeed for the too simple default implementation. This shows 74 | you that testing can usually not guarantee a 100% correct solution. 75 | 1. ```MajorityFull```: is an exhaustive tester that covers all possibilities. 76 | This is the best form of a tester. However, exhaustive testing is only 77 | possible for very simple circuits. 78 | 79 | You run a single test with following command in the terminal window: 80 | 81 | ``` 82 | sbt "testOnly MajorityPrinter" 83 | ``` 84 | 85 | Run the ```MajorityPrinter``` and watch the printout of the logic table: 86 | 87 | ``` 88 | Logic table for Majority 89 | a b c -> out 90 | false false false -> 0 91 | true false false -> 1 92 | false true false -> 0 93 | true true false -> 1 94 | false false true -> 0 95 | true false true -> 1 96 | false true true -> 0 97 | true true true -> 1 98 | [info] MajorityPrinter: 99 | [info] Majority print results 100 | [info] - should pass 101 | [info] Run completed in 1 second, 246 milliseconds. 102 | [info] Total number of tests run: 1 103 | [info] Suites: completed 1, aborted 0 104 | [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 105 | [info] All tests passed. 106 | ``` 107 | 108 | This shows that the default implementation just copies the value of ```a``` 109 | to the output. Clearly not a majority circuit. Change the Majority component 110 | to implement the majority circuit. You can watch the logic table for debugging. 111 | However, at the end run: 112 | ``` 113 | sbt "testOnly MajorityFull" 114 | ``` 115 | to make sure you have completed this exercise. 116 | 117 | 118 | ### Optional: Generating Hardware 119 | 120 | In lab1 you have learned how to generate hardware to run in an FPGA. 121 | In the current lab exercise you use testing to run your combinational circuit. 122 | However, we can also run those circuits on the FPGA board and use switches 123 | and LEDs to test the circuits. 124 | 125 | Generate the Verilog description by running the Majority App with: 126 | ``` 127 | sbt run 128 | ``` 129 | If there are more than one App in a project, you need to select which one 130 | to run, the ```Majority```. Like the test cases, you can also directly 131 | select which App to run by: 132 | ``` 133 | sbt "runMain Majority" 134 | ``` 135 | 136 | Create a Xiling Vivado project with the source file ```Majority.v``` and 137 | the constraint file ```majority.xdc``` that includes the pin definitions. 138 | Synthesize and implement the design, create the bitstream, configure the 139 | FPGA, and test the device with the three switches ```sw0```, ```sw1```, 140 | and ```sw2```. 141 | 142 | Although testing in real hardware gives confidence that the design works 143 | it has two drawbacks: (1) synthesizing, even a small design, consumes a 144 | considerable amount of time and (2) it is manual. 145 | With tests written in Chisel the testing is faster and easier to reproduce 146 | and automate. 147 | 148 | ### A Multiplexer (Mux) 149 | 150 | ![Mux](../figures/mux.svg) 151 | 152 | A multiplexer selects between different input signals. In the above figure 153 | it is a 2:1 multiplexer. With ```sel``` we route either input ```a``` or 154 | input ```b``` to output ```y```. We assume in this example that ```a``` 155 | is selected when ```sel``` is ```0``` or ```false```, otherwise ```b```. 156 | 157 | Open the ```Mux2``` component to implement the multiplexer. 158 | You can test your implementation with: 159 | ``` 160 | sbt "testOnly Mux2Spec" 161 | ``` 162 | 163 | A low-level solution would be to describe the multiplexing function 164 | as Boolean equation, such as ```(!sel & a) | (sel & b)```. 165 | This is correct (try it in ```Mux2```), but hard to read. 166 | Furthermore, this equation does not work so easily with multi-bit 167 | values. 168 | 169 | A better solution is to conditional assignment, in Chisel 170 | with ```when``` and ```.otherwise```. 171 | Look it up in Chapter 5 of the Chisel book and implement the 172 | Multiplexer. 173 | 174 | As multiplexing is such a fundamental operation, that Chisel 175 | provides a multiplexer component ```Mux```. 176 | Implement you final version of a multiplexer by using the ```Mux``` 177 | component. 178 | 179 | The *cool* thing on the ```Mux``` component is that it can multiplex 180 | arbitrary complex data structures, not just a vector of bits. 181 | Any user defined data type will work with ```Mux```. 182 | 183 | ### A Decoder 184 | 185 | ![Decoder](../figures/decoder.svg) 186 | 187 | The next exercise is to describe a 2-bit decoder. The test is called 188 | as follows: 189 | 190 | ``` 191 | sbt "testOnly DecoderSpec" 192 | ``` 193 | 194 | You can find the skeleton of the exercise in ```Decoder.scala```. 195 | Fill in the missing statement(s). A Chisel ```switch``` statement is probably 196 | the most elegant solution, but other solutions are valid as well. 197 | 198 | ### Addition/Subtraction Circuit 199 | 200 | As a last exercise you have to build a small arithmetic circuit. 201 | The circuit shall be able to add or subtract two unsigned integer. 202 | One input (```selAdd```) decides if the two numbers are added or 203 | subtracted (sounds like a multiplexer). The test is called as: 204 | 205 | ``` 206 | sbt "testOnly AddSubSpec" 207 | ``` 208 | 209 | The file for your solution is ```AddSub```. 210 | 211 | -------------------------------------------------------------------------------- /lab2/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" -------------------------------------------------------------------------------- /lab2/majority.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Basys3 rev B board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | set_property IOSTANDARD LVCMOS33 [get_ports *] 7 | 8 | 9 | ## Clock signal 10 | set_property PACKAGE_PIN W5 [get_ports clock] 11 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 12 | 13 | ## Switches 14 | set_property PACKAGE_PIN V17 [get_ports {io_a}] 15 | set_property PACKAGE_PIN V16 [get_ports {io_b}] 16 | set_property PACKAGE_PIN W16 [get_ports {io_c}] 17 | 18 | 19 | ## LEDs 20 | set_property PACKAGE_PIN U16 [get_ports {io_out}] 21 | 22 | 23 | ##Buttons 24 | # btnR proposed as reset 25 | #set_property PACKAGE_PIN T17 [get_ports btnR] 26 | set_property PACKAGE_PIN T17 [get_ports reset] -------------------------------------------------------------------------------- /lab2/src/main/scala/AddSub.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class AddSub extends Module { 4 | val io = IO(new Bundle { 5 | val a = Input(UInt(4.W)) 6 | val b = Input(UInt(4.W)) 7 | val selAdd = Input(Bool()) 8 | val y = Output(UInt(4.W)) 9 | }) 10 | 11 | val a = io.a 12 | val b = io.b 13 | val selAdd = io.selAdd 14 | val res = WireDefault(0.U(4.W)) 15 | 16 | // ***** your code starts here ***** 17 | 18 | // res := ???? 19 | 20 | // ***** your code ends here ***** 21 | 22 | io.y := res 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /lab2/src/main/scala/Decoder.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | class Decoder extends Module { 5 | val io = IO(new Bundle { 6 | val sel = Input(UInt(2.W)) 7 | val out = Output(UInt(4.W)) 8 | }) 9 | 10 | val sel = io.sel 11 | val dec = WireDefault(0.U) 12 | 13 | // ***** your code starts here ***** 14 | 15 | // ***** your code ends here ***** 16 | 17 | io.out := dec 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /lab2/src/main/scala/Majority.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * A 3-bit majority circuit. 3 | */ 4 | 5 | import chisel3._ 6 | 7 | class Majority extends Module { 8 | val io = IO(new Bundle { 9 | val a = Input(Bool()) 10 | val b = Input(Bool()) 11 | val c = Input(Bool()) 12 | val out = Output(Bool()) 13 | }) 14 | 15 | val a = io.a 16 | val b = io.b 17 | val c = io.c 18 | 19 | // This too simple implementation will pass the most simplistic tests only (MajoritySimple). 20 | // Rewrite this expression to express the majority to pass all tests. 21 | 22 | // ***** your code starts here ***** 23 | val res = a 24 | // ***** your code ends here ***** 25 | 26 | // Hint: this initial exercise shall familiarize you with the testing environment. 27 | // The solution is following expression: (a & b) | (a & c) | (b & c) 28 | 29 | io.out := res 30 | } 31 | 32 | // generate Verilog 33 | object Majority extends App { 34 | emitVerilog(new Majority()) 35 | } 36 | -------------------------------------------------------------------------------- /lab2/src/main/scala/Mux2.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class Mux2 extends Module { 4 | val io = IO(new Bundle { 5 | val a = Input(Bool()) 6 | val b = Input(Bool()) 7 | val sel = Input(Bool()) 8 | val y = Output(Bool()) 9 | }) 10 | 11 | val a = io.a 12 | val b = io.b 13 | val sel = io.sel 14 | val res = Wire(Bool()) 15 | 16 | // ***** your code starts here ***** 17 | 18 | res := b 19 | 20 | // ***** your code ends here ***** 21 | 22 | io.y := res 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /lab2/src/test/scala/AddSubSpec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class AddSubSpec extends AnyFlatSpec with ChiselScalatestTester { 6 | "AddSub" should "pass" in { 7 | 8 | test(new AddSub) { dut => 9 | dut.io.a.poke(1.U) 10 | dut.io.b.poke(2.U) 11 | dut.io.selAdd.poke(true.B) 12 | dut.clock.step() 13 | dut.io.y.expect(3.U) 14 | dut.io.a.poke(3.U) 15 | dut.io.b.poke(2.U) 16 | dut.io.selAdd.poke(false.B) 17 | dut.clock.step() 18 | dut.io.y.expect(1.U) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lab2/src/test/scala/DecoderSpec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class DecoderSpec extends AnyFlatSpec with ChiselScalatestTester { 6 | "Decoder" should "pass" in { 7 | test(new Decoder) { dut => 8 | for (n <- 0 to 3) { 9 | dut.io.sel.poke(n.U) 10 | dut.clock.step(1) 11 | val res = 1 << n 12 | println(s"$n $res") 13 | dut.io.out.expect(res.U) 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lab2/src/test/scala/MajoritySpec.scala: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Test a 3-bit majority circuit. 4 | */ 5 | 6 | import chisel3._ 7 | import chiseltest._ 8 | import org.scalatest.flatspec.AnyFlatSpec 9 | 10 | class MajoritySimple extends AnyFlatSpec with ChiselScalatestTester { 11 | "Majority simple test" should "pass" in { 12 | test(new Majority) { dut => 13 | // Simple tests 14 | dut.io.a.poke(false.B) 15 | dut.io.b.poke(false.B) 16 | dut.io.c.poke(false.B) 17 | dut.clock.step(1) 18 | dut.io.out.expect(false.B) 19 | dut.io.a.poke(true.B) 20 | dut.io.b.poke(true.B) 21 | dut.io.c.poke(true.B) 22 | dut.clock.step(1) 23 | dut.io.out.expect(true.B) 24 | } 25 | } 26 | } 27 | 28 | class MajorityPrinter extends AnyFlatSpec with ChiselScalatestTester { 29 | "Majority print results" should "pass" in { 30 | test(new Majority) { dut => 31 | println("Logic table for Majority") 32 | println(" a b c -> out") 33 | for (i <- 0 to 7) { 34 | val a = (i & 1) == 1 35 | val b = ((i & 2) >> 1) == 1 36 | val c = ((i & 4) >> 2) == 1 37 | dut.io.a.poke(a.B) 38 | dut.io.b.poke(b.B) 39 | dut.io.c.poke(c.B) 40 | dut.clock.step(1) 41 | val out = dut.io.out.peekInt().toInt 42 | println(s"$a $b $c -> $out") 43 | } 44 | } 45 | } 46 | } 47 | 48 | class MajorityFull extends AnyFlatSpec with ChiselScalatestTester { 49 | "Majority exhaustive test" should "pass" in { 50 | test(new Majority) { dut => 51 | // Exhaustive testing 52 | for (i <- 0 to 7) { 53 | val a = i & 1 54 | val b = (i & 2) >> 1 55 | val c = (i & 4) >> 2 56 | val res = a+b+c > 1 57 | dut.io.a.poke((a == 1).B) 58 | dut.io.b.poke((b == 1).B) 59 | dut.io.c.poke((c == 1).B) 60 | dut.clock.step(1) 61 | dut.io.out.expect(res.B) 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /lab2/src/test/scala/Mux2Spec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class Mux2Spec extends AnyFlatSpec with ChiselScalatestTester { 6 | "Mux2 " should "pass" in { 7 | test(new Mux2) { dut => 8 | for (a <- 0 to 1) { 9 | for (b <- 0 to 1) { 10 | for (sel <- 0 to 1) { 11 | dut.io.a.poke((a == 1).B) 12 | dut.io.b.poke((b == 1).B) 13 | dut.io.sel.poke((sel == 1).B) 14 | dut.clock.step(1) 15 | val res = if (sel == 0) a else b 16 | // println(a + " " + b + " " + sel + " " + res) 17 | dut.io.y.expect((res ==1).B) 18 | } 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lab3/README.md: -------------------------------------------------------------------------------- 1 | # Lab 3: Components and Small Sequential Circuits 2 | 3 | The lab session will show you how to use components, called modules in Chisel, 4 | and how to describe small sequential circuits. 5 | 6 | We assume that you have downloaded the complete lab material from GitHub 7 | and it is placed in folder ```chisel-lab```. 8 | 9 | Similar to the first two labs you import the projects in IntelliJ. 10 | We will not repeat these instructions here. See the former labs for the 11 | instruction. 12 | 13 | We provide the testing code for your circuits. You have completed all 14 | (Chisel code) exercises when all tests (run with ```sbt test```) complete 15 | without an error. 16 | 17 | Have fun! 18 | 19 | ## Background Reading 20 | 21 | * This lab is loosely based on Chapter 2, 4, and 6 of 22 | *[Digital Design with Chisel](http://www.imm.dtu.dk/~masca/chisel-book.html)* 23 | 24 | 25 | ## Using Components 26 | 27 | The following two exercises teach you how to create and use components/moduls. 28 | 29 | ### Use the Mux2 30 | 31 | We provide a ```Mux2``` component, a 2:1 multiplexer with single-bit inputs. 32 | For the first exercise edit ```UseMux2```. There you shall create an instance of 33 | ```Mux2``` and connect it to the signals: ```a```, ```b```, ```sel```, and ```res```. 34 | Run the specific test for this exercise with: 35 | 36 | ``` 37 | sbt "testOnly UseMux2Spec" 38 | ``` 39 | 40 | ### Design a 4:1 Multiplexer 41 | 42 | In digital design we often build larger, more complex designs by combining 43 | smaller and simpler components. In this exercise you shall build a 4:1 multiplexer 44 | out of 2:1 multiplexers (the ```Mux2``` component.) The ```Mux4``` component has 45 | a 2-bit select input (```sel```), four inputs (```a```, ```b```, ```c```, and ```d```), 46 | and one output (```y```). Select ```a``` when ```sel``` is ```"b00"```, 47 | ```b``` when ```sel``` is ```"b01"```, and so on. 48 | 49 | Before writing Chisel code draw the solution on a sheet of paper and discuss the solution. 50 | When you are confident in your design (done on paper), code it up in Chisel in ```Mux4```. 51 | Run the test for the 4:1 multiplexer with: 52 | 53 | ``` 54 | sbt "testOnly Mux4Spec" 55 | ``` 56 | 57 | ## Small Sequential Circuits 58 | 59 | The next four exercise teach you to create and use registers to build 60 | sequential circuits. 61 | 62 | ### Build a Two Clock Cycles Delay 63 | 64 | The next exercise is a simple circuit containing two registers that form a 2 clock 65 | cycles delay. This circuit is also used as an input synchronizer for external asynchronous 66 | signals. Below you find the schematics of this circuit. 67 | 68 | ![Synchronizer](../figures/synchronizer.svg) 69 | 70 | Implement the two clock cycle delay in ```Delay``` and run the test for the two clock cycles 71 | delay with: 72 | 73 | ``` 74 | sbt "testOnly DelaySpec" 75 | ``` 76 | 77 | ### A Free Running Counter 78 | 79 | Implement a 4-bit free running counter. That means the counter counts from 0 up to 80 | 15 and then restarts at 0. Put your implementation into ```Count15``` and run the 81 | test with: 82 | 83 | ``` 84 | sbt "testOnly Count15Spec" 85 | ``` 86 | 87 | ### Counter with a Limit 88 | 89 | The next counter shall count up till 6 and then restart at 0. 90 | Put your implementation into ```Count6``` and run the 91 | test with: 92 | 93 | ``` 94 | sbt "testOnly Count6Spec" 95 | ``` 96 | 97 | ### An Accumulator 98 | 99 | As the last exercise on small sequential circuits implement an accumulator (register). 100 | The accumulator adds the number provided in ```din```. It can be reset to 0 by 101 | asserting ```setZero```. The accumulator shall be set to 0 on reset. 102 | Implement the accumulator in ```Accu``` and test it with: 103 | 104 | ``` 105 | sbt "testOnly AccuSpec" 106 | ``` 107 | 108 | ## Schematic from Chisel Code 109 | 110 | We have several different ways to specify digital circuits. We can draw block 111 | diagrams as a visual representation or write Chisel code for simulation and 112 | synthesis of the circuit. It is important to be able to translate between those 113 | spcifications. In this part of the exercise you get Chisel code and shall draw 114 | a schematic of the circuit. Discuss your schematic with a TA. 115 | 116 | ### Code Example 1 117 | 118 | ``` 119 | when(ok) { 120 | light := GREEN 121 | } .otherwise { 122 | light := RED 123 | } 124 | ``` 125 | 126 | ### Code Example 2 127 | 128 | ``` 129 | val dout = WireDefault(0.U) 130 | 131 | switch(sel) { 132 | is(0.U) { dout := 0.U } 133 | is(1.U) { dout := 11.U } 134 | is(2.U) { dout := 22.U } 135 | is(3.U) { dout := 33.U } 136 | is(4.U) { dout := 44.U } 137 | is(5.U) { dout := 55.U } 138 | } 139 | 140 | ``` 141 | 142 | ### Code Example 3 143 | 144 | ``` 145 | val regAcc = RegInit(0.U(8.W)) 146 | 147 | switch(sel) { 148 | is(0.U) { regAcc := regAcc} 149 | is(1.U) { regAcc := 0.U} 150 | is(2.U) { regAcc := regAcc + din} 151 | is(3.U) { regAcc := regAcc - din} 152 | } 153 | ``` 154 | 155 | ## An App to Generate Verilog (Optional) 156 | 157 | This is an optional exercise, if you run out of work during the lab ;-) 158 | 159 | * Write an App to generate Verilog for the Mux4 circuit 160 | (an object that extends App, in ```Mux4.scala```) 161 | * Adapt the .xdc file for the circuit 162 | (e.g., start from the Basis .xdc file in the root of the lab folders) 163 | * Generate a Vivdao project 164 | * Synthesize 165 | * Configure the FPGA 166 | * Test the Mux4 in the FPGA with the switches and one LED 167 | 168 | -------------------------------------------------------------------------------- /lab3/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" -------------------------------------------------------------------------------- /lab3/src/main/scala/Accu.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class Accu extends Module { 4 | val io = IO(new Bundle { 5 | val din = Input(UInt(8.W)) 6 | val setZero = Input(Bool()) 7 | val dout = Output(UInt(8.W)) 8 | }) 9 | 10 | val res = Wire(UInt()) 11 | 12 | // ***** your code starts here ***** 13 | 14 | res := 0.U // dummy code to make it compile 15 | 16 | // ***** your code ends here ***** 17 | 18 | io.dout := res 19 | } -------------------------------------------------------------------------------- /lab3/src/main/scala/Count15.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class Count15 extends Module { 4 | val io = IO(new Bundle { 5 | val dout = Output(UInt(8.W)) 6 | }) 7 | 8 | val res = Wire(UInt()) 9 | 10 | // ***** your code starts here ***** 11 | 12 | res := 0.U // dummy code to make it compile 13 | 14 | // ***** your code ends here ***** 15 | 16 | io.dout := res 17 | } -------------------------------------------------------------------------------- /lab3/src/main/scala/Count6.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class Count6 extends Module { 4 | val io = IO(new Bundle { 5 | val dout = Output(UInt(8.W)) 6 | }) 7 | 8 | val res = Wire(UInt()) 9 | 10 | // ***** your code starts here ***** 11 | 12 | res := 0.U // dummy code to make it compile 13 | 14 | // ***** your code ends here ***** 15 | 16 | io.dout := res 17 | } -------------------------------------------------------------------------------- /lab3/src/main/scala/Delay.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class Delay extends Module { 4 | val io = IO(new Bundle { 5 | val din = Input(UInt(8.W)) 6 | val dout = Output(UInt(8.W)) 7 | }) 8 | 9 | val res = Wire(UInt()) 10 | 11 | // ***** your code starts here ***** 12 | 13 | // below is dummy code to make this example compile 14 | res := io.din 15 | 16 | // ***** your code ends here ***** 17 | 18 | io.dout := res 19 | } -------------------------------------------------------------------------------- /lab3/src/main/scala/Mux2.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | /** 4 | * Mux2 is a simple one-bit multiplexer. 5 | * Use it in UseMux2 and to build the Mux4 circuit. 6 | */ 7 | 8 | class Mux2 extends Module { 9 | val io = IO(new Bundle { 10 | val a = Input(UInt(1.W)) 11 | val b = Input(UInt(1.W)) 12 | val sel = Input(UInt(1.W)) 13 | val y = Output(UInt(1.W)) 14 | }) 15 | 16 | io.y := io.a 17 | when (io.sel === 1.U) { 18 | io.y := io.b 19 | } 20 | } -------------------------------------------------------------------------------- /lab3/src/main/scala/Mux4.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | /** 4 | * Use Mux2 components to build a 4:1 multiplexer 5 | */ 6 | 7 | class Mux4 extends Module { 8 | val io = IO(new Bundle { 9 | val a = Input(UInt(1.W)) 10 | val b = Input(UInt(1.W)) 11 | val c = Input(UInt(1.W)) 12 | val d = Input(UInt(1.W)) 13 | val sel = Input(UInt(2.W)) 14 | val y = Output(UInt(1.W)) 15 | }) 16 | 17 | // ***** your code starts here ***** 18 | 19 | // create a Mux4 component out of Mux2 components 20 | // and connect the input and output ports. 21 | 22 | // below is dummy code to make this example compile 23 | io.y := io.c 24 | 25 | // ***** your code ends here ***** 26 | } -------------------------------------------------------------------------------- /lab3/src/main/scala/UseMux2.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class UseMux2 extends Module { 4 | val io = IO(new Bundle { 5 | val sel = Input(UInt(1.W)) 6 | val dout = Output(UInt(1.W)) 7 | }) 8 | 9 | val a = 1.U 10 | val b = 0.U 11 | val sel = io.sel 12 | val res = Wire(UInt()) 13 | 14 | // ***** your code starts here ***** 15 | 16 | // create a Mux2 component and connect it to a, b, sel, and res 17 | 18 | // below is dummy code to make this example compile 19 | res := b 20 | 21 | // ***** your code ends here ***** 22 | 23 | io.dout := res 24 | } -------------------------------------------------------------------------------- /lab3/src/test/scala/AccuSpec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class AccuSpec extends AnyFlatSpec with ChiselScalatestTester { 6 | "Accu " should "pass" in { 7 | test(new Accu) {dut => 8 | dut.io.din.poke(0.U) 9 | dut.io.setZero.poke(false.B) 10 | // reset value 11 | dut.io.dout.expect(0.U) 12 | dut.clock.step(1) 13 | dut.io.dout.expect(0.U) 14 | dut.io.din.poke(7.U) 15 | dut.clock.step(1) 16 | dut.io.dout.expect(7.U) 17 | dut.clock.step(1) 18 | dut.io.dout.expect(14.U) 19 | dut.io.setZero.poke(true.B) 20 | dut.clock.step(1) 21 | dut.io.dout.expect(0.U) 22 | dut.io.setZero.poke(false.B) 23 | dut.io.din.poke(3.U) 24 | dut.clock.step(1) 25 | dut.io.dout.expect(3.U) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lab3/src/test/scala/Count15Spec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class Count15Spec extends AnyFlatSpec with ChiselScalatestTester { 6 | "Count15 " should "pass" in { 7 | test(new Count15) { dut => 8 | dut.io.dout.expect(0.U) 9 | for (n <- 0 to 40) { 10 | dut.io.dout.expect((n & 0xf).U) 11 | dut.clock.step(1) 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lab3/src/test/scala/Count6Spec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class Count6Spec extends AnyFlatSpec with ChiselScalatestTester { 6 | "Count6 " should "pass" in { 7 | test(new Count6) { dut => 8 | dut.io.dout.expect(0.U) 9 | for (n <- 0 to 40) { 10 | dut.io.dout.expect((n % 7).U) 11 | dut.clock.step(1) 12 | } 13 | } 14 | } 15 | } 16 | 17 | class Count6WaveSpec extends AnyFlatSpec with ChiselScalatestTester { 18 | "CountWave6 " should "pass" in { 19 | test(new Count6).withAnnotations(Seq(WriteVcdAnnotation)) { dut => 20 | dut.clock.step(20) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /lab3/src/test/scala/DelaySpec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class DelaySpec extends AnyFlatSpec with ChiselScalatestTester { 6 | "Delay " should "pass" in { 7 | test(new Delay) { dut => 8 | dut.io.din.poke(0.U) 9 | dut.clock.step(5) 10 | dut.io.dout.expect(0.U) 11 | 12 | dut.io.din.poke(123.U) 13 | dut.clock.step(1) 14 | dut.io.dout.expect(0.U) 15 | dut.clock.step(1) 16 | dut.io.dout.expect(123.U) 17 | 18 | dut.io.din.poke(0.U) 19 | dut.clock.step(1) 20 | dut.io.dout.expect(123.U) 21 | dut.clock.step(1) 22 | dut.io.dout.expect(0.U) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lab3/src/test/scala/Mux2Spec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | // Just have a simple Mux2 test here as a reference 6 | class Mux2Spec extends AnyFlatSpec with ChiselScalatestTester { 7 | "Mux2 " should "pass" in { 8 | test(new Mux2) { dut => 9 | for (a <- 0 to 1) { 10 | for (b <- 0 to 1) { 11 | for (sel <- 0 to 1) { 12 | dut.io.a.poke(a.U) 13 | dut.io.b.poke(b.U) 14 | dut.io.sel.poke(sel.U) 15 | dut.clock.step(1) 16 | val res = if (sel == 0) a else b 17 | // println(a + " " + b + " " + sel + " " + res) 18 | dut.io.y.expect(res.U) 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab3/src/test/scala/Mux4Spec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class Mux4Spec extends AnyFlatSpec with ChiselScalatestTester { 6 | "Mux4 " should "pass" in { 7 | test(new Mux4) { dut => 8 | for (n <- 0 to 15) { 9 | for (sel <- 0 to 3) { 10 | dut.io.a.poke((n & 0x1).U) 11 | dut.io.b.poke(((n >> 1) & 0x1).U) 12 | dut.io.c.poke(((n >> 2) & 0x1).U) 13 | dut.io.d.poke(((n >> 3) & 0x1).U) 14 | dut.io.sel.poke(sel.U) 15 | dut.clock.step(1) 16 | 17 | val res = (n >> sel) & 0x1 18 | 19 | // println(n + " " + sel + " " + res) 20 | dut.io.y.expect(res.U) 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lab3/src/test/scala/UseMux2Spec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class UseMux2Spec extends AnyFlatSpec with ChiselScalatestTester { 6 | "UseMux2 " should "pass" in { 7 | test(new UseMux2) { dut => 8 | dut.io.sel.poke(0.U) 9 | dut.clock.step(1) 10 | dut.io.dout.expect(1.U) 11 | dut.io.sel.poke(1.U) 12 | dut.clock.step(1) 13 | dut.io.dout.expect(0.U) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lab4/README.md: -------------------------------------------------------------------------------- 1 | # Lab 4: Testing 2 | 3 | ## Background Reading 4 | 5 | * Chapter 3 of 6 | *[Digital Design with Chisel](http://www.imm.dtu.dk/~masca/chisel-book.html)* 7 | 8 | ## Use IntelliJ 9 | 10 | With IntelliJ import the lab project as follows: 11 | 12 | * Start IntelliJ 13 | * Click *Import Project*, or on a running IntelliJ: *File - New - 14 | Project from Existing Source...* 15 | * Navigate to ```.../lab4``` and select the file ```build.sbt```, press *Open* 16 | * Press OK on the next dialog box 17 | 18 | 19 | ## Mux5 20 | 21 | In this part you shall write test code for a 5:1 multiplexer. The interface 22 | of the multiplexer is: 23 | 24 | ```scala 25 | class Mux5 extends Module { 26 | val io = IO(new Bundle { 27 | val a = Input(UInt(8.W)) 28 | val b = Input(UInt(8.W)) 29 | val c = Input(UInt(8.W)) 30 | val d = Input(UInt(8.W)) 31 | val e = Input(UInt(8.W)) 32 | val sel = Input(UInt(3.W)) 33 | val y = Output(UInt(8.W)) 34 | }) 35 | ..... 36 | } 37 | ``` 38 | 39 | Write the test code for the ```Mux5``` implementation. Try **not** to 40 | look into the implementation. The implementation has errors. 41 | Your job is to show those errors with your test code. You do not 42 | need to correct the errors in ```Mux5```. 43 | 44 | * There is a *starting* code given in ```src/test/scala```. 45 | * Use ChiselTest and edit the code 46 | in ```src/test/scala```, and run your test with ```sbt test```. 47 | * The empty test will pass, however, you need to do a test that shows 48 | that there is an error. Your test shall fail at the end. 49 | * Try to find out what the error is just with your testing, not showing 50 | into the DUT. 51 | 52 | ## Heap 53 | 54 | In this part you will write test code for a component which should determine the largest number in a sequence of numbers. 55 | 56 | The component supports two operations to interact with the sequence of numbers which is stored internally in the component. On the one hand, a single new number can be inserted into the sequence. On the other hand, the largest number of the sequence can be removed. 57 | 58 | 59 | The interface of the component is: 60 | ```scala 61 | val io = IO(new Bundle { 62 | val op = Input(Heap.Operation()) 63 | val newValue = Input(UInt(8.W)) 64 | val root = Output(UInt(8.W)) 65 | val empty = Output(Bool()) 66 | val full = Output(Bool()) 67 | val valid = Input(Bool()) 68 | val ready = Output(Bool()) 69 | }) 70 | ``` 71 | 72 | The capacity of the component is limited to fit 8 numbers in the internal sequence. The empty and full flags are used to signal that none or 8 numbers are in the sequence, respectively. 73 | 74 | The ready and valid flags are used to coordinate communication between the component and the outside world. When the component is not busy, it asserts `io.ready` and all output signals are considered stable. 75 | 76 | When the outside world wants to issue an operation, it asserts `io.valid` and indicates the type of operation at the same time on `io.op`. If the operation is an insertion, the new number is provided on `io.newValue` which is 8-bit wide. 77 | 78 | The operation is started after `io.valid` and `io.ready` are both asserted in the same clock cycle. The operation is finished when `io.ready` is asserted again and the results of the operation can be observed on the outputs of the component. 79 | 80 | The following timing diagram visualizes the issuing of operations using the ready-valid interface. 81 | 82 | ![Timing Diagram](../figures/heap_timing.svg) 83 | 84 | The operation types are referred to using `Operation.Insert` and `Operation.RemoveRoot` in Chisel. In the test code, you can simply apply these when poking `io.op`: 85 | 86 | ```scala 87 | dut.io.op.poke(Operation.Insert) 88 | ``` 89 | 90 | You can now write test code to verify the correct behavior of the component. There are two intentional errors added to the dut. One relates to the integrity of the stored values and another relates to the empty/full flags of the dut. You will find the errors by checking that the following statements hold: 91 | 92 | - The dut asserts empty after all numbers have been removed 93 | - The dut asserts full when 8 numbers have been inserted 94 | - A non-empty dut always presents the currently largest number in the sequence on `io.root` when `io.ready` is asserted 95 | - The inserted sequence of values contains the same values as the sequence of values observed on `io.root` when removing the root continuously 96 | - Inserting new values when the dut asserts full does not change the internal sequence 97 | - The dut deasserts full after a remove operation has finished on a previously full dut 98 | 99 | **Note** that each test runs on a *new* instance of the dut. 100 | 101 | ### Hints 102 | 103 | Once you observe a data integrity error in your tests, take a look at `src/main/scala/heap/HeapMemory.scala` and try to find the error. 104 | 105 | Once you observe an issue with the empty/full flags, take a look at `src/main/scala/heap/HeapControl.scala` to find the error. 106 | 107 | 108 | -------------------------------------------------------------------------------- /lab4/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" -------------------------------------------------------------------------------- /lab4/src/main/scala/Mux5.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | /** 5 | * A broken 5:1 multiplexer 6 | */ 7 | 8 | class Mux5 extends Module { 9 | val io = IO(new Bundle { 10 | val a = Input(UInt(8.W)) 11 | val b = Input(UInt(8.W)) 12 | val c = Input(UInt(8.W)) 13 | val d = Input(UInt(8.W)) 14 | val e = Input(UInt(8.W)) 15 | val sel = Input(UInt(3.W)) 16 | val y = Output(UInt(8.W)) 17 | }) 18 | 19 | io.y := 1.U 20 | switch(io.sel) { 21 | is("b000".U) { io.y := io.a } 22 | is("b001".U) { io.y := 1.U } 23 | is("b010".U) { io.y := io.c } 24 | is("b011".U) { io.y := io.d } 25 | is("b101".U) { io.y := io.e } 26 | } 27 | } 28 | 29 | object MuxHW extends App { 30 | emitVerilog(new Mux5(), Array("--target-dir", "generated")) 31 | } -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/Fetcher.scala: -------------------------------------------------------------------------------- 1 | 2 | import Fetcher.State 3 | import chisel3._ 4 | import chisel3.util._ 5 | import heap.{Indexed, ValidTagged} 6 | 7 | object Fetcher { 8 | 9 | class Request(params: Heap.Parameters) extends Bundle { 10 | import params._ 11 | val index = UInt(log2Ceil(n+1).W) 12 | val size = UInt(log2Ceil(n+2).W) 13 | val valid = Bool() 14 | } 15 | class Response(params: Heap.Parameters) extends Bundle { 16 | import params._ 17 | val parent = Indexed(log2Ceil(n+1).W, UInt(w.W)) 18 | val children = Vec(k, ValidTagged(Indexed(log2Ceil(n+1).W, UInt(w.W)))) 19 | val valid = Bool() 20 | } 21 | object State extends ChiselEnum { 22 | val Idle, RequestParent, RequestChildren, ReceiveChildren = Value 23 | } 24 | } 25 | 26 | class Fetcher(params: Heap.Parameters) extends Module { 27 | import params._ 28 | 29 | val io = IO(new Bundle { 30 | val req = Input(new Fetcher.Request(params)) 31 | val res = Output(new Fetcher.Response(params)) 32 | val mem = new HeapMemory.ReadAccess(params) 33 | }) 34 | 35 | val stateReg = RegInit(State.Idle) 36 | val validReg = RegInit(0.B) 37 | 38 | val sizeReg = RegInit(0.U(log2Ceil(n+2).W)) 39 | 40 | val parentIndexReg = RegInit(0.U(log2Ceil(n+1).W)) 41 | val childIndexReg = RegInit(VecInit(Seq.fill(k)(0.U(log2Ceil(n+1).W)))) 42 | val parentReg = RegInit(0.U(w.W)) 43 | val childrenReg = RegInit(VecInit(Seq.fill(k)(0.U(w.W)))) 44 | val maskReg = RegInit(VecInit(Seq.fill(k)(0.B))) 45 | io.res.parent := Indexed.fromTuple(parentReg -> parentIndexReg) 46 | 47 | io.res.children := (childrenReg, childIndexReg, maskReg).zipped.map { case (item, index, valid) => 48 | ValidTagged(valid, Indexed.fromTuple(item -> index)) 49 | } 50 | 51 | io.res.valid := 0.B 52 | io.mem.withSiblings := 0.B 53 | io.mem.index := parentIndexReg 54 | 55 | switch(stateReg) { 56 | is(State.Idle) { 57 | stateReg := Mux(io.req.valid, State.RequestParent, State.Idle) 58 | 59 | parentIndexReg := io.req.index 60 | sizeReg := io.req.size 61 | 62 | io.res.valid := validReg 63 | } 64 | is(State.RequestParent) { 65 | stateReg := State.RequestChildren 66 | 67 | childIndexReg := VecInit(Seq.tabulate(k)( i => (parentIndexReg << log2Ceil(k)).asUInt + (i+1).U)) 68 | 69 | io.mem.index := parentIndexReg 70 | } 71 | is(State.RequestChildren) { 72 | stateReg := State.ReceiveChildren 73 | 74 | parentReg := io.mem.values(0) 75 | 76 | io.mem.index := childIndexReg(0) 77 | io.mem.withSiblings := 1.B 78 | } 79 | is(State.ReceiveChildren) { 80 | stateReg := State.Idle 81 | 82 | childrenReg := io.mem.values 83 | maskReg := VecInit(childIndexReg.map(_ < sizeReg)) 84 | 85 | validReg := 1.B 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/Heap.scala: -------------------------------------------------------------------------------- 1 | 2 | import chisel3._ 3 | import chisel3.util._ 4 | 5 | object Heap { 6 | case class Parameters( 7 | n: Int, // Maximum number of elements 8 | k: Int, // Order of the heap 9 | w: Int, // item width 10 | ) { 11 | require(isPow2(k), "The order of the heap needs to be a power of 2") 12 | } 13 | object Operation extends ChiselEnum { 14 | val Insert, RemoveRoot = Value 15 | } 16 | class Request(params: Heap.Parameters) extends Bundle { 17 | import params._ 18 | val op = Input(Heap.Operation()) 19 | val newValue = Input(UInt(w.W)) 20 | val root = Output(UInt(w.W)) 21 | val empty = Output(Bool()) 22 | val full = Output(Bool()) 23 | val valid = Input(Bool()) 24 | val ready = Output(Bool()) 25 | } 26 | } 27 | 28 | class Heap(params: Heap.Parameters) extends Module { 29 | import params._ 30 | 31 | val io = IO(new Heap.Request(params)) 32 | 33 | object Components { 34 | val fetcher = Module(new Fetcher(params)) 35 | val swapper = Module(new Swapper(params)) 36 | val memory = Module(new HeapMemory(params)) 37 | val control = Module(new HeapControl(params)) 38 | val heapifier = Module(new Heapifier(params)) 39 | val maxFinder = Module(new MaxFinder(params)) 40 | } 41 | 42 | when(Components.control.io.mem.requestRead) { 43 | Components.memory.io.read.index := Components.control.io.mem.read.index 44 | Components.memory.io.read.withSiblings := 0.B 45 | } otherwise { 46 | Components.memory.io.read <> Components.fetcher.io.mem 47 | } 48 | 49 | Components.control.io.mem.read.values := Components.memory.io.read.values 50 | Components.fetcher.io.mem.values := Components.memory.io.read.values 51 | 52 | when(Components.control.io.mem.write.valid) { 53 | Components.memory.io.write <> Components.control.io.mem.write 54 | } otherwise { 55 | Components.memory.io.write <> Components.swapper.io.mem 56 | } 57 | 58 | Components.fetcher.io.req <> Components.control.io.fetcher 59 | Components.fetcher.io.res <> Components.maxFinder.io.fetcher 60 | Components.heapifier.io.maxFinder <> Components.maxFinder.io.res 61 | Components.heapifier.io.res <> Components.control.io.heapifier 62 | Components.heapifier.io.swapper <> Components.swapper.io.req 63 | 64 | Components.control.io.req.valid := io.valid 65 | Components.control.io.req.op := io.op 66 | Components.control.io.req.newValue := io.newValue 67 | 68 | io.ready := Components.control.io.req.ready 69 | io.empty := Components.control.io.req.empty 70 | io.full := Components.control.io.req.full 71 | io.root := Components.memory.io.root 72 | 73 | } 74 | -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/HeapControl.scala: -------------------------------------------------------------------------------- 1 | 2 | import HeapControl.State 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | object HeapControl { 7 | class Request(params: Heap.Parameters) extends Bundle { 8 | import params._ 9 | val op = Input(Heap.Operation()) 10 | val newValue = Input(UInt(w.W)) 11 | val empty = Output(Bool()) 12 | val full = Output(Bool()) 13 | val valid = Input(Bool()) 14 | val ready = Output(Bool()) 15 | } 16 | object State extends ChiselEnum { 17 | val Idle, WriteNewTail, IssueFetchUp, WaitForResUp, FetchTail, WriteTailToRoot, IssueFetchDown, WaitForResDown = Value 18 | } 19 | } 20 | 21 | class HeapControl(params: Heap.Parameters) extends Module { 22 | import params._ 23 | 24 | val io = IO(new Bundle { 25 | val req = new HeapControl.Request(params) 26 | val mem = new Bundle { 27 | val read = new HeapMemory.ReadAccess(params) 28 | val write = new HeapMemory.WriteAccess(params) 29 | val requestRead = Output(Bool()) 30 | } 31 | val fetcher = Output(new Fetcher.Request(params)) 32 | val heapifier = Input(new Heapifier.Response(params)) 33 | }) 34 | 35 | val stateReg = RegInit(State.Idle) 36 | 37 | val sizeReg = RegInit(0.U(log2Ceil(n+2).W)) 38 | val subtreeIndexReg = RegInit(0.U(log2Ceil(n+1).W)) 39 | val newValueReg = RegInit(0.U(w.W)) 40 | val tailReg = RegInit(0.U(w.W)) 41 | 42 | def parent(index: UInt): UInt = ((index - 1.U) >> log2Ceil(k)).asUInt 43 | def firstChild(index: UInt): UInt = (index << log2Ceil(k)).asUInt + 1.U 44 | 45 | 46 | val tailIndex = sizeReg - 1.U 47 | val full = RegInit(0.B) 48 | when(sizeReg === n.U) { full := 1.B } 49 | 50 | io.req.empty := sizeReg === 0.U 51 | io.req.full := full 52 | io.req.ready := 0.B 53 | 54 | io.fetcher.index := subtreeIndexReg 55 | io.fetcher.size := sizeReg 56 | io.fetcher.valid := 0.B 57 | 58 | io.mem.read := DontCare 59 | io.mem.requestRead := 0.B 60 | io.mem.write := DontCare 61 | io.mem.write.valid := 0.B 62 | 63 | switch(stateReg) { 64 | is(State.Idle) { 65 | newValueReg := io.req.newValue 66 | io.req.ready := 1.B 67 | 68 | io.mem.read.index := tailIndex 69 | io.mem.requestRead := 1.B 70 | 71 | when(io.req.valid) { 72 | when(io.req.op === Heap.Operation.Insert) { 73 | stateReg := Mux(full, State.Idle, State.WriteNewTail) 74 | } otherwise { 75 | when(sizeReg < 2.U) { 76 | sizeReg := 0.U 77 | stateReg := State.Idle 78 | } otherwise { 79 | stateReg := State.FetchTail 80 | } 81 | } 82 | } otherwise { 83 | stateReg := State.Idle 84 | } 85 | } 86 | is(State.WriteNewTail) { 87 | io.mem.write.value := newValueReg 88 | io.mem.write.index := sizeReg 89 | io.mem.write.valid := 1.B 90 | 91 | sizeReg := sizeReg + 1.U 92 | subtreeIndexReg := parent(sizeReg) 93 | 94 | stateReg := Mux(sizeReg === 0.U, State.Idle, State.IssueFetchUp) 95 | } 96 | is(State.IssueFetchUp) { 97 | io.fetcher.valid := 1.B 98 | 99 | stateReg := State.WaitForResUp 100 | } 101 | is(State.WaitForResUp) { 102 | when(io.heapifier.valid) { 103 | when(io.heapifier.swapped && subtreeIndexReg =/= 0.U) { 104 | subtreeIndexReg := parent(subtreeIndexReg) 105 | stateReg := State.IssueFetchUp 106 | } otherwise { 107 | stateReg := State.Idle 108 | } 109 | } otherwise { 110 | stateReg := State.WaitForResUp 111 | } 112 | } 113 | is(State.FetchTail) { 114 | tailReg := io.mem.read.values(0) 115 | 116 | stateReg := State.WriteTailToRoot 117 | } 118 | is(State.WriteTailToRoot) { 119 | io.mem.write.value := tailReg 120 | io.mem.write.index := 0.U 121 | io.mem.write.valid := 1.B 122 | 123 | sizeReg := sizeReg - 1.U 124 | subtreeIndexReg := 0.U 125 | 126 | stateReg := Mux(sizeReg === 2.U, State.Idle, State.IssueFetchDown) 127 | } 128 | is(State.IssueFetchDown) { 129 | io.fetcher.valid := 1.B 130 | 131 | stateReg := State.WaitForResDown 132 | } 133 | is(State.WaitForResDown) { 134 | when(io.heapifier.valid) { 135 | when(io.heapifier.swapped && firstChild(io.heapifier.largest) < sizeReg) { 136 | subtreeIndexReg := io.heapifier.largest 137 | stateReg := State.IssueFetchDown 138 | 139 | } otherwise { 140 | stateReg := State.Idle 141 | } 142 | } otherwise { 143 | stateReg := State.WaitForResDown 144 | } 145 | } 146 | 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/HeapMemory.scala: -------------------------------------------------------------------------------- 1 | 2 | import chisel3._ 3 | import chisel3.util.{log2Ceil, UIntToOH} 4 | import HeapMemory.split 5 | 6 | object HeapMemory { 7 | 8 | class ReadAccess(params: Heap.Parameters) extends Bundle { 9 | import params._ 10 | val index = Output(UInt(log2Ceil(n+1).W)) 11 | val withSiblings = Output(Bool()) 12 | val values = Input(Vec(k, UInt(w.W))) 13 | } 14 | 15 | class WriteAccess(params: Heap.Parameters) extends Bundle { 16 | import params._ 17 | val index = Output(UInt(log2Ceil(n+1).W)) 18 | val value = Output(UInt(w.W)) 19 | val valid = Output(Bool()) 20 | } 21 | 22 | // split UInt at given index (index is included in upper chunk) 23 | def split(index: UInt)(at: Int): (UInt,UInt) = index(index.getWidth - 1, at) -> index(at - 1, 0) 24 | 25 | 26 | } 27 | 28 | class HeapMemory(params: Heap.Parameters) extends Module { 29 | import params._ 30 | 31 | 32 | val io = IO(new Bundle { 33 | val read = Flipped(new HeapMemory.ReadAccess(params)) 34 | val write = Flipped(new HeapMemory.WriteAccess(params)) 35 | val root = Output(UInt(w.W)) 36 | }) 37 | 38 | val banks = Seq.fill(k)(SyncReadMem(n/k, UInt(w.W))) 39 | val rootReg = RegInit(0.U(w.W)) 40 | io.root := rootReg 41 | 42 | val (readRow, readColumn) = split(io.read.index - 1.U)(log2Ceil(k)) 43 | val readValues = VecInit(banks.map(_.read(readRow))) 44 | io.read.values := readValues 45 | io.read.values(0) := readValues(0) + 1.U 46 | when(RegNext(!io.read.withSiblings)) { 47 | io.read.values(0) := Mux(RegNext(io.read.index === 0.U), rootReg, readValues(RegNext(readColumn))) 48 | } 49 | 50 | val (writeRow, writeColumn) = split(io.write.index - 1.U)(log2Ceil(k)) 51 | val writeBankMask = UIntToOH(writeColumn).asBools 52 | when(io.write.valid) { 53 | when(io.write.index === 0.U) { 54 | rootReg := io.write.value 55 | } otherwise { 56 | banks.zip(writeBankMask).foreach { case (b,e) => 57 | when(e) { b.write(writeRow, io.write.value) } 58 | } 59 | } 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/Heapifier.scala: -------------------------------------------------------------------------------- 1 | 2 | import Heapifier.State 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | object Heapifier { 7 | 8 | class Response(params: Heap.Parameters) extends Bundle { 9 | import params._ 10 | val largest = UInt(log2Ceil(n+1).W) 11 | val swapped = Bool() 12 | val valid = Bool() 13 | } 14 | object State extends ChiselEnum { 15 | val Idle, IssueSwap, WaitForSwap = Value 16 | } 17 | 18 | } 19 | 20 | class Heapifier(params: Heap.Parameters) extends Module { 21 | import params._ 22 | 23 | val io = IO(new Bundle { 24 | val res = Output(new Heapifier.Response(params)) 25 | val maxFinder = Input(new MaxFinder.Result(params)) 26 | val swapper = Flipped(new Swapper.Request(params)) 27 | }) 28 | 29 | val stateReg = RegInit(State.Idle) 30 | val swapRequired = !io.maxFinder.isParent 31 | val swapRequiredReg = RegInit(0.B) 32 | 33 | io.res.largest := io.maxFinder.largest.index 34 | io.res.swapped := swapRequiredReg 35 | io.res.valid := 0.B 36 | 37 | io.swapper.values(0) := io.maxFinder.parent 38 | io.swapper.values(1) := io.maxFinder.largest 39 | io.swapper.valid := 0.B 40 | 41 | switch(stateReg) { 42 | is(State.Idle) { 43 | stateReg := Mux(RegNext(!io.maxFinder.valid) && io.maxFinder.valid, State.IssueSwap, State.Idle) 44 | } 45 | is(State.IssueSwap) { 46 | swapRequiredReg := swapRequired 47 | when(swapRequired) { 48 | io.swapper.valid := 1.B 49 | stateReg := State.WaitForSwap 50 | } otherwise { 51 | stateReg := State.Idle 52 | io.res.valid := 1.B 53 | io.res.swapped := 0.B 54 | } 55 | } 56 | is(State.WaitForSwap) { 57 | stateReg := Mux(io.swapper.ready, State.Idle, State.WaitForSwap) 58 | when(io.swapper.ready) { 59 | io.res.valid := 1.B 60 | } 61 | } 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/MaxFinder.scala: -------------------------------------------------------------------------------- 1 | 2 | import MaxFinder.ParentWrapper 3 | import chisel3._ 4 | import chisel3.util._ 5 | import heap.{Delay, Indexed} 6 | 7 | object MaxFinder { 8 | class Result(params: Heap.Parameters) extends Bundle { 9 | import params._ 10 | val largest = Indexed(log2Ceil(n+1).W, UInt(w.W)) 11 | val parent = Indexed(log2Ceil(n+1).W, UInt(w.W)) 12 | val isParent = Bool() 13 | val valid = Bool() 14 | } 15 | object ParentWrapper { 16 | def apply[T <: Data](isParent: Bool, item: T): ParentWrapper[T] = { 17 | val w = Wire(new ParentWrapper(chiselTypeOf(item))) 18 | w.item := item 19 | w.isParent := isParent 20 | w 21 | } 22 | } 23 | class ParentWrapper[T <: Data](gen: T) extends Bundle { 24 | val isParent = Bool() 25 | val item = gen 26 | } 27 | } 28 | 29 | class MaxFinder(params: Heap.Parameters) extends Module { 30 | import params._ 31 | 32 | val io = IO(new Bundle { 33 | val fetcher = Input(new Fetcher.Response(params)) 34 | val res = Output(new MaxFinder.Result(params)) 35 | }) 36 | 37 | val pipelineDepth = log2Ceil(k) + 1 38 | 39 | val maxChild = io.fetcher.children.reduceTree { (l, r) => 40 | RegNext(Mux(r.valid && r.data.item > l.data.item, r, l)) 41 | } 42 | val maxItem = RegNext(Mux(maxChild.valid && maxChild.data.item > io.fetcher.parent.item, ParentWrapper(0.B, maxChild.data), ParentWrapper(1.B, io.fetcher.parent))) 43 | io.res.largest := maxItem.item 44 | io.res.parent := io.fetcher.parent 45 | io.res.isParent := maxItem.isParent 46 | io.res.valid := Delay(io.fetcher.valid, pipelineDepth) 47 | 48 | } 49 | -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/Swapper.scala: -------------------------------------------------------------------------------- 1 | 2 | import Swapper.State 3 | import chisel3._ 4 | import chisel3.util._ 5 | import heap.Indexed 6 | 7 | object Swapper { 8 | 9 | class Request(params: Heap.Parameters) extends Bundle { 10 | import params._ 11 | val values = Input(Vec(2, Indexed(log2Ceil(n+1).W, UInt(w.W)))) 12 | val valid = Input(Bool()) 13 | val ready = Output(Bool()) 14 | } 15 | object State extends ChiselEnum { 16 | val Idle, WriteFirst, WriteSecond = Value 17 | } 18 | 19 | } 20 | 21 | class Swapper(params: Heap.Parameters) extends Module { 22 | import params._ 23 | 24 | val io = IO(new Bundle { 25 | val req = new Swapper.Request(params) 26 | val mem = new HeapMemory.WriteAccess(params) 27 | }) 28 | 29 | val stateReg = RegInit(State.Idle) 30 | val valuesReg = Reg(Vec(2, Indexed(log2Ceil(n+1).W, UInt(w.W)))) 31 | 32 | io.req.ready := 0.B 33 | io.mem := DontCare 34 | io.mem.valid := 0.B 35 | 36 | switch(stateReg) { 37 | is(State.Idle) { 38 | stateReg := Mux(io.req.valid, State.WriteFirst, State.Idle) 39 | valuesReg := io.req.values 40 | io.req.ready := 1.B 41 | } 42 | is(State.WriteFirst) { 43 | stateReg := State.WriteSecond 44 | 45 | io.mem.index := valuesReg(0).index 46 | io.mem.value := valuesReg(1).item 47 | io.mem.valid := 1.B 48 | } 49 | is(State.WriteSecond) { 50 | stateReg := State.Idle 51 | 52 | io.mem.index := valuesReg(1).index 53 | io.mem.value := valuesReg(0).item 54 | io.mem.valid := 1.B 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /lab4/src/main/scala/heap/package.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.internal.firrtl.Width 3 | import chisel3.util.log2Ceil 4 | 5 | import java.io.{File, PrintWriter} 6 | import scala.annotation.tailrec 7 | 8 | package object heap { 9 | 10 | class TestHeap extends Heap(Heap.Parameters(8, 2, 8)) 11 | 12 | object Delay { 13 | def apply[T <: Data](x: T, cycles: Int = 1): T = if (cycles == 0) x else RegNext(Delay(x, cycles - 1), init = 0.U.asTypeOf(x)) 14 | } 15 | 16 | 17 | object Indexed { 18 | def fromTuple[T <: Data](init: (T, UInt)): Indexed[T] = { 19 | val w = Wire(new Indexed(init._2.getWidth.W, chiselTypeOf(init._1))) 20 | w.item := init._1 21 | w.index := init._2 22 | w 23 | } 24 | 25 | def apply[T <: Data](indexWidth: Width, typeGen: => T): Indexed[T] = new Indexed(indexWidth, typeGen) 26 | } 27 | 28 | class Indexed[T <: Data](indexWidth: Width, typeGen: => T) extends Bundle { 29 | val item = typeGen 30 | val index = UInt(indexWidth) 31 | } 32 | 33 | object ValidTagged { 34 | def apply[T <: Data](typeGen: => T): ValidTagged[T] = new ValidTagged(typeGen) 35 | 36 | def apply[T <: Data](valid: Bool, data: T): ValidTagged[T] = { 37 | val v = Wire(ValidTagged(chiselTypeOf(data))) 38 | v.valid := valid 39 | v.data := data 40 | v 41 | } 42 | } 43 | 44 | class ValidTagged[T <: Data](typeGen: => T) extends Bundle { 45 | val valid = Bool() 46 | val data = typeGen 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /lab4/src/test/scala/HeapTest.scala: -------------------------------------------------------------------------------- 1 | 2 | import heap._ 3 | import Heap.Operation 4 | import chisel3._ 5 | import chiseltest._ 6 | import org.scalatest.flatspec.AnyFlatSpec 7 | 8 | class HeapTest extends AnyFlatSpec with ChiselScalatestTester { 9 | 10 | behavior of "Heap" 11 | 12 | it should "present the currently largest number on io.root while ready and not empty" in { 13 | test(new TestHeap) { dut => 14 | 15 | // setup a new operation 16 | dut.io.op.poke(Operation.Insert) 17 | dut.io.newValue.poke(220.U) 18 | dut.io.valid.poke(1.B) 19 | 20 | // step to start operation 21 | dut.clock.step() 22 | 23 | // the operation has been initiated and we can deassert valid 24 | dut.io.valid.poke(0.B) 25 | 26 | // wait for the dut to get ready again 27 | while (!dut.io.ready.peekBoolean()) dut.clock.step() 28 | 29 | // the inserted value should appear as the largest value for now 30 | dut.io.root.expect(220.U) 31 | 32 | // write more test code here 33 | 34 | } 35 | } 36 | 37 | it should "not change the stored values" in { 38 | // Insert a series of values and remove the root until 39 | // the heap is empty while saving the root values. 40 | // The set of saved values should be the same as the 41 | // set of inserted values. 42 | test(new TestHeap) { dut => 43 | // write your test code here 44 | } 45 | } 46 | 47 | it should "assert empty after all numbers have been removed" in { 48 | test(new TestHeap) { dut => 49 | // write your test code here 50 | } 51 | } 52 | 53 | it should "assert full when 8 numbers have been inserted" in { 54 | test(new TestHeap) { dut => 55 | // write your test code here 56 | } 57 | } 58 | 59 | it should "deassert full after one number is removed when it was full" in { 60 | test(new TestHeap) { dut => 61 | // write your test code here 62 | } 63 | } 64 | 65 | it should "not change the sequence if new insertions are issued when it is full" in { 66 | test(new TestHeap) { dut => 67 | // write your test code here 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /lab4/src/test/scala/Mux5Test.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class Mux5Test extends AnyFlatSpec with ChiselScalatestTester { 6 | "Mux5 " should "pass" in { 7 | test(new Mux5()) { dut => 8 | // write your test here 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lab5/README.md: -------------------------------------------------------------------------------- 1 | # Lab 5: Seven-Segment Decoder and Test 2 | 3 | This lab is your first step toward your final project, the vending 4 | machine. 5 | 6 | 7 | ## Seven Segment Decoder 8 | 9 | You have to provide the table for the seven-segment decoder 10 | in ```SevenSegDecoder.scala```. 11 | Read the [Basys 3](https://reference.digilentinc.com/reference/programmable-logic/basys-3/start?redirect=1) 12 | documentation and the .xdc file on which segment is connected to which pin. 13 | 14 | The project contains a nice tester that prints out your encoding. 15 | Therefore, you can work on your table until getting it right without 16 | needing to resort to the slow synthesis for the FPGA. Run the test with: 17 | 18 | 19 | ``` 20 | sbt "testOnly SevenSegDecoderSpec" 21 | ``` 22 | 23 | When you are happy with the test results, generate Verilog with: 24 | 25 | ``` 26 | sbt "runMain SevenSegDecoder" 27 | ``` 28 | 29 | Then, create a Vivado project for the 7-segment decoder, synthesize 30 | your design, and configure the FPGA. Test the 7-segment decoder with 31 | the switches. 32 | 33 | An .xdc file (```sevenseg.xdc```) with the pin definitions is available. 34 | 35 | ## Test Drive the Seven-Segment Display 36 | 37 | The second part of the lab is your next step toward your vending machine. 38 | 39 | The circuit consists of the seven-segment decoder and the test circuit. 40 | The test circuit shall drive the seven-segment display with a counter 41 | to show all possible values. The counter shall count at a frequency 42 | of around 2 Hz for easy following by a human. 43 | 44 | Reuse your table from the first part of the lab. 45 | 46 | The test circuit shall be implemented in ```CountSevenSeg.scala```. You need 47 | to instantiate the ```SevenSegDecoder``` module, add your test circuit, 48 | and connect the module. 49 | 50 | A simple test is provided, which you can run with 51 | 52 | ``` 53 | sbt "testOnly SevenSegCountSpec" 54 | ``` 55 | 56 | and explore the waveform with GTKWave. 57 | 58 | When you are happy with the test results, generate Verilog with: 59 | 60 | ``` 61 | sbt "runMain CountSevenSeg" 62 | ``` 63 | 64 | Then, create a Vivado project for the 7-segment display test, synthesize 65 | your design, and configure the FPGA. 66 | 67 | An .xdc file (```sevenseg-cnt.xdc```) with the pin definitions is available. 68 | For more information, look into the 69 | [Basys 3](https://reference.digilentinc.com/reference/programmable-logic/basys-3/start?redirect=1) 70 | documentation. You can also find the pin definitions in the 71 | [Schematic of the IO](https://reference.digilentinc.com/basys3/refmanual#basic_io). 72 | 73 | *Can you draw the schematic of your design described in Chisel?* 74 | 75 | When your design works in the FPGA, show it to a TA for an OK 76 | tick in the list. **This is part of your grade.** 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /lab5/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" -------------------------------------------------------------------------------- /lab5/sevenseg-cnt.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Basys3 rev B board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | set_property IOSTANDARD LVCMOS33 [get_ports *] 7 | 8 | 9 | ## Clock signal 10 | set_property PACKAGE_PIN W5 [get_ports clock] 11 | 12 | # BTN3 - can be used as manual clock instead 13 | #set_property PACKAGE_PIN C16 [get_ports clock] 14 | 15 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 16 | 17 | 18 | ##Buttons 19 | # btnR proposed as reset 20 | #set_property PACKAGE_PIN T17 [get_ports btnR] 21 | set_property PACKAGE_PIN T17 [get_ports reset] 22 | 23 | ##7 segment display 24 | set_property PACKAGE_PIN W7 [get_ports {io_seg[0]}] 25 | set_property PACKAGE_PIN W6 [get_ports {io_seg[1]}] 26 | set_property PACKAGE_PIN U8 [get_ports {io_seg[2]}] 27 | set_property PACKAGE_PIN V8 [get_ports {io_seg[3]}] 28 | set_property PACKAGE_PIN U5 [get_ports {io_seg[4]}] 29 | set_property PACKAGE_PIN V5 [get_ports {io_seg[5]}] 30 | set_property PACKAGE_PIN U7 [get_ports {io_seg[6]}] 31 | #set_property PACKAGE_PIN V7 [get_ports io_dp] 32 | set_property PACKAGE_PIN U2 [get_ports {io_an[0]}] 33 | set_property PACKAGE_PIN U4 [get_ports {io_an[1]}] 34 | set_property PACKAGE_PIN V4 [get_ports {io_an[2]}] 35 | set_property PACKAGE_PIN W4 [get_ports {io_an[3]}] 36 | -------------------------------------------------------------------------------- /lab5/sevenseg.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Basys3 rev B board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | set_property IOSTANDARD LVCMOS33 [get_ports *] 7 | 8 | 9 | ## Clock signal 10 | #set_property PACKAGE_PIN W5 [get_ports clock] 11 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 12 | 13 | ## Switches 14 | set_property PACKAGE_PIN V17 [get_ports {io_sw[0]}] 15 | set_property PACKAGE_PIN V16 [get_ports {io_sw[1]}] 16 | set_property PACKAGE_PIN W16 [get_ports {io_sw[2]}] 17 | set_property PACKAGE_PIN W17 [get_ports {io_sw[3]}] 18 | 19 | ##Buttons 20 | # btnR proposed as reset 21 | #set_property PACKAGE_PIN T17 [get_ports btnR] 22 | set_property PACKAGE_PIN T17 [get_ports reset] 23 | 24 | ##7 segment display 25 | set_property PACKAGE_PIN W7 [get_ports {io_seg[0]}] 26 | set_property PACKAGE_PIN W6 [get_ports {io_seg[1]}] 27 | set_property PACKAGE_PIN U8 [get_ports {io_seg[2]}] 28 | set_property PACKAGE_PIN V8 [get_ports {io_seg[3]}] 29 | set_property PACKAGE_PIN U5 [get_ports {io_seg[4]}] 30 | set_property PACKAGE_PIN V5 [get_ports {io_seg[5]}] 31 | set_property PACKAGE_PIN U7 [get_ports {io_seg[6]}] 32 | #set_property PACKAGE_PIN V7 [get_ports io_dp] 33 | set_property PACKAGE_PIN U2 [get_ports {io_an[0]}] 34 | set_property PACKAGE_PIN U4 [get_ports {io_an[1]}] 35 | set_property PACKAGE_PIN V4 [get_ports {io_an[2]}] 36 | set_property PACKAGE_PIN W4 [get_ports {io_an[3]}] 37 | -------------------------------------------------------------------------------- /lab5/src/main/scala/CountSevenSeg.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | 3 | class CountSevenSeg extends Module { 4 | val io = IO(new Bundle { 5 | val seg = Output(UInt(7.W)) 6 | val an = Output(UInt(4.W)) 7 | }) 8 | 9 | val sevSeg = WireDefault("b1111111".U(7.W)) 10 | 11 | // *** your code starts here 12 | 13 | 14 | // *** your code ends here 15 | 16 | io.seg := sevSeg 17 | io.an := "b1110".U 18 | } 19 | 20 | // generate Verilog 21 | object CountSevenSeg extends App { 22 | emitVerilog(new CountSevenSeg()) 23 | } 24 | -------------------------------------------------------------------------------- /lab5/src/main/scala/SevenSegDecoder.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | class SevenSegDecoder extends Module { 5 | val io = IO(new Bundle { 6 | val sw = Input(UInt(4.W)) 7 | val seg = Output(UInt(7.W)) 8 | val an = Output(UInt(4.W)) 9 | }) 10 | 11 | val sevSeg = WireDefault(0.U(7.W)) 12 | 13 | // ***** your code starts here ***** 14 | 15 | // ***** your code ends here ***** 16 | 17 | io.seg := ~sevSeg 18 | io.an := "b1110".U 19 | } 20 | 21 | // generate Verilog 22 | object SevenSegDecoder extends App { 23 | emitVerilog(new SevenSegDecoder()) 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /lab5/src/test/scala/SevenSegCountSpec.scala: -------------------------------------------------------------------------------- 1 | import chiseltest._ 2 | import org.scalatest.flatspec.AnyFlatSpec 3 | 4 | class SevenSegCountSpec extends AnyFlatSpec with ChiselScalatestTester { 5 | "SevenSegTest " should "pass" in { 6 | test(new CountSevenSeg).withAnnotations(Seq(WriteVcdAnnotation)) { dut => 7 | dut.clock.step(100) 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lab5/src/test/scala/SevenSegDecoderSpec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class SevenSegDecoderSpec extends AnyFlatSpec with ChiselScalatestTester { 6 | "SevenSegDecoder " should "pass" in { 7 | test(new SevenSegDecoder) { dut => 8 | def print7Segment(x:BigInt,y: Int) = { 9 | var tempStr = "" 10 | println(y.toHexString) //Print the hexadecimal value 11 | println(if ((~x & 0x01) != 0) " _" else " ") //Print top "_" 12 | tempStr += (if((~x & 0x20) != 0) "|" else " ") //Print top left "|" 13 | tempStr += (if((~x & 0x40) != 0) "_" else " ") //Print middle "_" 14 | tempStr += (if((~x & 0x2) != 0) "|" else " ") //Print top right "|" 15 | println(tempStr) 16 | tempStr = (if((~x & 0x10) != 0) "|" else " ") //Print lower left "|" 17 | tempStr += (if((~x & 0x8) != 0) "_" else " ") //Print lower "_" 18 | tempStr += (if((~x & 0x4) != 0) "|" else " ") //Print lower right "|" 19 | println(tempStr) 20 | println() //Print empty line 21 | } 22 | 23 | for (value <- 0 until 16) { 24 | dut.io.sw.poke(value.U) //We apply a value to the input 25 | println(dut.io.seg.peek().litValue.toString(2).reverse.padTo(7,'0').reverse) // And check the value on the output. 26 | print7Segment(dut.io.seg.peek().litValue, value) // Here we print the result, as it would look on the 7-segment display. 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lab6/README.md: -------------------------------------------------------------------------------- 1 | # Lab 6: Multiplexed Seven-Segment Display 2 | 3 | In this lab you will extend your seven-segment decoder to display 4 | four digits in a time-multiplexed manner. 5 | This lab is your next step towards your vending machine. 6 | 7 | The Basys 3 FPGA board has four so-called seven-segment displays 8 | consisting of individual light emitting diodes (LED). 9 | The display uses time-multiplexing where the 4 digits share 10 | the 8 signals controlling the individual LED segments. 11 | An additional 4 signals are used to enable the individual digits. 12 | The idea is to turn on the digits one at a time and repeat 13 | this a rate of roughly 1 KHz. A human observer will not see this 14 | alternating activation. This solution requires only 12 pins on the FPGA 15 | 16 | All LEDs in a given digit have the anode terminal connected to a transistor, 17 | which itself is connected to the corresponding AN signal. 18 | All LEDs with the same label (A, B, C, ... , G, DP), one in each digit, 19 | have their cathode terminals connected to the same signal. The actual design use bipolar transistors and is explained in more detail in the 20 | [Basys 3 Reference Manual](https://digilent.com/reference/programmable-logic/basys-3/reference-manual) 21 | 22 | Build a synchronous circuit in Chisel for a multiplexed seven-segment display 23 | to display four hexadecimal digits on the LED display. 24 | The 16 switches are used as input for the four digits. 25 | 26 | A simple solution is to display the numbers in hexadecimal. 27 | However, humans usually 28 | expect numbers in decimal notation. Therefore, you might (optional) extend this circuit 29 | to perform binary to binary-coded-decimal (BCD) conversion. The Chisel book 30 | contains the Scala code to generate such a table. 31 | 32 | Sketch the circuit on a piece of paper! Do not turn on any PC before 33 | you have done your design. Remember: When you write Chisel you are 34 | describing the circuit you designed, you are not *programming* Chisel. 35 | 36 | However, there is one issue that needs to be solved: 37 | the 100 MHz from the clock input will not work as refresh frequency for 38 | the multiplexing of the LED display. 39 | We need to use a logical tick generation to multiplex the display at about 1 kHz. 40 | All registers are clocked by the main clock of 100 MHz. However, the component 41 | that does the multiplexing (state machine, or counter, or ...) will be enabled 42 | only for one clock cycle every 1 ms. Is this similar to the tick generation from 43 | last week? 44 | 45 | 46 | Reuse ```SevenSegDec.scala``` from your former lab exercise. 47 | To run the simulation (test) execute: 48 | 49 | ``` 50 | sbt test 51 | ``` 52 | 53 | and explore the waveform with GTKWave. The test runs just for 54 | 200 clock cycles. To see any useful results you need to switch 55 | your multiplexer with a high frequency (your counter counts only 56 | up to a few clock cycles). The waveform can be found in folder 57 | ```test_run_dir``` 58 | 59 | When you are happy with the test result, change your maximum count 60 | value to generate a tick at around 1 kHz, and generate Verilog with: 61 | 62 | ``` 63 | sbt run 64 | ``` 65 | 66 | Then create a Vivado project for the display multiplexer, synthesize 67 | your design, and configure the FPGA. 68 | 69 | An .xdc file (```display.xdc```) with the pin definitions is available. 70 | For more information look into the 71 | [Basys 3](https://reference.digilentinc.com/reference/programmable-logic/basys-3/start?redirect=1) 72 | documentation. You can also find the pin definitions in the 73 | [Schematic of the IO](https://reference.digilentinc.com/basys3/refmanual#basic_io). 74 | 75 | **When your design is working in the FPGA, show it to a TA for an OK 76 | tick in the list! This is part of your grade** 77 | 78 | For those not having an FPGA available at the moment there is a simulation 79 | of the 7-segment display available. It is not perfect, but you can test 80 | if you get your multiplexing correct. As with the waveform tester, 81 | switch the display at a higher frequency (e.g., every 20 clock cycles), to 82 | see results in the simulation. 83 | 84 | You run the simulation of the display with: 85 | 86 | ``` 87 | sbt test:run 88 | ``` 89 | 90 | -------------------------------------------------------------------------------- /lab6/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" 23 | 24 | libraryDependencies += "org.scala-lang.modules" %% "scala-swing" % "3.0.0" -------------------------------------------------------------------------------- /lab6/display.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Basys3 rev B board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | set_property IOSTANDARD LVCMOS33 [get_ports *] 7 | 8 | 9 | ## Clock signal 10 | set_property PACKAGE_PIN W5 [get_ports clock] 11 | 12 | # BTN3 - can be used as manual clock instead 13 | #set_property PACKAGE_PIN C16 [get_ports clock] 14 | 15 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 16 | 17 | 18 | ##Buttons 19 | # btnR proposed as reset 20 | #set_property PACKAGE_PIN T17 [get_ports btnR] 21 | set_property PACKAGE_PIN T17 [get_ports reset] 22 | 23 | ##7 segment display 24 | set_property PACKAGE_PIN W7 [get_ports {io_seg[0]}] 25 | set_property PACKAGE_PIN W6 [get_ports {io_seg[1]}] 26 | set_property PACKAGE_PIN U8 [get_ports {io_seg[2]}] 27 | set_property PACKAGE_PIN V8 [get_ports {io_seg[3]}] 28 | set_property PACKAGE_PIN U5 [get_ports {io_seg[4]}] 29 | set_property PACKAGE_PIN V5 [get_ports {io_seg[5]}] 30 | set_property PACKAGE_PIN U7 [get_ports {io_seg[6]}] 31 | #set_property PACKAGE_PIN V7 [get_ports io_dp] 32 | set_property PACKAGE_PIN U2 [get_ports {io_an[0]}] 33 | set_property PACKAGE_PIN U4 [get_ports {io_an[1]}] 34 | set_property PACKAGE_PIN V4 [get_ports {io_an[2]}] 35 | set_property PACKAGE_PIN W4 [get_ports {io_an[3]}] 36 | 37 | ## Switches 38 | set_property PACKAGE_PIN V17 [get_ports {io_sw[0]}] 39 | set_property PACKAGE_PIN V16 [get_ports {io_sw[1]}] 40 | set_property PACKAGE_PIN W16 [get_ports {io_sw[2]}] 41 | set_property PACKAGE_PIN W17 [get_ports {io_sw[3]}] 42 | set_property PACKAGE_PIN W15 [get_ports {io_sw[4]}] 43 | set_property PACKAGE_PIN V15 [get_ports {io_sw[5]}] 44 | set_property PACKAGE_PIN W14 [get_ports {io_sw[6]}] 45 | set_property PACKAGE_PIN W13 [get_ports {io_sw[7]}] 46 | set_property PACKAGE_PIN V2 [get_ports {io_sw[8]}] 47 | set_property PACKAGE_PIN T3 [get_ports {io_sw[9]}] 48 | set_property PACKAGE_PIN T2 [get_ports {io_sw[10]}] 49 | set_property PACKAGE_PIN R3 [get_ports {io_sw[11]}] 50 | set_property PACKAGE_PIN W2 [get_ports {io_sw[12]}] 51 | set_property PACKAGE_PIN U1 [get_ports {io_sw[13]}] 52 | set_property PACKAGE_PIN T1 [get_ports {io_sw[14]}] 53 | set_property PACKAGE_PIN R2 [get_ports {io_sw[15]}] 54 | -------------------------------------------------------------------------------- /lab6/src/main/scala/Display.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | /** 5 | * This is the top level to develop the display multiplexing circuit. 6 | * The multiplexing circuit is in the DisplayMultiplexer. 7 | */ 8 | class Display(maxCount: Int) extends Module { 9 | val io = IO(new Bundle { 10 | val sw = Input(UInt(16.W)) 11 | val seg = Output(UInt(7.W)) 12 | val an = Output(UInt(4.W)) 13 | }) 14 | 15 | val dispMux = Module(new DisplayMultiplexer(maxCount)) 16 | 17 | // Simulate the price and sum input with the switches 18 | dispMux.io.price := io.sw(7, 0) 19 | dispMux.io.sum := io.sw(15, 8) 20 | 21 | // Connect the display 22 | io.seg := dispMux.io.seg 23 | io.an := dispMux.io.an 24 | } 25 | 26 | // generate Verilog 27 | object Display extends App { 28 | emitVerilog(new Display(100000)) 29 | } -------------------------------------------------------------------------------- /lab6/src/main/scala/DisplayMultiplexer.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | class DisplayMultiplexer(maxCount: Int) extends Module { 5 | val io = IO(new Bundle { 6 | val sum = Input(UInt(8.W)) 7 | val price = Input(UInt(8.W)) 8 | val seg = Output(UInt(7.W)) 9 | val an = Output(UInt(4.W)) 10 | }) 11 | 12 | val sevSeg = WireDefault("b1111111".U(7.W)) 13 | val select = WireDefault("b0001".U(4.W)) 14 | 15 | // *** your code starts here 16 | 17 | 18 | // *** your code ends here 19 | 20 | io.seg := ~sevSeg 21 | io.an := ~select 22 | } 23 | -------------------------------------------------------------------------------- /lab6/src/main/scala/SevenSegDec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | class SevenSegDec extends Module { 5 | val io = IO(new Bundle { 6 | val in = Input(UInt(4.W)) 7 | val out = Output(UInt(7.W)) 8 | }) 9 | 10 | val sevSeg = WireDefault(0.U) 11 | 12 | // *** add your table from Lab 6 here or use the version from Lab 8. 13 | 14 | // *** end adding the table 15 | 16 | io.out := sevSeg 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /lab6/src/test/scala/DisplaySimulation.scala: -------------------------------------------------------------------------------- 1 | 2 | import scala.swing._ 3 | import scala.swing.event._ 4 | 5 | import java.awt.{Color, Graphics2D} 6 | 7 | import chisel3._ 8 | import chiseltest._ 9 | import org.scalatest.flatspec.AnyFlatSpec 10 | 11 | 12 | /** 13 | * A simulation of the Basys3 display 14 | */ 15 | class DisplaySimulation extends MainFrame { 16 | 17 | val sevenSeg = Array(List(23, 5, 40, 10), List(66, 10, 10, 50), List(66, 63, 10, 50), 18 | List(23, 108, 40, 10), List(10, 63, 10, 50), 19 | List(10, 10, 10, 50), List(23, 56, 40, 10)) 20 | 21 | val digits = Array(0x00, 0x00, 0x00, 0x00) 22 | var inVal = 0x1234 23 | var running = true 24 | 25 | def draw7(g: Graphics2D, x: Int, y: Int, seg: Int): Unit = { 26 | var shift = seg 27 | for (seg <- sevenSeg) { 28 | if ((shift & 0x01) != 0) { 29 | g.setColor(Color.red) 30 | } else { 31 | g.setColor(Color.black) 32 | } 33 | shift >>= 1 34 | g.fillRect(seg(0) + x, seg(1) + y, seg(2), seg(3)) 35 | } 36 | } 37 | 38 | title = "Display Simulator" 39 | preferredSize = new Dimension(400, 400) 40 | // contents = new Label("Here is the contents!") 41 | contents = new GridPanel(2, 1) { 42 | hGap = 50 43 | vGap = 50 44 | 45 | contents += new Panel { 46 | override def paintComponent(g: Graphics2D): Unit = { 47 | val xOff = 20 48 | val yOff = 20 49 | for (i <- 0 until 4) { 50 | draw7(g, xOff + i*90, yOff, digits(i)) 51 | } 52 | } 53 | } 54 | 55 | contents += new GridPanel(3, 2) { 56 | hGap = 30 57 | vGap = 30 58 | 59 | val label = new Label("1234") 60 | contents += label 61 | contents += new Panel {} 62 | 63 | 64 | val textField = new TextField { 65 | columns = 4 66 | text = "1234" 67 | } 68 | 69 | contents += textField 70 | 71 | contents += new Button { 72 | text = "Update" 73 | reactions += { 74 | case ButtonClicked(_) => { 75 | label.text = textField.text 76 | inVal = Integer.parseInt(textField.text, 16) 77 | println(inVal) 78 | } 79 | } 80 | } 81 | 82 | contents += new Panel {} 83 | 84 | contents += new Button { 85 | text = "Exit" 86 | reactions += { 87 | case ButtonClicked(_) => { 88 | running = false 89 | closeOperation() 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | 97 | object DisplaySimulation extends App { 98 | val display = new DisplaySimulation 99 | display.visible = true 100 | RawTester.test(new Display((20))) { dut => 101 | dut.clock.setTimeout(0) 102 | while (display.running) { 103 | dut.io.sw.poke(display.inVal.U) 104 | dut.clock.step(4) 105 | var an = dut.io.an.peekInt().toInt 106 | val seg = dut.io.seg.peekInt().toInt 107 | for (i <- 0 until 4) { 108 | if ((an & 1) == 0) { 109 | display.digits(3 - i) = ~seg 110 | } 111 | an >>= 1 112 | } 113 | display.repaint() 114 | Thread.sleep(10) 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /lab6/src/test/scala/DisplaySpec.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | class DisplaySpec extends AnyFlatSpec with ChiselScalatestTester { 6 | "DisplayTest " should "pass" in { 7 | test(new Display(20)).withAnnotations(Seq(WriteVcdAnnotation)) { dut => 8 | dut.io.sw.poke(0x1234.U) 9 | dut.clock.step(200) 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lab7/README.md: -------------------------------------------------------------------------------- 1 | # Lab 7: Using an External Component 2 | 3 | In this lab you will use an external component from a Chisel library hosted 4 | at Maven central. This shows you how open-source HW components can be shared 5 | easily with Chisel. 6 | 7 | In this lab you will add 8 | a [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter) 9 | component to your design. The UART is a 10 | serial interface where you can send and receive characters between the FPGA 11 | board and a terminal program on your computer. The UART is a standard 12 | component in many FPGA boards and is used for debugging and for communication. 13 | 14 | ## Preparation 15 | 16 | Do have some feedback that your setup in the FPGA is working 17 | add a blinking LED to your design. 18 | You can use the code from the previous lab1. 19 | 20 | ## Using an External Component 21 | 22 | The UART component is available as a Chisel library 23 | [ip-contributions](https://github.com/freechipsproject/ip-contributions) 24 | from Maven central. You 25 | can add it to your project with the following lines in your `build.sbt` file: 26 | 27 | ```scala 28 | libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 29 | ``` 30 | 31 | The UART component is available in the package ```package chisel.lib.uart```. 32 | Therefore, include the following line in your source file: 33 | 34 | ```scala 35 | import chisel.lib.uart._ 36 | ``` 37 | 38 | The UART component is a Chisel module. You can instantiate it with the 39 | following code: 40 | 41 | ```scala 42 | val uart = Module(new BufferedTx(100000000, 115200)) 43 | ``` 44 | 45 | The first parameter is the baud rate, the second parameter is the clock 46 | frequency. The ```BufferedTx``` component has a read/valid interface to 47 | send characters to the UART. 48 | 49 | To see the output of the UART you need to connect it to a terminal program. 50 | Under Winows PuTTY is a good choice. Under Linux you can use the ```gtkterm```. 51 | Under Mac OS X you can use the ```screen``` command. 52 | 53 | Set the baud rate of the terminal program to 115200 and one stop bit, 54 | no parity, no flow control. The UART sends the characters as ASCII 55 | characters. Therefore, you can see the characters in the terminal program. 56 | 57 | ### Sending Characters without Handshaking 58 | 59 | As the initial exercise send alternating '0' and '1' characters to the 60 | UART at the blink frequency of your LED. As this is way slower than the 61 | UART baud rate, you can ignore handshaking for now. 62 | 63 | The following code sends the character '0' to the UART: 64 | 65 | ```scala 66 | uart.io.channel.valid := true.B 67 | uart.io.channel.bits := '0'.U 68 | ``` 69 | 70 | Note that the data is not the binary zero, but needs ot be encoded in 71 | [ASCII](https://en.wikipedia.org/wiki/ASCII). The character '0' is 72 | encoded as 48 in ASCII. However, in Chisel you can simply write '0' as 73 | character literal. The character literal is automatically converted to 74 | the corresponding ASCII code. 75 | 76 | However, if you keep valid ```true.B``` for more than one clock cycle, 77 | the UART will send the same character multiple times. Therefore, you 78 | shall have the valid signal set only for a single clock cycle. 79 | 80 | ### Send a String 81 | 82 | Now, send the string "Hello World!" to the UART. You can use a ```Vec``` 83 | set to a default value with a ```VecInit``` to store the characters of the string. The following 84 | code creates a ```Vec``` with the characters of the string "Hello World!". 85 | 86 | ```scala 87 | val hello = VecInit('H'.U, 'e'.U, 'l'.U, ...) 88 | ``` 89 | 90 | Use a counter to send the characters of the string one by one. 91 | Note that your components needs to consider now handshaking. 92 | Only when the when ```ready``` is ```true.B``` you can send the next 93 | character. 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /lab7/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" 23 | libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.6.1" 24 | -------------------------------------------------------------------------------- /lab7/serial.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Basys3 rev B board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | set_property IOSTANDARD LVCMOS33 [get_ports *] 7 | 8 | ## Clock signal 9 | set_property PACKAGE_PIN W5 [get_ports clock] 10 | 11 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 12 | 13 | ##Buttons 14 | # btnR proposed as reset 15 | #set_property PACKAGE_PIN T17 [get_ports btnR] 16 | set_property PACKAGE_PIN T17 [get_ports reset] 17 | set_property PACKAGE_PIN U16 [get_ports {io_led}] 18 | 19 | set_property CONFIG_VOLTAGE 3.3 [current_design] 20 | set_property CFGBVS VCCO [current_design] 21 | 22 | ##USB-RS232 Interface 23 | set_property PACKAGE_PIN A18 [get_ports io_tx] 24 | set_property PACKAGE_PIN B18 [get_ports io_rx] 25 | 26 | #set_property PACKAGE_PIN B18 [get_ports RsRx] 27 | #set_property PACKAGE_PIN A18 [get_ports RsTx] 28 | 29 | -------------------------------------------------------------------------------- /lab7/serialA7.xdc: -------------------------------------------------------------------------------- 1 | ## This file is an .xdc for the Nexys A7-100T for the UART connection 2 | 3 | set_property IOSTANDARD LVCMOS33 [get_ports *] 4 | 5 | ## Clock signal 6 | set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clock }]; # IO_L12P_T1_MRCC_35 Sch=clk100mhz 7 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clock}]; 8 | 9 | ## LEDs 10 | set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { io_led }]; # IO_L18P_T2_A24_15 Sch=io_led 11 | 12 | ##Buttons 13 | set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L4N_T0_D05_14 Sch=btnu 14 | 15 | ##USB-RS232 Interface 16 | set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { io_rx }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in 17 | set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { io_tx }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out 18 | 19 | #set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { UART_TXD_IN }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in 20 | #set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { UART_RXD_OUT }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out 21 | -------------------------------------------------------------------------------- /lab7/src/main/scala/SerialPort.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | /** 5 | * This is the top level to for the UART output and a test blinking LED. 6 | */ 7 | class SerialPort(frequ: Int) extends Module { 8 | val io = IO(new Bundle { 9 | val tx = Output(Bool()) 10 | val led = Output(Bool()) 11 | }) 12 | io.tx := true.B 13 | io.led := true.B 14 | } 15 | 16 | // generate Verilog 17 | object SerialPort extends App { 18 | emitVerilog(new SerialPort(100000000)) 19 | } -------------------------------------------------------------------------------- /vending/README.md: -------------------------------------------------------------------------------- 1 | # The Vending Machine 2 | 3 | 4 | The inputting of coins (2 kr. and 5 kr.) is emulated by two push-buttons 5 | ```coin2``` and ```coin5```. The price of an item, called ```price```, 6 | is set by five switches, and two digits in the display shall show the ```price```. 7 | The left two digits in the display show the ```sum``` of the money entered so far. 8 | After entering enough money, a customer may press a button ```buy``` and this 9 | will result in the controller asserting the ```releaseCan``` output signal. 10 | If too little money is entered when ```buy``` is pushed an output ```alarm``` 11 | will be asserted instead. The ports ```alarm``` and ```releaseCan``` are 12 | connected to two LEDs on the FPGA board. 13 | 14 | This folder contains the setup of the full Vending Machine project. 15 | It includes a top-level of the design (```VendingMachine```), the 16 | constraint file ```vedning.xdc``` for the pin definitions, 17 | a start for a test (```VendingTester```), and a simulation of the Basys 3 18 | board (```VendingSimulation```). 19 | 20 | ![basys](basys-vending.jpg) 21 | 22 | ## Vending Machine Specification 23 | 24 | The vending machine sells one type of canned soft drink. 25 | The price of a can is set by the owner of the machine using 5 switches. 26 | Using unsigned binary representation this allows a price range from 0 kr. to 31 kr. 27 | The price is displayed on two seven-segment displays in decimal representation. 28 | The other two seven-segment displays show the amount of money entered so far. 29 | 30 | 31 | The machine accepts two types of coins: 2 kroner and 5 kroner. 32 | The inputting of coins is emulated by two push-buttons called ```coin2``` 33 | and ```coin5```. The amount entered so far (called ```sum```) is displayed 34 | on the left two seven-segment displays in decimal (hexadecimal representation can be used for a start). 35 | When enough money has been entered, the customer may press a button ```buy```. 36 | In response the machine will activate a signal ```releaseCan``` for as long as 37 | ```buy``` is pressed and subtract the ```price``` of a can from the ```sum```. 38 | The machine does not return any money; any surplus is left for the next purchase. 39 | If ```buy``` is pressed before enough money has been entered the machine activates 40 | a signal ```alarm``` for as long as ```buy``` is pressed. 41 | 42 | We will make the following simplifying assumptions: 43 | 44 | 1. The vending machine never runs out of cans. 45 | 2. Only one of the signals ```buy```, ```coin2```, and ```coin5``` are asserted at any given time. 46 | 3. The user never enters more money than what the machine can represent and display. 47 | 48 | After turning on power the owner resets the machine. Asserting ```reset``` is an 49 | indication that the machine is full of cans and that all coin compartments have 50 | been emptied. In addition, ```reset``` sets ```sum``` to 00. 51 | 52 | Important note: It is important that input signals that cause actions when they 53 | are asserted are implemented by push buttons that are de-bounced. 54 | The Basys 3 board has only 4 de-bounced push-buttons on the extension board. 55 | We will use these for the input signals ```buy```, ```coin2```, and ```coin5```. 56 | For ```reset``` a bouncing button is sufficient, as long as the reset signal is 57 | synchronized. The bounce produced by the switch may cause reset to be asserted 58 | and de-asserted multiple times, but it is OK to reset a circuit multiple times. 59 | 60 | Later, when you have completed the laboratory exercises according to 61 | the above specifications and demonstrated your design to a teaching assistant, 62 | you may want to extend your design. Below is a list of ideas. 63 | You may have more ideas. 64 | Please explain and include any optional design work in your report. 65 | 66 | * Supplement the alarm by visual signal, for example blinking the sum display. 67 | * Count coins and assert alarm if a coin compartment is full (>20 of given type ). 68 | * Maximum number of cans in the machine; for example 20. If the machine gets empty show ```EPty``` in the four seven-segment displays. 69 | * Implement a digital debouncer circuit. This will allow you to use the push buttons on the Basys 3 board itself (instead of the external Pmod BTN push-button module). 70 | * Connect a [UART](https://github.com/schoeberl/chisel-book/blob/master/src/main/scala/uart/uart.scala) to your VM and sending messages to your laptop. 71 | * ... your ideas 72 | 73 | The *standard solution* without any optional tasks is considered a 74 | *standard performance*. To obtain a top grade (i.e., 10 or 12) 75 | you are expected to develop additional features. 76 | 77 | ## Design and Implementation 78 | 79 | The first step is to design a datapath. To do this you need to determine what data 80 | you need to store and manipulate. This defines the registers in the datapath. 81 | By data we mean variables and not constants. Constants in hardware is just a 82 | matter of connecting signals to Vdd and Ground. Then you determine what operations 83 | you need to perform on the data. 84 | An operation is performed during a clock cycle and some example operations are 85 | ```nextVal := sum + 5``` or ```nextVal := sum - price```. 86 | List all the operations that your datapath should be capable of performing. 87 | Based on this list of clock-cycle operations and the list of registers you 88 | should be able to design a datapath. There is a lot of freedom and many alternatives. 89 | In our case it should suffice to be able to do one single arithmetic operation 90 | in a clock cycle, i.e., to use only one single adder/subtractor in the datapath. 91 | When the datapath is in place, the next step is to design the finite state machine (FSM) 92 | that will control the sequence of operations in the datapath and deliver the 93 | output signals ```releaseCan``` and ```alarm```. This combination of a datapath 94 | with and FSM is called a state machine with datapath (FSMD). 95 | 96 | In summary the design phase involves the following: 97 | 98 | * A list of registers and *clock cycle operations* to be supported by the datapath. 99 | * A diagram showing an intended datapath design (registers, multiplexers, adders/subtractors etc.) 100 | * A complete specification of the central processing unit in the form of a state graph for the FSM. 101 | * A test sequence for simulating your design, i.e., a timing diagram showing the input signals that you want your Chisel test-bench to generate along with the expected outputs from your circuit. 102 | 103 | 104 | A comment about the input signals: 105 | You should be aware of the fact that the signals will be asserted for as many clock 106 | cycles as you push the buttons and switches. For ```reset``` and ```buy``` this is 107 | what you want and need to deal with. For signals ```coin2``` and ```coin5``` 108 | you do not want to add 2 kr. or 5 kr. for as many cycles a you push the corresponding 109 | button. To avoid this the FSM in your vedning machine must respond to the rising edge 110 | and wait for the corresponding signal to be de-asserted. 111 | Alternatively you may want to improve the input synchronizer such that it delivers 112 | signals ```coin2``` and ```coin5``` that are active for one clock cycle only. 113 | 114 | ### Implementation 115 | The next step is to describe the design of your vending machine in Chisel. 116 | We recommend that you describe your design as one component (Chisel Module). 117 | As errors are very hard to identify on the FPGA board we recommend that you 118 | simulate your design. 119 | 120 | * Write the Chisel code according to these guidelines. 121 | * Write a Chisel test-bench that can drive the simulation and simulate your circuit. 122 | 123 | Now synthesize and upload the design to your Basys 3 FPGA-board. 124 | Enjoy a job well done! **Show your working design to a TA.** 125 | 126 | 127 | ### Evaluation 128 | 129 | Assess the resource usage for the ```VendingMachine```. 130 | Synthesize it separately and check the resource usage reported by Xilinx Vivado. 131 | How many LUT's and FF's are used? Compare the RTL schematics with your hand designed datapath. 132 | What is the maximum clock frequency of your design? 133 | 134 | ## Testing the Design 135 | 136 | When writing your code, always run tests. Best approach is a test-driven development 137 | where you write tests together with the design. This repository contains a simple 138 | test to get you started. It presses some buttons and generates a waveform file that 139 | you can view with GTKWave (remember to open a ```.vcd``` file with ```File - Open New Tab```). 140 | You can run the test with: 141 | 142 | ``` 143 | sbt test 144 | ``` 145 | 146 | Extend the test with your own tests. 147 | 148 | 149 | ## Generating the Verilog Files for the FPGA 150 | 151 | Finally, the real test is in the FPGA baord. Generate the Verilog file with: 152 | 153 | ``` 154 | sbt run 155 | ``` 156 | 157 | Create a Xilinx Vivado project with the generatd Verilog file 158 | ```VendingMachine.v``` and the constraint file ```vending.xdc```. 159 | 160 | 161 | 162 | ## Simulating the Basys3 Board 163 | 164 | Furthermore, we can also run the vending machine hardware with a simulation 165 | of the Basys3 board, as follows: 166 | 167 | ``` 168 | sbt test:run 169 | ``` 170 | 171 | The simulation contains the 7-segment display simulation that is included 172 | in lab8. As with the waveform tester, switch the display at a higher 173 | frequency (e.g., every 20 clock cycles) to avoid simulating forever. 174 | 175 | The simulation contains three buttons for the VM that are connected to 176 | the inputs ```con2```, ```con5```, and ```buy```. With one click you can 177 | toggle to pressed, with another clock you can toggle back to release. 178 | The status is also written out to the command line. 179 | 180 | The ```Exit``` button stops the simulation. 181 | 182 | The next row simulates the 16 green LEDs. Two LEDs are connected to 183 | ```releaseCan``` and ```alarm```. 184 | 185 | The bottom row contains 16 check boxes to simulate the 16 switches. 186 | The right 5 check boxes are connected to the ```price``` input. 187 | 188 | ## Guidelines for the Report 189 | 190 | According to the course description your performance in the course is based on 191 | "Written examination and reports". There is only one report. 192 | A report covering the entire vending machine project. 193 | Below you find some requirements and guidelines for the report. 194 | You may write your report in Danish or in English if you want to practice this. 195 | 196 | The report must be handed in using DTU Learn, where you find an assignment called 197 | "Vending Machine Project". One student from each team should upload the report 198 | and the other team members should ``join''. 199 | As the report is considered part of the exam it is important that we have 200 | everybody registered. The file must be in PDF-format and the report including 201 | all appendices (Chisel code listings, etc.) must be in a *single file*. 202 | This is important! We do not accept MS Word and we do not accept multiple files. 203 | The file must be named group.pdf (for example: group10.pdf). 204 | 205 | DTU Learn performs a check for plagiarism, and we assume that you are 206 | aware of DTU's policy on this (see: Studiehaandbog, Regelsamling, afsnit 3.9 207 | "Snyd ved eksamen og anden bedoemmelse"). 208 | 209 | **If you want, you are allowed to use the help of ChatGPT or other LLMs to write your report.** 210 | In that case, state in the preface that you used ChatGPT to write/enhance the 211 | report and cite ChatGPT. You ae still responsible for the text and any 212 | nonsense that ChatGPT writes. 213 | 214 | **If you want, you are allowed to use the help of ChatGPT and/or Copilot 215 | to help you in Chisel coding.** 216 | In that case, have a section on reflecting how helpful those tools were 217 | and what you learned from using them. Cite the tools. 218 | You are still responsible for the code and any nonsense that ChatGPT 219 | or Copilot writes. 220 | 221 | **If you use ChatGPT, Copilot, or any AI as help, write an extra section 222 | reflecting on the experience.** What did you learn? What did you not learn? 223 | 224 | The cover page of the report must contain the following information: 225 | 226 | 1. Number and name of the course: 02139: Digital Electronics 2. (Danish: "02139 Digital elektronik 2"). 227 | 2. Title of the report: Vending Machine Project. (Danish: "Sodavandsautomat projekt"). 228 | 3. Student names and id numbers. 229 | 230 | The rest of the documents contains: 231 | 232 | 1. Preface (Danish: Forord): A clear indication of the contributions of each team member; sufficiently detailed to enable an assessment of the contribution of each individual student. Information about issues that have influenced the work, for example change of group members. 233 | 2. The body of the report should cover the preparation and the lab work for laboratory exercises. 234 | 3. As a guideline the report should be about 10 pages of text, excluding figures and appendices. Include appendices with Chisel code (only files you have written or modified) and screen-dumps of the wave-window to document your simulations. 235 | 4. Have block diagram figures for your design. 236 | 5. A state diagram for your FSM. 237 | 6. A schematics of your datapath. 238 | 7. All figures need to be drawn ``nicely''; that means with a drawing program and not hand drawn and a picture taken. 239 | 240 | ### A generic report structure may be as the following: 241 | 242 | Abstract. (Summary and achievements/results) 243 | 244 | Preface. (Who did what etc.) 245 | 246 | 1. Introduction and Problem Formulation (Welcoming the reader. Setting the scene) 247 | 2. Analysis and Design (Figuring out what to build) 248 | 3. Implementation (Building it) 249 | 4. Test (how was it tested) 250 | 5. Results (Objective figures and facts) 251 | 6. Discussions (Your reflections) 252 | 7. Experiences Using AI Tools (if used, reflections on usage of ChatGPT, Copilot, etc.) 253 | 8. Conclusion (Summary and goodbye) 254 | 9. List of References 255 | 256 | Appendix A: Chisel code for the design 257 | 258 | Appendix B: Chisel code for test-benches 259 | 260 | A report is not a lab notebook, nor a set of problem solutions. 261 | A report is a stand-alone document that is written after all the work 262 | has been performed. However, it is good practice to take notes in electronic form during your work for a collection of facts. When writing the report, remember that the aim is to explain to an outsider and in the most efficient way possible what has been done, how it has been done, and the conclusions that can be drawn from the work. Be brief, and make sure the reader knows where you are heading. The report should present the material in a logical order, which is sometimes different from the order in which the tasks were performed. 263 | 264 | Finally, a word about copyright: You are *not* allowed to silently copy figures 265 | or text from other documents! In general the rules are as follows: 266 | 267 | You are allowed to reuse short passages of text provided that you clearly state this. In the running text you can do this by writing: 268 | ... as stated/explained in [ref]: *"the text that you are copying"* ... where [ref] is a complete and correct citation of the document from where you are copying the text. 269 | 270 | Figures are generally covered by copyright and can only be used if you obtain 271 | permission from the copyright holder. 272 | 273 | ### Additional Rules 274 | 275 | * No photos and no hand drawings, use a drawing program. 276 | * No videos 277 | * Maximum size of the report is 2 MB. 278 | -------------------------------------------------------------------------------- /vending/basys-vending.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schoeberl/chisel-lab/9b1fae8d9dc2581debd688ca6c3e17ba894c14c7/vending/basys-vending.jpg -------------------------------------------------------------------------------- /vending/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq( 2 | "-deprecation", 3 | "-feature", 4 | "-unchecked", 5 | // "-Xfatal-warnings", 6 | "-language:reflectiveCalls", 7 | ) 8 | 9 | /* 10 | scalaVersion := "2.13.14" 11 | val chiselVersion = "6.5.0" 12 | addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full) 13 | libraryDependencies += "org.chipsalliance" %% "chisel" % chiselVersion 14 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "6.0.0" 15 | // libraryDependencies += "edu.berkeley.cs" % "ip-contributions" % "0.5.1" 16 | */ 17 | 18 | scalaVersion := "2.13.14" 19 | val chiselVersion = "3.6.1" 20 | addCompilerPlugin("edu.berkeley.cs" %% "chisel3-plugin" % chiselVersion cross CrossVersion.full) 21 | libraryDependencies += "edu.berkeley.cs" %% "chisel3" % chiselVersion 22 | libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.6.2" 23 | 24 | libraryDependencies += "org.scala-lang.modules" %% "scala-swing" % "3.0.0" -------------------------------------------------------------------------------- /vending/src/main/scala/VendingMachine.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chisel3.util._ 3 | 4 | class VendingMachine(maxCount: Int) extends Module { 5 | val io = IO(new Bundle { 6 | val price = Input(UInt(5.W)) 7 | val coin2 = Input(Bool()) 8 | val coin5 = Input(Bool()) 9 | val buy = Input(Bool()) 10 | val releaseCan = Output(Bool()) 11 | val alarm = Output(Bool()) 12 | val seg = Output(UInt(7.W)) 13 | val an = Output(UInt(4.W)) 14 | }) 15 | 16 | val sevSeg = WireDefault(0.U) 17 | 18 | // ***** some dummy connections ***** 19 | sevSeg := "b1111111".U 20 | 21 | io.alarm := io.coin2 22 | io.releaseCan := io.coin5 23 | 24 | 25 | io.seg := ~sevSeg 26 | io.an := "b1110".U 27 | } 28 | 29 | // generate Verilog 30 | object VendingMachine extends App { 31 | emitVerilog(new VendingMachine(100000)) 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /vending/src/test/scala/VendingSimulation.scala: -------------------------------------------------------------------------------- 1 | import scala.swing._ 2 | import scala.swing.event._ 3 | import java.awt.{Color, Graphics2D} 4 | import chisel3._ 5 | import chiseltest._ 6 | import org.scalatest.flatspec.AnyFlatSpec 7 | 8 | 9 | /** 10 | * Simulation of the Basys3 board for the Vending Machine 11 | */ 12 | class VendingSimulation extends MainFrame { 13 | 14 | val sevenSeg = Array(List(23, 5, 40, 10), List(66, 10, 10, 50), List(66, 63, 10, 50), 15 | List(23, 108, 40, 10), List(10, 63, 10, 50), 16 | List(10, 10, 10, 50), List(23, 56, 40, 10)) 17 | 18 | val digits = Array(0x00, 0x00, 0x00, 0x00) 19 | var ledVal = new Array[Boolean](16) 20 | val switches = new Array[CheckBox](16) 21 | val btn = new Array[ToggleButton](3) 22 | var btnVal = new Array[Boolean](3) 23 | var running = true 24 | 25 | def draw7(g: Graphics2D, x: Int, y: Int, seg: Int): Unit = { 26 | var shift = seg 27 | for (seg <- sevenSeg) { 28 | if ((shift & 0x01) != 0) { 29 | g.setColor(Color.red) 30 | } else { 31 | g.setColor(Color.gray) 32 | } 33 | shift >>= 1 34 | g.fillRect(seg(0) + x, seg(1) + y, seg(2), seg(3)) 35 | } 36 | } 37 | 38 | def drawLed(g: Graphics2D, on: Boolean): Unit = { 39 | if (on) { 40 | g.setColor(Color.green) 41 | } else { 42 | } 43 | g.fillRect(5, 5, 15, 8) 44 | } 45 | 46 | title = "Basys3 Simulator" 47 | preferredSize = new Dimension(400, 600) 48 | contents = new GridPanel(3, 1) { 49 | hGap = 50 50 | vGap = 50 51 | 52 | contents += new Panel { 53 | override def paintComponent(g: Graphics2D): Unit = { 54 | g.setColor(Color.black) 55 | g.fillRect(10, 10, 380, 143) 56 | 57 | val xOff = 20 58 | val yOff = 20 59 | for (i <- 0 until 4) { 60 | draw7(g, xOff + i*90, yOff, digits(i)) 61 | } 62 | } 63 | } 64 | 65 | contents += new GridPanel(2, 16) { 66 | hGap = 30 67 | vGap = 30 68 | 69 | btn(0) = new ToggleButton { 70 | text = "2 kr." 71 | reactions += { 72 | case ButtonClicked(_) => { 73 | btnVal(0) = this.selected 74 | println("2 kr. " + (if (btnVal(0)) "on" else "off")) 75 | } 76 | } 77 | } 78 | 79 | btn(1) = new ToggleButton { 80 | text = "5 kr." 81 | reactions += { 82 | case ButtonClicked(_) => { 83 | btnVal(1) = this.selected 84 | println("5 kr. " + (if (btnVal(1)) "on" else "off")) 85 | } 86 | } 87 | } 88 | 89 | btn(2) = new ToggleButton { 90 | text = "Buy" 91 | reactions += { 92 | case ButtonClicked(_) => { 93 | btnVal(2) = this.selected 94 | println("Buy " + (if (btnVal(2)) "on" else "off")) 95 | } 96 | } 97 | } 98 | 99 | contents ++= btn 100 | contents += new Panel {} 101 | 102 | contents += new Button { 103 | text = "Exit" 104 | reactions += { 105 | case ButtonClicked(_) => { 106 | running = false 107 | closeOperation() 108 | } 109 | } 110 | } 111 | } 112 | 113 | contents += new GridPanel(1, 6) { 114 | 115 | for (i <- 0 until 16) { 116 | contents += new GridPanel(4, 1) { 117 | contents += new Panel {} 118 | contents += new Panel() { 119 | override def paintComponent(g: Graphics2D): Unit = { 120 | drawLed(g, ledVal(15-i)) 121 | } 122 | 123 | } 124 | val c = new CheckBox("") 125 | switches(15-i) = c 126 | contents += c 127 | contents += new Panel {} 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | object VendingSimulation extends App { 135 | val d = new VendingSimulation 136 | d.visible = true 137 | RawTester.test(new VendingMachine(20)) { dut => 138 | dut.clock.setTimeout(0) 139 | while (d.running) { 140 | 141 | dut.clock.step(4) 142 | var an = dut.io.an.peekInt().toInt 143 | val seg = dut.io.seg.peekInt().toInt 144 | for (i <- 0 until 4) { 145 | if ((an & 1) == 0) { 146 | d.digits(3 - i) = ~seg 147 | } 148 | an >>= 1 149 | } 150 | 151 | d.ledVal(15) = dut.io.releaseCan.peekInt() == 1 152 | d.ledVal(0) = dut.io.alarm.peekInt() == 1 153 | var price = 0 154 | for (i <- 0 until 5) { 155 | price <<= 1 156 | price += (if (d.switches(4-i).selected) 1 else 0) 157 | } 158 | dut.io.price.poke(price.U) 159 | dut.io.coin2.poke(d.btnVal(0).B) 160 | dut.io.coin5.poke(d.btnVal(1).B) 161 | dut.io.buy.poke(d.btnVal(2).B) 162 | 163 | d.repaint() 164 | Thread.sleep(10) 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /vending/src/test/scala/VendingTester.scala: -------------------------------------------------------------------------------- 1 | import chisel3._ 2 | import chiseltest._ 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | 6 | class VendingTester extends AnyFlatSpec with ChiselScalatestTester { 7 | "Vending machine test" should "pass" in { 8 | test(new VendingMachine(20)).withAnnotations(Seq(WriteVcdAnnotation)) { dut => 9 | println("We are generting a VCD file with the test of the vending machine") 10 | dut.io.price.poke(7.U) 11 | dut.clock.step(3) 12 | dut.io.coin2.poke(true.B) 13 | dut.clock.step(3) 14 | dut.io.coin2.poke(false.B) 15 | dut.clock.step(6) 16 | dut.io.coin5.poke(true.B) 17 | dut.clock.step(3) 18 | dut.io.coin5.poke(false.B) 19 | dut.clock.step(8) 20 | dut.io.buy.poke(true.B) 21 | dut.clock.step(3) 22 | dut.io.buy.poke(false.B) 23 | dut.clock.step(10) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /vending/vending-nexys.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Nexys A7-50T and A7-100T boards 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | ## Clock signal 7 | set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clock }]; # IO_L12P_T1_MRCC_35 Sch=clk100mhz 8 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clock}]; 9 | 10 | 11 | ## Switches 12 | set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports {io_price[0]}]; # IO_L24N_T3_RS0_15 Sch=sw[0] 13 | set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports {io_price[1]}]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] 14 | set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports {io_price[2]}]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] 15 | set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports {io_price[3]}]; #IO_L13N_T2_MRCC_14 Sch=sw[3] 16 | set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports {io_price[4]}]; #IO_L12N_T1_MRCC_14 Sch=sw[4] 17 | #set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { SW[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] 18 | #set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { SW[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] 19 | #set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { SW[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] 20 | #set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { SW[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] 21 | #set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { SW[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] 22 | #set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { SW[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] 23 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { SW[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] 24 | #set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { SW[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] 25 | #set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { SW[8] }]; #IO_L24N_T3_34 Sch=sw[8] 26 | #set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { SW[9] }]; #IO_25_34 Sch=sw[9] 27 | #set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { SW[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] 28 | #set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { SW[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] 29 | #set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { SW[12] }]; #IO_L24P_T3_35 Sch=sw[12] 30 | #set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { SW[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] 31 | #set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { SW[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] 32 | #set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { SW[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] 33 | 34 | 35 | ## LEDs 36 | set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { io_alarm }]; # IO_L18P_T2_A24_15 Sch=io_led 37 | #set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { LED[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] 38 | #set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { LED[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] 39 | #set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { LED[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] 40 | #set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { LED[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] 41 | #set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { LED[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] 42 | #set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { LED[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] 43 | #set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { LED[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] 44 | #set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { LED[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] 45 | #set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { LED[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] 46 | #set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { LED[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] 47 | #set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { LED[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] 48 | #set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { LED[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] 49 | #set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { LED[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] 50 | #set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { LED[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] 51 | set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { io_releaseCan }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] 52 | 53 | ## RGB LEDs 54 | #set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { LED16_B }]; #IO_L5P_T0_D06_14 Sch=led16_b 55 | #set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { LED16_G }]; #IO_L10P_T1_D14_14 Sch=led16_g 56 | #set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { LED16_R }]; #IO_L11P_T1_SRCC_14 Sch=led16_r 57 | #set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { LED17_B }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b 58 | #set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { LED17_G }]; #IO_0_14 Sch=led17_g 59 | #set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { LED17_R }]; #IO_L11N_T1_SRCC_14 Sch=led17_r 60 | 61 | ##7 segment display 62 | set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { io_seg[0] }]; #IO_L24N_T3_A00_D16_14 Sch=ca 63 | set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { io_seg[1] }]; #IO_25_14 Sch=cb 64 | set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { io_seg[2] }]; #IO_25_15 Sch=cc 65 | set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { io_seg[3] }]; #IO_L17P_T2_A26_15 Sch=cd 66 | set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { io_seg[4] }]; #IO_L13P_T2_MRCC_14 Sch=ce 67 | set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { io_seg[5] }]; #IO_L19P_T3_A10_D26_14 Sch=cf 68 | set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { io_seg[6] }]; #IO_L4P_T0_D04_14 Sch=cg 69 | #set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { DP }]; #IO_L19N_T3_A21_VREF_15 Sch=dp 70 | set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { io_an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] 71 | set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { io_an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] 72 | set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { io_an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] 73 | set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { io_an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] 74 | 75 | 76 | ##Buttons 77 | set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L4N_T0_D05_14 Sch=btnu 78 | set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { io_coin2 }]; #IO_L12P_T1_MRCC_14 Sch=btnl 79 | set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { io_coin5 }]; #IO_L10N_T1_D15_14 Sch=btnr 80 | set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { io_buy }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd 81 | #set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { CPU_RESETN }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn 82 | #set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { BTNC }]; #IO_L9P_T1_DQS_14 Sch=btnc 83 | #set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { BTNU }]; #IO_L4N_T0_D05_14 Sch=btnu 84 | #set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { BTNL }]; #IO_L12P_T1_MRCC_14 Sch=btnl 85 | #set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { BTNR }]; #IO_L10N_T1_D15_14 Sch=btnr 86 | #set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { BTND }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd 87 | 88 | 89 | ##Pmod Headers 90 | ##Pmod Header JA 91 | #set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { JA[1] }]; #IO_L20N_T3_A19_15 Sch=ja[1] 92 | #set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { JA[2] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] 93 | #set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { JA[3] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] 94 | #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { JA[4] }]; #IO_L18N_T2_A23_15 Sch=ja[4] 95 | #set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { JA[7] }]; #IO_L16N_T2_A27_15 Sch=ja[7] 96 | #set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { JA[8] }]; #IO_L16P_T2_A28_15 Sch=ja[8] 97 | #set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { JA[9] }]; #IO_L22N_T3_A16_15 Sch=ja[9] 98 | #set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { JA[10] }]; #IO_L22P_T3_A17_15 Sch=ja[10] 99 | 100 | ##Pmod Header JB 101 | #set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { JB[1] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] 102 | #set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { JB[2] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] 103 | #set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { JB[3] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] 104 | #set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { JB[4] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] 105 | #set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { JB[7] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] 106 | #set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { JB[8] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] 107 | #set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { JB[9] }]; #IO_0_15 Sch=jb[9] 108 | #set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { JB[10] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] 109 | 110 | ##Pmod Header JC 111 | #set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { JC[1] }]; #IO_L23N_T3_35 Sch=jc[1] 112 | #set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { JC[2] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] 113 | #set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { JC[3] }]; #IO_L22N_T3_35 Sch=jc[3] 114 | #set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { JC[4] }]; #IO_L19P_T3_35 Sch=jc[4] 115 | #set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { JC[7] }]; #IO_L6P_T0_35 Sch=jc[7] 116 | #set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { JC[8] }]; #IO_L22P_T3_35 Sch=jc[8] 117 | #set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { JC[9] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] 118 | #set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { JC[10] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] 119 | 120 | ##Pmod Header JD 121 | #set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { JD[1] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] 122 | #set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { JD[2] }]; #IO_L17P_T2_35 Sch=jd[2] 123 | #set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { JD[3] }]; #IO_L17N_T2_35 Sch=jd[3] 124 | #set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { JD[4] }]; #IO_L20N_T3_35 Sch=jd[4] 125 | #set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { JD[7] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] 126 | #set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { JD[8] }]; #IO_L20P_T3_35 Sch=jd[8] 127 | #set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { JD[9] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] 128 | #set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { JD[10] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] 129 | 130 | ##Pmod Header JXADC 131 | #set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { XA_N[1] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] 132 | #set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { XA_P[1] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] 133 | #set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { XA_N[2] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] 134 | #set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { XA_P[2] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] 135 | #set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { XA_N[3] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] 136 | #set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { XA_P[3] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] 137 | #set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { XA_N[4] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] 138 | #set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { XA_P[4] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] 139 | -------------------------------------------------------------------------------- /vending/vending.xdc: -------------------------------------------------------------------------------- 1 | # This is for the display exercise 2 | 3 | set_property IOSTANDARD LVCMOS33 [get_ports *] 4 | 5 | 6 | ## Clock signal 7 | set_property PACKAGE_PIN W5 [get_ports clock] 8 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clock] 9 | 10 | ## Switches 11 | set_property PACKAGE_PIN V17 [get_ports {io_price[0]}] 12 | set_property PACKAGE_PIN V16 [get_ports {io_price[1]}] 13 | set_property PACKAGE_PIN W16 [get_ports {io_price[2]}] 14 | set_property PACKAGE_PIN W17 [get_ports {io_price[3]}] 15 | set_property PACKAGE_PIN W15 [get_ports {io_price[4]}] 16 | #set_property PACKAGE_PIN V15 [get_ports {io_sw[5]}] 17 | #set_property PACKAGE_PIN W14 [get_ports {io_sw[6]}] 18 | #set_property PACKAGE_PIN W13 [get_ports {io_sw[7]}] 19 | #set_property PACKAGE_PIN V2 [get_ports {io_sw[8]}] 20 | #set_property PACKAGE_PIN T3 [get_ports {io_sw[9]}] 21 | #set_property PACKAGE_PIN T2 [get_ports {io_sw[10]}] 22 | #set_property PACKAGE_PIN R3 [get_ports {io_sw[11]}] 23 | #set_property PACKAGE_PIN W2 [get_ports {io_sw[12]}] 24 | #set_property PACKAGE_PIN U1 [get_ports {io_sw[13]}] 25 | #set_property PACKAGE_PIN T1 [get_ports {io_sw[14]}] 26 | #set_property PACKAGE_PIN R2 [get_ports {io_sw[15]}] 27 | 28 | ## LEDs 29 | set_property PACKAGE_PIN U16 [get_ports {io_alarm}] 30 | #set_property PACKAGE_PIN E19 [get_ports {led[1]}] 31 | #set_property PACKAGE_PIN U19 [get_ports {led[2]}] 32 | #set_property PACKAGE_PIN V19 [get_ports {led[3]}] 33 | #set_property PACKAGE_PIN W18 [get_ports {led[4]}] 34 | #set_property PACKAGE_PIN U15 [get_ports {led[5]}] 35 | #set_property PACKAGE_PIN U14 [get_ports {led[6]}] 36 | #set_property PACKAGE_PIN V14 [get_ports {led[7]}] 37 | #set_property PACKAGE_PIN V13 [get_ports {led[8]}] 38 | #set_property PACKAGE_PIN V3 [get_ports {led[9]}] 39 | #set_property PACKAGE_PIN W3 [get_ports {led[10]}] 40 | #set_property PACKAGE_PIN U3 [get_ports {led[11]}] 41 | #set_property PACKAGE_PIN P3 [get_ports {led[12]}] 42 | #set_property PACKAGE_PIN N3 [get_ports {led[13]}] 43 | #set_property PACKAGE_PIN P1 [get_ports {led[14]}] 44 | set_property PACKAGE_PIN L1 [get_ports {io_releaseCan}] 45 | 46 | ##Buttons 47 | # btnR proposed as reset 48 | #set_property PACKAGE_PIN T17 [get_ports btnR] 49 | set_property PACKAGE_PIN T17 [get_ports reset] 50 | 51 | 52 | ## Pmod in lower row 53 | # BTN0 54 | set_property PACKAGE_PIN A15 [get_ports {io_coin2}] 55 | # BTN1 56 | set_property PACKAGE_PIN A17 [get_ports {io_coin5}] 57 | # BTN2 58 | set_property PACKAGE_PIN C15 [get_ports {io_buy}] 59 | # BTN3 - can be used as manual clock 60 | #set_property PACKAGE_PIN C16 [get_ports {io_btn[3]}] 61 | 62 | ##7 segment display 63 | set_property PACKAGE_PIN W7 [get_ports {io_seg[0]}] 64 | set_property PACKAGE_PIN W6 [get_ports {io_seg[1]}] 65 | set_property PACKAGE_PIN U8 [get_ports {io_seg[2]}] 66 | set_property PACKAGE_PIN V8 [get_ports {io_seg[3]}] 67 | set_property PACKAGE_PIN U5 [get_ports {io_seg[4]}] 68 | set_property PACKAGE_PIN V5 [get_ports {io_seg[5]}] 69 | set_property PACKAGE_PIN U7 [get_ports {io_seg[6]}] 70 | #set_property PACKAGE_PIN V7 [get_ports io_dp] 71 | set_property PACKAGE_PIN U2 [get_ports {io_an[0]}] 72 | set_property PACKAGE_PIN U4 [get_ports {io_an[1]}] 73 | set_property PACKAGE_PIN V4 [get_ports {io_an[2]}] 74 | set_property PACKAGE_PIN W4 [get_ports {io_an[3]}] 75 | --------------------------------------------------------------------------------