return latchregister results so that it can be further set/modified
[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 qlq_n = mkname("qlq", name)
66 self.s = Signal(llen, name=s_n, reset=0)
67 self.r = Signal(llen, name=r_n, reset=(1<<llen)-1) # defaults to off
68 self.q = Signal(llen, name=q_n, reset_less=True)
69 self.qn = Signal(llen, name=qn_n, reset_less=True)
70 self.qlq = Signal(llen, name=qlq_n, reset_less=True)
71
72 def elaborate(self, platform):
73 m = Module()
74 q_int = Signal(self.llen)
75
76 m.d.sync += q_int.eq((q_int & ~self.r) | self.s)
77 if self.sync:
78 m.d.comb += self.q.eq(q_int)
79 else:
80 m.d.comb += self.q.eq((q_int & ~self.r) | self.s)
81 m.d.comb += self.qn.eq(~self.q)
82 m.d.comb += self.qlq.eq(self.q | q_int) # useful output
83
84 return m
85
86 def ports(self):
87 return self.s, self.r, self.q, self.qn
88
89
90 def sr_sim(dut):
91 yield dut.s.eq(0)
92 yield dut.r.eq(0)
93 yield
94 yield
95 yield
96 yield dut.s.eq(1)
97 yield
98 yield
99 yield
100 yield dut.s.eq(0)
101 yield
102 yield
103 yield
104 yield dut.r.eq(1)
105 yield
106 yield
107 yield
108 yield dut.r.eq(0)
109 yield
110 yield
111 yield
112
113 def test_sr():
114 dut = SRLatch(llen=4)
115 vl = rtlil.convert(dut, ports=dut.ports())
116 with open("test_srlatch.il", "w") as f:
117 f.write(vl)
118
119 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch.vcd')
120
121 dut = SRLatch(sync=False, llen=4)
122 vl = rtlil.convert(dut, ports=dut.ports())
123 with open("test_srlatch_async.il", "w") as f:
124 f.write(vl)
125
126 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch_async.vcd')
127
128 if __name__ == '__main__':
129 test_sr()