update SRLatch API to include q_int
[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 return reg
51
52
53 def mkname(prefix, suffix):
54 if suffix is None:
55 return prefix
56 return "%s_%s" % (prefix, suffix)
57
58
59 class SRLatch(Elaboratable):
60 def __init__(self, sync=True, llen=1, name=None):
61 self.sync = sync
62 self.llen = llen
63 s_n, r_n = mkname("s", name), mkname("r", name)
64 q_n, qn_n = mkname("q", name), mkname("qn", name)
65 qint = mkname("qint", name)
66 qlq_n = mkname("qlq", name)
67 self.s = Signal(llen, name=s_n, reset=0)
68 self.r = Signal(llen, name=r_n, reset=(1<<llen)-1) # defaults to off
69 self.q = Signal(llen, name=q_n, reset_less=True)
70 self.qn = Signal(llen, name=qn_n, reset_less=True)
71 self.qlq = Signal(llen, name=qlq_n, reset_less=True)
72 self.q_int = Signal(llen, name=qint, reset_less=True)
73
74 def elaborate(self, platform):
75 m = Module()
76
77 m.d.sync += self.q_int.eq((self.q_int & ~self.r) | self.s)
78 if self.sync:
79 m.d.comb += self.q.eq(self.q_int)
80 else:
81 m.d.comb += self.q.eq((self.q_int & ~self.r) | self.s)
82 m.d.comb += self.qn.eq(~self.q)
83 m.d.comb += self.qlq.eq(self.q | self.q_int) # useful output
84
85 return m
86
87 def ports(self):
88 return self.s, self.r, self.q, self.qn
89
90
91 def sr_sim(dut):
92 yield dut.s.eq(0)
93 yield dut.r.eq(0)
94 yield
95 yield
96 yield
97 yield dut.s.eq(1)
98 yield
99 yield
100 yield
101 yield dut.s.eq(0)
102 yield
103 yield
104 yield
105 yield dut.r.eq(1)
106 yield
107 yield
108 yield
109 yield dut.r.eq(0)
110 yield
111 yield
112 yield
113
114 def test_sr():
115 dut = SRLatch(llen=4)
116 vl = rtlil.convert(dut, ports=dut.ports())
117 with open("test_srlatch.il", "w") as f:
118 f.write(vl)
119
120 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch.vcd')
121
122 dut = SRLatch(sync=False, llen=4)
123 vl = rtlil.convert(dut, ports=dut.ports())
124 with open("test_srlatch_async.il", "w") as f:
125 f.write(vl)
126
127 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch_async.vcd')
128
129 if __name__ == '__main__':
130 test_sr()