add docstring to latchregister
[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
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 def latchregister(m, incoming, outgoing, settrue, name=None):
25 """latchregister
26
27 based on a conditon, "settrue", incoming data will be "latched"
28 into a register and passed out on "outgoing".
29
30 * if "settrue" is ASSERTED, outgoing is COMBINATORIALLY equal to incoming
31 * on the same cycle that settrue is DEASSERTED, outgoing REMAINS
32 equal (indefinitely) to the incoming value
33 """
34 # make reg same as input. reset OK.
35 if isinstance(incoming, Record):
36 reg = Record.like(incoming, name=name)
37 else:
38 reg = Signal.like(incoming, name=name)
39 with m.If(settrue): # pass in some kind of expression/condition here
40 m.d.sync += reg.eq(incoming) # latch input into register
41 m.d.comb += outgoing.eq(incoming) # return input (combinatorial)
42 with m.Else():
43 m.d.comb += outgoing.eq(reg) # return input (combinatorial)
44
45 def mkname(prefix, suffix):
46 if suffix is None:
47 return prefix
48 return "%s_%s" % (prefix, suffix)
49
50 class SRLatch(Elaboratable):
51 def __init__(self, sync=True, llen=1, name=None):
52 self.sync = sync
53 self.llen = llen
54 s_n, r_n = mkname("s", name), mkname("r", name)
55 q_n, qn_n = mkname("q", name), mkname("qn", name)
56 qlq_n = mkname("qlq", name)
57 self.s = Signal(llen, name=s_n, reset=0)
58 self.r = Signal(llen, name=r_n, reset=(1<<llen)-1) # defaults to off
59 self.q = Signal(llen, name=q_n, reset_less=True)
60 self.qn = Signal(llen, name=qn_n, reset_less=True)
61 self.qlq = Signal(llen, name=qlq_n, reset_less=True)
62
63 def elaborate(self, platform):
64 m = Module()
65 q_int = Signal(self.llen)
66
67 m.d.sync += q_int.eq((q_int & ~self.r) | self.s)
68 if self.sync:
69 m.d.comb += self.q.eq(q_int)
70 else:
71 m.d.comb += self.q.eq((q_int & ~self.r) | self.s)
72 m.d.comb += self.qn.eq(~self.q)
73 m.d.comb += self.qlq.eq(self.q | q_int) # useful output
74
75 return m
76
77 def ports(self):
78 return self.s, self.r, self.q, self.qn
79
80
81 def sr_sim(dut):
82 yield dut.s.eq(0)
83 yield dut.r.eq(0)
84 yield
85 yield
86 yield
87 yield dut.s.eq(1)
88 yield
89 yield
90 yield
91 yield dut.s.eq(0)
92 yield
93 yield
94 yield
95 yield dut.r.eq(1)
96 yield
97 yield
98 yield
99 yield dut.r.eq(0)
100 yield
101 yield
102 yield
103
104 def test_sr():
105 dut = SRLatch(llen=4)
106 vl = rtlil.convert(dut, ports=dut.ports())
107 with open("test_srlatch.il", "w") as f:
108 f.write(vl)
109
110 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch.vcd')
111
112 dut = SRLatch(sync=False, llen=4)
113 vl = rtlil.convert(dut, ports=dut.ports())
114 with open("test_srlatch_async.il", "w") as f:
115 f.write(vl)
116
117 run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch_async.vcd')
118
119 if __name__ == '__main__':
120 test_sr()