110a5fd8d684e07fc0b3887a00b13edf543048b0
[nmigen-examples.git] / up_counter / up_counter.py
1 #from nmigen import *
2 from nmigen import Signal, Value, Elaboratable, Module, Cat, Const
3 #from nmigen import ClockDomain, ClockSignal
4 from nmigen.build import Platform
5 #from nmigen.cli import main_parser, main_runner
6 #from nmigen.asserts import Assert, Assume, Cover, Past
7
8 # --- CONVERT ---
9 from nmigen.back import verilog
10
11 from nmigen.sim import Simulator, Delay, Settle, Tick, Passive
12
13 from nmutil.gtkw import write_gtkw
14
15
16 class UpCounter(Elaboratable):
17 """
18 A 16-bit up counter with a fixed limit.
19
20 Parameters
21 ----------
22 limit : int
23 The value at which the counter overflows.
24
25 Attributes
26 ----------
27 en : Signal, in
28 The counter is incremented if ``en`` is asserted, and retains
29 its value otherwise.
30 ovf : Signal, out
31 ``ovf`` is asserted when the counter reaches its limit.
32 """
33 def __init__(self, limit):
34 self.limit = limit
35
36 # Ports
37 self.en = Signal()
38 self.ovf = Signal()
39
40 # State
41 self.count = Signal(16)
42
43 def elaborate(self, platform):
44 m = Module()
45
46 m.d.comb += self.ovf.eq(self.count == self.limit)
47
48 with m.If(self.en):
49 with m.If(self.ovf):
50 m.d.sync += self.count.eq(0)
51 with m.Else():
52 m.d.sync += self.count.eq(self.count + 1)
53
54 return m
55 # --- TEST ---
56 from nmigen.sim import Simulator
57
58
59 dut = UpCounter(25)
60 def bench():
61 # Disabled counter should not overflow.
62 yield dut.en.eq(0)
63 for _ in range(30):
64 yield
65 assert not (yield dut.ovf)
66
67 # Once enabled, the counter should overflow in 25 cycles.
68 yield dut.en.eq(1)
69 for _ in range(25):
70 yield
71 assert not (yield dut.ovf)
72 yield
73 assert (yield dut.ovf)
74
75 # The overflow should clear in one cycle.
76 yield
77 assert not (yield dut.ovf)
78
79
80 sim = Simulator(dut)
81 sim.add_clock(1e-6) # 1 MHz
82 sim.add_sync_process(bench)
83 with sim.write_vcd("up_counter.vcd"):
84 sim.run()
85
86 # GTKWave doc generation
87 style = {
88 '': {'base': 'dec'},
89 'in': {'color': 'orange'},
90 'out': {'color': 'yellow'},
91 'pad_i': {'color': 'orange'},
92 'pad_o': {'color': 'yellow'},
93 'core_i': {'color': 'indigo'},
94 'core_o': {'color': 'blue'},
95 'debug': {'module': 'top', 'color': 'red'}
96 }
97 traces = [
98 ('Counter', [
99 ('clk', 'in'),
100 ('en', 'in'),
101 ('ovf', 'in'),
102 ('rst', 'in'),
103 ('count[15:0]', 'out')
104 ])
105 ]
106
107 write_gtkw("up_counter.gtkw", "up_counter.vcd", traces, style, module="bench.top")
108
109 top = UpCounter(25)
110 with open("up_counter.v", "w") as f:
111 f.write(verilog.convert(top, ports=[top.en, top.ovf]))