speed up ==, hash, <, >, <=, and >= for plain_data
[nmutil.git] / src / nmutil / latch.py
index 2086fe59695c3aad7b2f47d9b7dd005e4c9c128c..e2d7541d396fa7468668f4bd903346abd504a94f 100644 (file)
@@ -1,6 +1,14 @@
+# SPDX-License-Identifier: LGPL-3-or-later
+"""
+    This work is funded through NLnet under Grant 2019-02-012
+
+    License: LGPLv3+
+
+
+"""
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
-from nmigen import Signal, Module, Const, Elaboratable
+from nmigen import Record, Signal, Module, Const, Elaboratable, Mux
 
 """ jk latch
 
@@ -21,36 +29,61 @@ always @ (posedge c)
 endmodule
 """
 
+
 def latchregister(m, incoming, outgoing, settrue, name=None):
-    reg = Signal.like(incoming, name=name) # make reg same as input. reset OK.
-    with m.If(settrue):
+    """latchregister
+
+    based on a conditon, "settrue", incoming data will be "latched"
+    into a register and passed out on "outgoing".
+
+    * if "settrue" is ASSERTED, outgoing is COMBINATORIALLY equal to incoming
+    * on the same cycle that settrue is DEASSERTED, outgoing REMAINS
+      equal (indefinitely) to the incoming value
+    """
+    # make reg same as input. reset OK.
+    if isinstance(incoming, Record):
+        reg = Record.like(incoming, name=name)
+    else:
+        reg = Signal.like(incoming, name=name)
+    m.d.comb += outgoing.eq(Mux(settrue, incoming, reg))
+    with m.If(settrue):  # pass in some kind of expression/condition here
         m.d.sync += reg.eq(incoming)      # latch input into register
-        m.d.comb += outgoing.eq(incoming) # return input (combinatorial)
-    with m.Else():
-        m.d.comb += outgoing.eq(reg) # return input (combinatorial)
+    return reg
+
+
+def mkname(prefix, suffix):
+    if suffix is None:
+        return prefix
+    return "%s_%s" % (prefix, suffix)
 
 
 class SRLatch(Elaboratable):
-    def __init__(self, sync=True, llen=1):
+    def __init__(self, sync=True, llen=1, name=None):
         self.sync = sync
         self.llen = llen
-        self.s = Signal(llen, reset=0)
-        self.r = Signal(llen, reset=(1<<llen)-1) # defaults to off
-        self.q = Signal(llen, reset_less=True)
-        self.qn = Signal(llen, reset_less=True)
-        self.qlq = Signal(llen, reset_less=True)
+        s_n, r_n = mkname("s", name), mkname("r", name)
+        q_n, qn_n = mkname("q", name), mkname("qn", name)
+        qint = mkname("qint", name)
+        qlq_n = mkname("qlq", name)
+        self.s = Signal(llen, name=s_n, reset=0)
+        self.r = Signal(llen, name=r_n, reset=(1 << llen)-1)  # defaults to off
+        self.q = Signal(llen, name=q_n, reset_less=True)
+        self.qn = Signal(llen, name=qn_n, reset_less=True)
+        self.qlq = Signal(llen, name=qlq_n, reset_less=True)
+        self.q_int = Signal(llen, name=qint, reset_less=True)
 
     def elaborate(self, platform):
         m = Module()
-        q_int = Signal(self.llen)
 
-        m.d.sync += q_int.eq((q_int & ~self.r) | self.s)
+        next_o = Signal(self.llen, reset_less=True)
+        m.d.comb += next_o.eq((self.q_int & ~self.r) | self.s)
+        m.d.sync += self.q_int.eq(next_o)
         if self.sync:
-            m.d.comb += self.q.eq(q_int)
+            m.d.comb += self.q.eq(self.q_int)
         else:
-            m.d.comb += self.q.eq((q_int & ~self.r) | self.s)
+            m.d.comb += self.q.eq(next_o)
         m.d.comb += self.qn.eq(~self.q)
-        m.d.comb += self.qlq.eq(self.q | q_int) # useful output
+        m.d.comb += self.qlq.eq(self.q | self.q_int)  # useful output
 
         return m
 
@@ -81,6 +114,7 @@ def sr_sim(dut):
     yield
     yield
 
+
 def test_sr():
     dut = SRLatch(llen=4)
     vl = rtlil.convert(dut, ports=dut.ports())
@@ -96,5 +130,6 @@ def test_sr():
 
     run_simulation(dut, sr_sim(dut), vcd_name='test_srlatch_async.vcd')
 
+
 if __name__ == '__main__':
     test_sr()