speed up ==, hash, <, >, <=, and >= for plain_data
[nmutil.git] / src / nmutil / concurrentunit.py
index 6280a59f85958046d5be23b3bc4c41d764e35129..f317fbcd52ed1c8ee16630841bf23f2ba3681b33 100644 (file)
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: LGPL-3-or-later
 """ concurrent unit from mitch alsup augmentations to 6600 scoreboard
 
     This work is funded through NLnet under Grant 2019-02-012
@@ -101,6 +102,7 @@ class ALUProxy:
     sandwiched in between the fan-in and fan-out.  One ALU looks like
     it is multiple concurrent ALUs
     """
+
     def __init__(self, alu, p, n):
         self.alu = alu
         self.p = p
@@ -121,14 +123,15 @@ class ReservationStations(Elaboratable):
 
         Fan-in and Fan-out are combinatorial.
     """
+
     def __init__(self, num_rows, maskwid=0, feedback_width=None):
         self.num_rows = nr = num_rows
         self.feedback_width = feedback_width
         self.inpipe = InMuxPipe(nr, self.i_specfn, maskwid)   # fan-in
-        self.outpipe = MuxOutPipe(nr, self.o_specfn, maskwid) # fan-out
+        self.outpipe = MuxOutPipe(nr, self.o_specfn, maskwid)  # fan-out
 
         self.p = self.inpipe.p  # kinda annoying,
-        self.n = self.outpipe.n # use pipe in/out as this class in/out
+        self.n = self.outpipe.n  # use pipe in/out as this class in/out
         self._ports = self.inpipe.ports() + self.outpipe.ports()
 
     def setup_pseudoalus(self):
@@ -188,7 +191,9 @@ class ReservationStations2(Elaboratable):
         class to correctly set that muxid in each data packet to the
         correct constant.  this could change in future.
 
+        FAILING TO SET THE MUXID IS GUARANTEED TO RESULT IN CORRUPTED DATA.
     """
+
     def __init__(self, alu, num_rows, alu_name=None):
         if alu_name is None:
             alu_name = "alu"
@@ -207,7 +212,7 @@ class ReservationStations2(Elaboratable):
             self.p.append(p)
             self.n.append(n)
 
-        self.pipe = self # for Arbiter to select the incoming prevcontrols
+        self.pipe = self  # for Arbiter to select the incoming prevcontrols
 
         # set up pseudo-alus that look like a standard pipeline
         self.pseudoalus = []
@@ -225,7 +230,7 @@ class ReservationStations2(Elaboratable):
 
     def elaborate(self, platform):
         m = Module()
-        pe = PriorityEncoder(self.num_rows) # input priority picker
+        pe = PriorityEncoder(self.num_rows)  # input priority picker
         m.submodules[self.alu_name] = self.alu
         m.submodules.selector = pe
         for i, (p, n) in enumerate(zip(self.p, self.n)):
@@ -237,9 +242,9 @@ class ReservationStations2(Elaboratable):
         self.m_id = Signal.like(pe.o)
 
         # ReservationStation status information, progressively updated in FSM
-        rsvd = Signal(self.num_rows) # indicates RS data in flight
-        sent = Signal(self.num_rows) # sent indicates data in pipeline
-        wait = Signal(self.num_rows) # the outputs are waiting for accept
+        rsvd = Signal(self.num_rows)  # indicates RS data in flight
+        sent = Signal(self.num_rows)  # sent indicates data in pipeline
+        wait = Signal(self.num_rows)  # the outputs are waiting for accept
 
         # pick first non-reserved ReservationStation with data not already
         # sent into the ALU
@@ -249,7 +254,7 @@ class ReservationStations2(Elaboratable):
 
         # mux in and mux out ids.  note that all data *must* have a muxid
         mid = self.m_id                   # input mux selector
-        o_muxid = self.alu.n.o_data.muxid # output mux selector
+        o_muxid = self.alu.n.o_data.muxid  # output mux selector
 
         # technically speaking this could be set permanently "HI".
         # when all the ReservationStations outputs are waiting,
@@ -266,68 +271,68 @@ class ReservationStations2(Elaboratable):
 
         # first, establish input: select one input to pass data to (p_mux)
         for i in range(self.num_rows):
-            i_buf, o_buf = self.alu.new_specs("buf%d" % i) # buffers
+            i_buf, o_buf = self.alu.new_specs("buf%d" % i)  # buffers
             with m.FSM():
                 # indicate ready to accept data, and accept it if incoming
                 # BUT, if there is an opportunity to send on immediately
                 # to the ALU, take it early (combinatorial)
                 with m.State("ACCEPTING%d" % i):
-                    m.d.comb += self.p[i].o_ready.eq(1) # ready indicator
+                    m.d.comb += self.p[i].o_ready.eq(1)  # ready indicator
                     with m.If(self.p[i].i_valid):  # valid data incoming
                         m.d.sync += rsvd[i].eq(1)  # now reserved
                         # a unique opportunity: the ALU happens to be free
