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