├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── LICENSE.txt ├── README.md ├── top.lpf └── top.py /.gitignore: -------------------------------------------------------------------------------- 1 | !.vscode 2 | *.il 3 | *.json 4 | *.config 5 | *.bit 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "yowasp.toolchain" 4 | ] 5 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "yowaspToolchain.pythonRequirements": [ 3 | "amaranth" 4 | ], 5 | "yowaspToolchain.buildCommands": [ 6 | ["python", "top.py"], 7 | ["yosys", "top.il", "-o", "top.json", "-p", "synth_ecp5"], 8 | ["nextpnr-ecp5", "--85k", "--package", "CABGA381", "--json", "top.json", "--lpf", "top.lpf", "--textcfg", "top.config"], 9 | ["ecppack", "--compress", "top.config", "top.bit"], 10 | ["openFPGALoader", "-b", "ulx3s", "-m", "top.bit"] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (C) Catherine 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demonstration of the [YoWASP toolchain](https://yowasp.org/) and [its VS Code extension](https://marketplace.visualstudio.com/items?itemName=yowasp.toolchain) 2 | 3 | ## Getting started 4 | 5 | You can run this demonstration either with or without hardware. The design is built for the [Radiona ULX3S](https://radiona.org/ulx3s/) board, and bitstream upload only works on [WebUSB-enabled browsers](https://caniuse.com/webusb) (and not on the desktop VS Code at the moment). If these requirements are not met, the board programming will fail, but every step before that will still complete. 6 | 7 | 1. Open this repository in Visual Studio Code. If you have a GitHub account, you can open it [directly via vscode.dev](https://vscode.dev/github/YoWASP/toolchain-demo); otherwise, use any 8 | 2. Install the [YoWASP VS Code extension](https://marketplace.visualstudio.com/items?itemName=yowasp.toolchain) (there will be a prompt to do so in the lower right corner; click "Install"). 9 | 3. **(Only when using hardware)** Plug your FPGA evaluation board into a USB port. 10 | 4. Press Ctrl+Shift+P (or open menu "View" → "Command Palette...") and navigate to "YoWASP Toolchain: Build..." by typing the first letters of each word. Press Enter. 11 | 5. A terminal will open at the bottom of the window and show the progress of the build process. It may take a few minutes to complete for the first time, and at times there may be no progress indication. This is normal; running the toolchain for the first time requires downloading about 100 MB of code and data, which will be cached afterwards in the browser. 12 | 6. **(Only when using hardware)** A prompt to use a USB device will appear in the lower right corner; click "Connect Device", pick the line starting with "ULX3S FPGA" in the panel that opens, and click "Connect" in that panel. 13 | 7. **(Only when using hardware)** The terminal will now show the progress of the bitstream loading process. This should only take a few seconds, and when complete, the board will start blinking a LED at 1 Hz. 14 | 8. That's it! Now that your environment is verified to work, you can fork this repository and play with the demo design. 15 | 16 | ## Customizing the demo 17 | 18 | This demonstration is made for the Radiona ULX3S board, but it could be used with any Lattice iCE40, ECP5, MachXO2, MachXO3, or Nexus FPGAs; see also the [openFPGALoader board compatibility list](https://trabucayre.github.io/openFPGALoader/compatibility/board.html). The build process is configured in the `.vscode/settings.json` file, and will need to be adjusted for your particular FPGA and board. 19 | -------------------------------------------------------------------------------- /top.lpf: -------------------------------------------------------------------------------- 1 | LOCATE COMP "clk" SITE "G2"; 2 | IOBUF PORT "clk" IO_TYPE=LVCMOS33; 3 | FREQUENCY PORT "clk" 25000000.0 HZ; 4 | 5 | LOCATE COMP "rst" SITE "R1"; 6 | IOBUF PORT "rst" IO_TYPE=LVCMOS33 PULLMODE=DOWN; 7 | 8 | LOCATE COMP "led" SITE "B2"; 9 | IOBUF PORT "led" IO_TYPE=LVCMOS33 DRIVE=4; 10 | -------------------------------------------------------------------------------- /top.py: -------------------------------------------------------------------------------- 1 | from amaranth import * 2 | from amaranth.lib import wiring 3 | from amaranth.lib.wiring import In, Out 4 | 5 | 6 | class Blinky(wiring.Component): 7 | led: Out(1) 8 | 9 | def __init__(self, frequency): 10 | self.frequency = frequency 11 | 12 | super().__init__() 13 | 14 | def elaborate(self, platform): 15 | m = Module() 16 | count = Signal(range(self.frequency // 2)) 17 | with m.If(count == self.frequency // 2 - 1): 18 | m.d.sync += self.led.eq(~self.led) 19 | m.d.sync += count.eq(0) 20 | with m.Else(): 21 | m.d.sync += count.eq(count + 1) 22 | return m 23 | 24 | 25 | if __name__ == '__main__': 26 | from amaranth.back import rtlil 27 | 28 | with open('top.il', 'w') as f: 29 | f.write(rtlil.convert(Blinky(25_000_000))) 30 | --------------------------------------------------------------------------------