store latch next in temporary
[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 next_o = Signal(self.llen, reset_less=True)
78 m.d.comb += next_o.eq((self.q_int & ~self.r) | self.s)
79 m.d.sync += self.q_int.eq(next_o)
80 if self.sync:
81 m.d.comb += self.q.eq(self.q_int)
82 else:
83 m.d.comb += self.q.eq(next_o)
84 m.d.comb += self.qn.eq(~self.q)
85 m.d.comb += self.qlq.eq(self.q | self.q_int) # useful output
86
87 return m
88
89 def ports(self):
90 return self.s, self.r, self.q, self.qn
91
92
93 def sr_sim(dut):
94 yield dut.s.eq(0)
95 yield dut.r.eq(0)
96 yield
97 yield
98 yield
99 yield dut.s.eq(1)
100 yield
101 yield
102 yield
103 yield dut.s.eq(0)
104 yield
105 yield
106 yield
107 yield dut.r.eq(1)
108 yield
109 yield
110 yield
111 yield dut.r.eq(0)
112 yield
113 yield
114 yield
115
116 def test_sr():
117 dut = SRLatch(llen=4)
118 vl = rtlil.convert(dut, ports=dut.ports())
119 with open("test_srlatch.il", "w") as f:
120 f.write(vl)
121
122 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch.vcd')
123
124 dut = SRLatch(sync=False, llen=4)
125 vl = rtlil.convert(dut, ports=dut.ports())
126 with open("test_srlatch_async.il", "w") as f:
127 f.write(vl)
128
129 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch_async.vcd')
130
131 if __name__ == '__main__':
132 test_sr()