Migen is a Python library designed for building FPGA and ASIC applications that has seen what feels like exponentially increasing usage via word-of-mouth over the past 7 years. With many examples of Migen being used in production, the main architects over at M-labs have noticed a number of flaws with the language that have constituted a moderate reboot of the library called nMigen.1
While Migen (oMigen) continues to get updates for new targets and bug fixes,
the future direction of work on Migen from M-labs will be focused on nMigen.
A compatibility layer
is provided so that designs not using nMigen's
modules can be ported seamlessly to nMigen with as little as a single import
from migen import * to
from nmigen.compat import *.2
This post is meant to serve as an primer to quickly get started in nMigen for someone familiar with oMigen. The target audience comfortable with using a large majority of oMigen features, although they need not know every single parameter by memory of some of the more complicated oMigen constructs like memories.
Without delving into syntax, and as someone still more familiar with writing oMigen compared to nMigen, these are the major differences/similarities I personally noted when writing nMigen code and synthesizing code to FPGAs:
The fundamental unit of HDL code is still the
although their instantiation and adding HDL statements differs between
oMigen and nMigen.
Module creation needs to be done within the scope of a method
elaborate. You will typically subclass nMigen's
and add your input/output signals and
submodules as class members accessible
__init__. You then also create a method known as
elaborate in which you construct your
Module using nMigen language
Fragments are also still present in nMigen, but have semantically different
properties that are beyond the scope of this post.3
nMigen breaks the cycle of FPGA tools targeting Verilog/VHDL only.
nMigen generates yosys's RTLIL Intermediate Representation (IR) as output rather than taking oMigen's Verilog generation approach. This now means yosys is a hard dependency when using nMigen.
For proprietary toolchains which can accept only Verilog or VHDL, yosys's
write_verilog commmand is capable of converting back to Verilog from RTLIL.
nMigen explicitly supports this use-case via
On the other hand, all FOSS toolchains for FPGAs currently (and for the foreseeable future, will) require yosys before the Place-And-Route (PNR) and bitstream generation. Since yosys will happily generate input files compatible with FOSS PNR tools4 from RTLIL by design, this means that one can generate an FPGA bitstream using nMigen without needing to target Verilog first (beyond the Verilog libraries yosys uses internally)!
nMigen uses Python context managers to implement flow control.
Context managers mean it is now possible to pair
under the same
FSM blocks. The context
managers have access to enough information to correctly handle statements
with the same trigger condition but different clock domains (including
This feature has no equivalent in oMigen, where flow control constructs were
tied to a specific clock domain (or the comb "domain") via
self.sync += [If(..., ...).Else(...)].
FSMs are also implemented as a context manager in nMigen, whereas in oMigen
they are implemented as plain Modules with a
do_finalize method that hooks
into oMigen internals to generate the required code correctly. Because one
can associate multiple domains to the same trigger condition using context
NextValue node, commonly used to build FSMs in oMigen, is no
longer needed and thus has been removed. FSM ergonomics was one of the
primary reasons for switching to context managers in nMigen, and will be
demonstrated with sample code later.
There are no more
The lack of
Specials affects how
Tristates in particular
are implemented, which I'll discuss later. Discussing the lack of
do_finalize is beyond the scope of this post.3
nMigen supports yosys's formal verification facilities.
This could be a blog post in and of itself and is beyond the scope of this post. That being said, this is an nMigen exclusive feature, not available to the oMigen compatibility layer.
The build system has been revamped, and is not compatible with
For most cases, the required changes are minimal burden (although I will
briefly discuss internals later). As of this writing (6-27-2019), only
targeting Xilinx Spartan 6, Xilinx Series 7, Lattice iCE40, and Lattice ECP5
is supported, a subset of
Board files still exist, but now live in their own repository called nmigen-boards.
As of this writing (6-27-2019), porting a board to nmigen is a follow up post I intend to make soon. Board file layout is beyond the scope of this post.
Now that I have summarized a high-level overview of nMigen and oMigen differences, I will now demonstrate how to write nMigen code by comparing and contrasting (effectively) functionally identical code snippets written in both languages. The previous section will serve as a guide.
DDR I/O, etc. Good lead-in from Tristates
This post was ultimately meant to serve as a lead-in to porting your own FPGA development board to nMigen. In my analogous post for oMigen, I assumed a user had no prior Migen experience. Thus I gave a quick primer on Migen before describing how to port a board. This matched my original experiences with oMigen in April 2015, where I in fact successfully ported a board before I could ever test it at the bench.
For the analogous nMigen post, my intent was to inline this entire post into the porting a new board post, while also giving a quick primer for those wh have never seen oMigen or nMigen. This way, I felt I was accommodating multiple skill levels. However, I soon figured out there's enough information about oMigen and nMigen differences that it was best to create this post as a prerequisite for previous oMigen users.
That said, I hope this post is useful in and of itself for those familiar with oMigen and LiteX for getting started with the future direction of Migen development. As someone fairly satisfied5 with nMigen's design decisions, I look forward to what new designs people have to offer in nMigen.
1 While I am involved with submitting new features to nMigen not in (o)Migen, I was/am not personally involved design decisions of nMigen core. I defer a blog post or discussion of nMigen design decisions to someone at M-labs.
2 Miscompilation of code using the nMigen compatibility layer that previously worked in oMigen is considered a good bug report :).
3 This should be read as "I am not currently qualified to discuss the differences, and while I think they're important, I am deferring discussion to an update to this post" :).
4 There are a number of FOSS PNR tools in various states of development, but the primary two currently used by projects are nextpnr and arachne-pnr. Nextpnr is preferred for all new projects because it is FPGA-family agnostic and just about superior to arachne-pnr in features (multiple clock constraints, timing-driven placement) and resultant bitstream quality in every way.