We should now be able to implement our first module.
Our goal here is to have a module with a led, that blinks. We'll call it “blinky”.
Here is the code:
from nmigen import * from nmigen.cli import main class Blinky(Elaboratable): def __init__(self): self.led = Signal() def elaborate(self, platform): m = Module() counter = Signal(3) m.d.sync += counter.eq(counter + 1) m.d.comb += self.led.eq(counter[2]) return m if __name__ == "__main__": top = Blinky() main(top, ports=(top.led))
As we can see, our module is created inside an elaborate()
method, which returns it.
The platform
parameter gives us access to I/O resources, and will be covered in a later chapter.
counter = Signal(3) m.d.sync += counter.eq(counter + 1)
We have declared a 3-bit counter, which will increment at each clock tick (from 0 to 7). Once it reaches 7, it will wrap and restart at 0.
m.d.comb += self.led.eq(counter[2])
We assign the highest bit of our counter to the led. This bit will toggle the slowest, at 1/8 of the clock frequency.
Notice that counter[2]
is the 3rd register of our 3-bit counter.
This assignment is combinatorial, so it does not depend on a clock. In other words: “no matter what, we want our led to reflect the value of the 3rd bit of the counter”.
In more realistic conditions, if we had a 50MHz clock, we would want our counter to be much bigger, like 22-bits or more, so the led blink is slow enough to be observable.
The nMigen CLI is handy for common use cases such as simulating designs or generating RTLIL/Verilog.
Let's show the help:
% python blinky.py -h usage: blinky.py [-h] {generate,simulate} ... positional arguments: {generate,simulate} generate generate RTLIL or Verilog from the design simulate simulate the design optional arguments: -h, --help show this help message and exit
% python blinky.py simulate -h usage: blinky.py simulate [-h] [-v VCD-FILE] [-w GTKW-FILE] [-p TIME] -c COUNT optional arguments: -h, --help show this help message and exit -v VCD-FILE, --vcd-file VCD-FILE write execution trace to VCD-FILE -w GTKW-FILE, --gtkw-file GTKW-FILE write GTKWave configuration to GTKW-FILE -p TIME, --period TIME set 'sync' clock domain period to TIME (default: 1e-06) -c COUNT, --clocks COUNT simulate for COUNT 'sync' clock periods
We want to simulate our design for 20 clock cycles.
% python blinky.py simulate -c 20 -v blinky.vcd
Notice that we also provided a -v blinky.vcd
argument. This will output the waveform in a VCD file, which can later be inspected with software such as GTKWave.
We see the led switches on an off at the same time as the counter's highest bit.
We can also see the counter wrapping from 0b111 to 0b000 as it overflows.
In the next chapter, we will see how to organize larger designs into a hierarchy of modules.