User Tools

Site Tools


Introduction to the nMigen FHDL


When coding with nMigen, we often manipulate a “Signal”. A Signal carries a varying integer value. It has a fixed width and a reset value, which is 0 by default.

A few examples:

led = Signal()
button = Signal()
counter = Signal(4, reset=3)

Of course, those declarations don't do much so far.


A Record is a collection of signals, with a predefined layout.

For example:

rgb_led = Record([("r", 1), ("g", 1), ("b", 1)])

Here we declare a rgb_led record with three 1-bit fields.


Let's say we have a button and a led, represented as signals.
Whenever the button is pressed, we want the led to turn on.

We can do that by assigning the value of the button signal to the led signal.
This assignment is done with the keyword “eq”:


Assignments alone do nothing, they must be affected to a module.


A Module is an nMigen entity that can hold assignments.

For example:

m = Module()
led1 = Signal()
led2 = Signal()
button = Signal()
m.d.comb += led1.eq(button)
m.d.sync += led2.eq(~led2)

Assignments must be affected to one of the module's domains:

  1. “comb” is a shorthand for combinatorial assignments.
    Here, led1 will always have the same value as button, as if the two were wired together.
  2. “sync” is a shorthand for synchronous assignments.
    Here, led2 will invert its value every time the clock ticks. It will hold its value between two clock ticks.


We can use If/Elif/Else statements to describe the behaviour of our leds:

m.d.comb += led1.eq(button)

is equivalent to:

with m.If(button):
    m.d.comb += led1.eq(1)
with m.Else():
    m.d.comb += led1.eq(0)

Inside the scope of a statement, we can add assignments to multiple domains:

with m.If(button):
    m.d.comb += led1.eq(1)
    m.d.sync += led2.eq(~led2)

In this example, led2 will only update its value if button is high during a clock tick.


In the next chapter, we will implement and simulate our first nMigen design.

nmigen/nmigen_fhdl.txt · Last modified: 2019/09/04 15:08 by jfng