speed up ==, hash, <, >, <=, and >= for plain_data
[nmutil.git] / src / nmutil / latch.py
1 # SPDX-License-Identifier: LGPL-3-or-later
2 """
3 This work is funded through NLnet under Grant 2019-02-012
4
5 License: LGPLv3+
6
7
8 """
9 from nmigen.compat.sim import run_simulation
10 from nmigen.cli import verilog, rtlil
11 from nmigen import Record, Signal, Module, Const, Elaboratable, Mux
12
13 """ jk latch
14
15 module jk(q,q1,j,k,c);
16 output q,q1;
17 input j,k,c;
18 reg q,q1;
19 initial begin q=1'b0; q1=1'b1; end
20 always @ (posedge c)
21 begin
22 case({j,k})
23 {1'b0,1'b0}:begin q=q; q1=q1; end
24 {1'b0,1'b1}: begin q=1'b0; q1=1'b1; end
25 {1'b1,1'b0}:begin q=1'b1; q1=1'b0; end
26 {1'b1,1'b1}: begin q=~q; q1=~q1; end
27 endcase
28 end
29 endmodule
30 """
31
32
33 def latchregister(m, incoming, outgoing, settrue, name=None):
34 """latchregister
35
36 based on a conditon, "settrue", incoming data will be "latched"
37 into a register and passed out on "outgoing".
38
39 * if "settrue" is ASSERTED, outgoing is COMBINATORIALLY equal to incoming
40 * on the same cycle that settrue is DEASSERTED, outgoing REMAINS
41 equal (indefinitely) to the incoming value
42 """
43 # make reg same as input. reset OK.
44 if isinstance(incoming, Record):
45 reg = Record.like(incoming, name=name)
46 else:
47 reg = Signal.like(incoming, name=name)
48 m.d.comb += outgoing.eq(Mux(settrue, incoming, reg))
49 with m.If(settrue): # pass in some kind of expression/condition here
50 m.d.sync += reg.eq(incoming) # latch input into register
51 return reg
52
53
54 def mkname(prefix, suffix):
55 if suffix is None:
56 return prefix
57 return "%s_%s" % (prefix, suffix)
58
59
60 class SRLatch(Elaboratable):
61 def __init__(self, sync=True, llen=1, name=None):
62 self.sync = sync
63 self.llen = llen
64 s_n, r_n = mkname("s", name), mkname("r", name)
65 q_n, qn_n = mkname("q", name), mkname("qn", name)
66 qint = mkname("qint", name)
67 qlq_n = mkname("qlq", name)
68 self.s = Signal(llen, name=s_n, reset=0)
69 self.r = Signal(llen, name=r_n, reset=(1 << llen)-1) # defaults to off
70 self.q = Signal(llen, name=q_n, reset_less=True)
71 self.qn = Signal(llen, name=qn_n, reset_less=True)
72 self.qlq = Signal(llen, name=qlq_n, reset_less=True)
73 self.q_int = Signal(llen, name=qint, reset_less=True)
74
75 def elaborate(self, platform):
76 m = Module()
77
78 next_o = Signal(self.llen, reset_less=True)
79 m.d.comb += next_o.eq((self.q_int & ~self.r) | self.s)
80 m.d.sync += self.q_int.eq(next_o)
81 if self.sync:
82 m.d.comb += self.q.eq(self.q_int)
83 else:
84 m.d.comb += self.q.eq(next_o)
85 m.d.comb += self.qn.eq(~self.q)
86 m.d.comb += self.qlq.eq(self.q | self.q_int) # useful output
87
88 return m
89
90 def ports(self):
91 return self.s, self.r, self.q, self.qn
92
93
94 def sr_sim(dut):
95 yield dut.s.eq(0)
96 yield dut.r.eq(0)
97 yield
98 yield
99 yield
100 yield dut.s.eq(1)
101 yield
102 yield
103 yield
104 yield dut.s.eq(0)
105 yield
106 yield
107 yield
108 yield dut.r.eq(1)
109 yield
110 yield
111 yield
112 yield dut.r.eq(0)
113 yield
114 yield
115 yield
116
117
118 def test_sr():
119 dut = SRLatch(llen=4)
120 vl = rtlil.convert(dut, ports=dut.ports())
121 with open("test_srlatch.il", "w") as f:
122 f.write(vl)
123
124 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch.vcd')
125
126 dut = SRLatch(sync=False, llen=4)
127 vl = rtlil.convert(dut, ports=dut.ports())
128 with open("test_srlatch_async.il", "w") as f:
129 f.write(vl)
130
131 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch_async.vcd')
132
133
134 if __name__ == '__main__':
135 test_sr()