format code
[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
117 def test_sr():
118 dut = SRLatch(llen=4)
119 vl = rtlil.convert(dut, ports=dut.ports())
120 with open("test_srlatch.il", "w") as f:
121 f.write(vl)
122
123 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch.vcd')
124
125 dut = SRLatch(sync=False, llen=4)
126 vl = rtlil.convert(dut, ports=dut.ports())
127 with open("test_srlatch_async.il", "w") as f:
128 f.write(vl)
129
130 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch_async.vcd')
131
132
133 if __name__ == '__main__':
134 test_sr()