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