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.
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.
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:
led1will always have the same value as
button, as if the two were wired together.
led2will 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.