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