Exploring Yosys/Trellis/NextPnR for Lattice ECP5

2022-04-18

I’ve been tinkering with the IceSugarPro board recently, which is a nice little SO-DIMM form factor FPGA board containing a Lattice ECP5 FPGA. It’s the successor to the earlier IceSugar board which contained a Lattice iCE40UP5k: despite not having an iCE40 series chip, the IceSugarPro retains the name!

This board is similar to the Colorlight i5 – and will even fit a breakout board intended for that module (with caveats) – however I chose this over the Colorlight for the simple reason that its SDRAM is more useful. The Colorlight i5’s SDRAM is 32 bits wide, which is appealing despite it only being eight megabytes in size – but unfortunately it’s not byte-addressable since the four DQM signals are tied low rather than connected to the FPGA.

The IceSugarPro, on the other hand, has the seemingly defacto-standard 32 megabytes of 16-bit SDRAM, with DQMs connected as normal.

The other thing that makes both boards very appealing is that they have relatively mature support in the open source tool flow, namely Yosys, Project Trellis and NextPnR. This combination, coupled with the somewhat-experimental ghdl-yosys-plugin, makes for an impressive toolchain. The documentation is excellent, and even the intermediate files generated by the tools are surprisingly human-readable, which aids in tracking down the inevitable problems as they arise. Because, naturally, it’s not all plain sailing!

I must admit I put this on the back burner for a while, when I found that I wasn’t able to build EightThirtyTwo using the GHDL plugin. This surprised me because I’ve been using GHDL right from the start to simulate and develop the CPU. I finally managed to make it work a few days ago (at the time of writing interrupts are still broken, but the rest of the CPU seems to work.)

The Gotchas and quirks I’ve encountered so far are:

  • Asynchronous resets. If you encounter an error message about “$posedge not found”, chances are you have a VHDL process with an asynchronous reset, but aren’t specifying a reset value for all signals assigned within the process. There are some subtleties here, and I’m still not 100% sure exactly what combination of circumstances triggers the error.
  • There is only the most basic support for tristate signals. In short, you can’t carry a bidirectional signal to an inner module (such as an SDRAM controller) and then conditionally assign ‘Z’ to it to make it high impedance. Whether or not the Z state is supported at all depends on the tech mapping, in this case Project Trellis – but if it is supported, the tri-stating must be done in the toplevel. For SDRAM, this means instead of having a birectional SDRAM_DQ(15 downto 0) signal, we need separate SDRAM_DQ_IN(15 downto 0) and SDRAM_DQ_OUT(15 downto 0) signals, along with a SDRAM_DRIVE_DQ signal. This poses a problem if we want to use the same codebase on other vendors’ FPGAs, since doing the tristating with combinational logic in the toplevel would prevent the cells being packed to Fast IO registers on Intel FPGAs. One possible solution is to retain the “inout” type on SDRAM_DQ_OUT, and continue to assign Z to it in the SDRAM controller. With Yosys it will silently become an “out” signal, and we can tristate in the project-specific toplevel, while on Intel devices we can pass it directly to the pins. I haven’t yet verified whether assigning SDRAM_DQ_IN from tristate pins driven from SDRAM_DQ_OUT will mess up the Fast Input Register assignment…
  • Parameters can be passed to Verilog modules from VHDL parent modules, by creating a VHDL component with suitably-named generics.
  • Generics cannot be passed to a VHDL module from a Verilog parent module. The easiest way around this is simply to wrap the VHDL module in a VHDL shim which specifies the generics.
  • The documentation says it’s possible to add ghdl files to the project directly within yosys – however when using a large number of vhdl files, it’s easier / neater to add them one by one using “ghdl -a” before running yosys and then elaborate them with yosys’s ghdl <top_entity> command. However they must be added in leaf-to-root dependency order.
  • If there is an “island” of VHDL entities instantiated from within a verilog module, it must be elaborated with yosys’s ghdl command before reading the verilog module which contains it.

I’m certainly enjoying tinkering with this board and the open source toolchain. In a future installment I shall look at bughunting the EightThirtyTwo interrupt problem (tricky, given that I can’t use SignalTap!) and also using PMODs to talk to the outside world.

Leave a Reply

Your email address will not be published. Required fields are marked *