-                        with m.If(mid == i): # picker selected us
+                        with m.If(mid == i):  # picker selected us
                             with m.If(self.alu.p.o_ready):  # ALU can accept
-                                m.d.comb += self.alu.p.i_valid.eq(1) # transfer
+                                # transfer
+                                m.d.comb += self.alu.p.i_valid.eq(1)
                                 m.d.comb += nmoperator.eq(self.alu.p.i_data,
-                                                         self.p[i].i_data)
-                                m.d.sync += sent[i].eq(1) # now reserved
-                                m.next = "WAITOUT%d" % i # move to "wait output"
+                                                          self.p[i].i_data)
+                                m.d.sync += sent[i].eq(1)  # now reserved
+                                m.next = "WAITOUT%d" % i  # move to "wait output"
                         with m.Else():
                             # nope. ALU wasn't free. try next cycle(s)
                             m.d.sync += nmoperator.eq(i_buf, self.p[i].i_data)
-                            m.next = "ACCEPTED%d" % i # move to "accepted"
+                            m.next = "ACCEPTED%d" % i  # move to "accepted"
 
                 # now try to deliver to the ALU, but only if we are "picked"
                 with m.State("ACCEPTED%d" % i):
-                    with m.If(mid == i): # picker selected us
+                    with m.If(mid == i):  # picker selected us
                         with m.If(self.alu.p.o_ready):  # ALU can accept
-                            m.d.comb += self.alu.p.i_valid.eq(1) # transfer
+                            m.d.comb += self.alu.p.i_valid.eq(1)  # transfer
                             m.d.comb += nmoperator.eq(self.alu.p.i_data, i_buf)
-                            m.d.sync += sent[i].eq(1) # now reserved
-                            m.next = "WAITOUT%d" % i # move to "wait output"
+                            m.d.sync += sent[i].eq(1)  # now reserved
+                            m.next = "WAITOUT%d" % i  # move to "wait output"
 
                 # waiting for output to appear on the ALU, take a copy
                 # BUT, again, if there is an opportunity to send on
                 # immediately, take it (combinatorial)
                 with m.State("WAITOUT%d" % i):
-                    with m.If(o_muxid == i): # when ALU output matches our RS
+                    with m.If(o_muxid == i):  # when ALU output matches our RS
                         with m.If(self.alu.n.o_valid):  # ALU can accept
                             # second unique opportunity: the RS is ready
-                            with m.If(self.n[i].i_ready): # ready to receive
-                                m.d.comb += self.n[i].o_valid.eq(1) # valid
+                            with m.If(self.n[i].i_ready):  # ready to receive
+                                m.d.comb += self.n[i].o_valid.eq(1)  # valid
                                 m.d.comb += nmoperator.eq(self.n[i].o_data,
                                                           self.alu.n.o_data)
-                                m.d.sync += wait[i].eq(0) # clear waiting
-                                m.d.sync += sent[i].eq(0) # and sending
-                                m.d.sync += rsvd[i].eq(0) # and reserved
-                                m.next = "ACCEPTING%d" % i # back to "accepting"
+                                m.d.sync += wait[i].eq(0)  # clear waiting
+                                m.d.sync += sent[i].eq(0)  # and sending
+                                m.d.sync += rsvd[i].eq(0)  # and reserved
+                                m.next = "ACCEPTING%d" % i  # back to "accepting"
                             with m.Else():
                                 # nope. RS wasn't ready. try next cycles
-                                m.d.sync += wait[i].eq(1) # now waiting
+                                m.d.sync += wait[i].eq(1)  # now waiting
                                 m.d.sync += nmoperator.eq(o_buf,
                                                           self.alu.n.o_data)
-                                m.next = "SENDON%d" % i # move to "send data on"
+                                m.next = "SENDON%d" % i  # move to "send data on"
 
                 # waiting for "valid" indicator on RS output: deliver it
                 with m.State("SENDON%d" % i):
-                    with m.If(self.n[i].i_ready): # user is ready to receive
-                        m.d.comb += self.n[i].o_valid.eq(1) # indicate valid
+                    with m.If(self.n[i].i_ready):  # user is ready to receive
+                        m.d.comb += self.n[i].o_valid.eq(1)  # indicate valid
                         m.d.comb += nmoperator.eq(self.n[i].o_data, o_buf)
-                        m.d.sync += wait[i].eq(0) # clear waiting
-                        m.d.sync += sent[i].eq(0) # and sending
-                        m.d.sync += rsvd[i].eq(0) # and reserved
-                        m.next = "ACCEPTING%d" % i # and back to "accepting"
+                        m.d.sync += wait[i].eq(0)  # clear waiting
+                        m.d.sync += sent[i].eq(0)  # and sending
+                        m.d.sync += rsvd[i].eq(0)  # and reserved
+                        m.next = "ACCEPTING%d" % i  # and back to "accepting"
 
         return m
-