Adding README and counter example.
authorAndrey Miroshnikov <andrey@technepisteme.xyz>
Sun, 24 Sep 2023 13:08:11 +0000 (13:08 +0000)
committerAndrey Miroshnikov <andrey@technepisteme.xyz>
Sun, 24 Sep 2023 13:08:11 +0000 (13:08 +0000)
README.md [new file with mode: 0644]
up_counter/up_counter.py [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..a6491cf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# nMigen Examples (To be used with Libre-SOC flow)
+
+See the Libre-SOC nMigen [tutorial page](https://libre-soc.org/docs/learning_nmigen/)
+
+## Counter example
+
+Example modified from [original in nMigen repo](https://gitlab.com/nmigen/nmigen/blob/master/docs/start.rst).
+
+Includes gtkw nmutils lib for generating the .gtkw trace file.
+
+To run:
+
+    python3 up_counter.py
diff --git a/up_counter/up_counter.py b/up_counter/up_counter.py
new file mode 100644 (file)
index 0000000..110a5fd
--- /dev/null
@@ -0,0 +1,111 @@
+#from nmigen import *
+from nmigen import Signal, Value, Elaboratable, Module, Cat, Const
+#from nmigen import ClockDomain, ClockSignal
+from nmigen.build import Platform
+#from nmigen.cli import main_parser, main_runner
+#from nmigen.asserts import Assert, Assume, Cover, Past
+
+# --- CONVERT ---
+from nmigen.back import verilog
+
+from nmigen.sim import Simulator, Delay, Settle, Tick, Passive
+
+from nmutil.gtkw import write_gtkw
+
+
+class UpCounter(Elaboratable):
+    """
+    A 16-bit up counter with a fixed limit.
+
+    Parameters
+    ----------
+    limit : int
+        The value at which the counter overflows.
+
+    Attributes
+    ----------
+    en : Signal, in
+        The counter is incremented if ``en`` is asserted, and retains
+        its value otherwise.
+    ovf : Signal, out
+        ``ovf`` is asserted when the counter reaches its limit.
+    """
+    def __init__(self, limit):
+        self.limit = limit
+
+        # Ports
+        self.en  = Signal()
+        self.ovf = Signal()
+
+        # State
+        self.count = Signal(16)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        m.d.comb += self.ovf.eq(self.count == self.limit)
+
+        with m.If(self.en):
+            with m.If(self.ovf):
+                m.d.sync += self.count.eq(0)
+            with m.Else():
+                m.d.sync += self.count.eq(self.count + 1)
+
+        return m
+# --- TEST ---
+from nmigen.sim import Simulator
+
+
+dut = UpCounter(25)
+def bench():
+    # Disabled counter should not overflow.
+    yield dut.en.eq(0)
+    for _ in range(30):
+        yield
+        assert not (yield dut.ovf)
+
+    # Once enabled, the counter should overflow in 25 cycles.
+    yield dut.en.eq(1)
+    for _ in range(25):
+        yield
+        assert not (yield dut.ovf)
+    yield
+    assert (yield dut.ovf)
+
+    # The overflow should clear in one cycle.
+    yield
+    assert not (yield dut.ovf)
+
+
+sim = Simulator(dut)
+sim.add_clock(1e-6) # 1 MHz
+sim.add_sync_process(bench)
+with sim.write_vcd("up_counter.vcd"):
+    sim.run()
+
+# GTKWave doc generation
+style = {
+    '': {'base': 'dec'},
+    'in': {'color': 'orange'},
+    'out': {'color': 'yellow'},
+    'pad_i': {'color': 'orange'},
+    'pad_o': {'color': 'yellow'},
+    'core_i': {'color': 'indigo'},
+    'core_o': {'color': 'blue'},
+    'debug': {'module': 'top', 'color': 'red'}
+}
+traces = [
+    ('Counter', [
+        ('clk', 'in'),
+        ('en', 'in'),
+        ('ovf', 'in'),
+        ('rst', 'in'),
+        ('count[15:0]', 'out')
+    ])
+]
+
+write_gtkw("up_counter.gtkw", "up_counter.vcd", traces, style, module="bench.top")
+
+top = UpCounter(25)
+with open("up_counter.v", "w") as f:
+    f.write(verilog.convert(top, ports=[top.en, top.ovf]))