reorg and add in more TODO pointers for DivPipe*Stage blocks to be added
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 5 Jul 2019 13:24:49 +0000 (14:24 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 5 Jul 2019 13:24:49 +0000 (14:24 +0100)
src/ieee754/fpdiv/divstages.py
src/ieee754/fpdiv/pipeline.py

index c9813e45bfe366f2b268f82eb94c8b0b5927c838..b0c539f9805e94080c0713fd83f76fd6739101cc 100644 (file)
@@ -15,80 +15,191 @@ from ieee754.fpcommon.postcalc import FPAddStage1Data
 
 # TODO: write these
 from .div0 import FPDivStage0Mod
-from .div1 import FPDivStage1Mod
+from .div1 import FPDivStage1Mod # can be dropped entirely
+                                 # (replaced with DivPipeCalculateStage)
+                                 # note, yes, DivPipeCalculateStage *NOT*
+                                 # DivPipeCoreCalculateStage
 from .div2 import FPDivStage2Mod
 from .div0 import FPDivStage0Data
 
 
-class FPDivStages(FPState, SimpleHandshake):
+class FPDivStagesSetup(FPState, SimpleHandshake):
 
-    def __init__(self, width, pspec, n_stages, begin, end):
-        FPState.__init__(self, "align")
+    def __init__(self, width, pspec, n_stages):
+        FPState.__init__(self, "divsetup")
         self.width = width
         self.pspec = pspec
         self.n_stages = n_stages # number of combinatorial stages
-        self.begin = begin # "begin" mode
-        self.end = end # "end" mode
         SimpleHandshake.__init__(self, self) # pipeline is its own stage
         self.m1o = self.ospec()
 
     def ispec(self):
-        if self.begin: # TODO - this is for FPDivStage0Mod
-            # REQUIRED.  do NOT change.
-            return FPSCData(self.width, self.pspec, False) # from denorm
+        # REQUIRED.  do NOT change.
+        return FPSCData(self.width, self.pspec, False) # from denorm
+
+    def ospec(self):
+        # XXX TODO: replace with "intermediary" (DivPipeInterstageData)
+        return FPDivStage0Data(self.width, self.pspec) # DIV ospec (loop)
+
+    def setup(self, m, i):
+        """ links module to inputs and outputs.
+
+            note: this is a pure *combinatorial* module (StageChain).
+            therefore each sub-module must also be combinatorial
+            (and not do too much: in particular, n_stages must be
+            reduced slightly when either self.end=True or self.begin=True)
+        """
+
+        divstages = []
+
+        # Converts from FPSCData into DivPipeInputData
+        divstages.append(FPDivStage0Mod(self.width, self.pspec))
+
+        # does 1 "convert" (actual processing) from DivPipeInputData
+        # into "intermediate" output (DivPipeInterstageData)
+        # vvvvvvv
+        # FIXME divstages.append(DivPipeSetupStage(something))
+        # ^^^^^^^
+
+        # here is where the intermediary stages are added.
+        # n_stages is adjusted (in pipeline.py), reduced to take
+        # into account the extra processing that self.begin and self.end
+        # will add.
+        for count in range(self.n_stages): # number of combinatorial stages
+            # XXX: this can actually be entirely dropped...
+            divstages.append(FPDivStage1Mod(self.width, self.pspec))
+
+            # ... and replaced with this.
+            # vvvvvvv
+            #divstages.append(DivPipeCalculateStage(core_config, count))
+            # ^^^^^^^
+
+        chain = StageChain(divstages)
+        chain.setup(m, i)
 
-        if self.end: # TODO - this is for FPDivStage2Mod
-            # XXX TODO: replace with "intermediary" (DivPipeCoreInterstageData?)
-            return FPDivStage0Data(self.width, self.pspec) # DIV ispec (loop)
+        # output is from the last pipe stage
+        self.o = divstages[-1].o
+
+    def process(self, i):
+        return self.o
+
+    def action(self, m):
+        m.d.sync += self.m1o.eq(self.process(None))
+        m.next = "normalise_1"
+
+
+class FPDivStagesIntermediary(FPState, SimpleHandshake):
 
+    def __init__(self, width, pspec, n_stages):
+        FPState.__init__(self, "divintermediate")
+        self.width = width
+        self.pspec = pspec
+        self.n_stages = n_stages # number of combinatorial stages
+        self.begin = begin # "begin" mode
+        self.end = end # "end" mode
+        SimpleHandshake.__init__(self, self) # pipeline is its own stage
+        self.m1o = self.ospec()
+
+    def ispec(self):
         # TODO - this is for FPDivStage1Mod
-        # XXX TODO: replace with "intermediary" (DivPipeCoreInterstageData)
+        # XXX TODO: replace with "intermediary" (DivPipeInterstageData)
         return FPDivStage0Data(self.width, self.pspec) # DIV ispec (loop)
 
     def ospec(self):
-        if self.begin: # TODO - this is for FPDivStage0Mod
-            # XXX TODO: replace with "intermediary" (DivPipeCoreInterstageData)
-            return FPDivStage0Data(self.width, self.pspec) # DIV ospec (loop)
-
-        if self.end: # TODO - this is for FPDivStage2Mod
-            # REQUIRED.  do NOT change.
-            return FPAddStage1Data(self.width, self.pspec) # to post-norm
-
         # TODO - this is for FPDivStage1Mod
-        # XXX TODO: replace with "intermediary" (DivPipeCoreInterstageData)
+        # XXX TODO: replace with "intermediary" (DivPipeInterstageData)
         return FPDivStage0Data(self.width, self.pspec) # DIV ospec (loop)
 
     def setup(self, m, i):
-        """ links module to inputs and outputs
+        """ links module to inputs and outputs.
+
+            note: this is a pure *combinatorial* module (StageChain).
+            therefore each sub-module must also be combinatorial
+            (and not do too much)
         """
 
-        # start mode accepts data from the FP normalisation stage
-        # and does a bit of munging of the data.  it will be chained
-        # into the first DIV combinatorial block,
+        divstages = []
+
+        # here is where the intermediary stages are added.
+        # n_stages is adjusted (in pipeline.py), reduced to take
+        # into account the extra processing that self.begin and self.end
+        # will add.
+        for count in range(self.n_stages): # number of combinatorial stages
+            # XXX: this can actually be entirely dropped...
+            divstages.append(FPDivStage1Mod(self.width, self.pspec))
+
+            # ... and replaced with this.
+            # vvvvvvv
+            #divstages.append(DivPipeCalculateStage(core_config, count))
+            # ^^^^^^^
+
+        chain = StageChain(divstages)
+        chain.setup(m, i)
+
+        # output is from the last pipe stage
+        self.o = divstages[-1].o
+
+    def process(self, i):
+        return self.o
+
+    def action(self, m):
+        m.d.sync += self.m1o.eq(self.process(None))
+        m.next = "normalise_1"
 
-        # end mode takes the DIV pipeline/chain data and munges it
-        # into the format that the normalisation can accept.
 
-        # neither start nor end mode simply takes the exact same
-        # data in as out, this is where the Q/Rem comes in and Q/Rem goes out
+class FPDivStagesFinal(FPState, SimpleHandshake):
+
+    def __init__(self, width, pspec, n_stages):
+        FPState.__init__(self, "divfinal")
+        self.width = width
+        self.pspec = pspec
+        self.n_stages = n_stages # number of combinatorial stages
+        SimpleHandshake.__init__(self, self) # pipeline is its own stage
+        self.m1o = self.ospec()
+
+    def ispec(self):
+        # XXX TODO: replace with "intermediary" (DivPipeInterstageData?)
+        return FPDivStage0Data(self.width, self.pspec) # DIV ispec (loop)
+
+    def ospec(self):
+        # REQUIRED.  do NOT change.
+        return FPAddStage1Data(self.width, self.pspec) # to post-norm
+
+    def setup(self, m, i):
+        """ links module to inputs and outputs.
+
+            note: this is a pure *combinatorial* module (StageChain).
+            therefore each sub-module must also be combinatorial
+            (and not do too much)
+        """
+
+        # takes the DIV pipeline/chain data and munges it
+        # into the format that the normalisation can accept.
 
         divstages = []
 
-        if self.begin: # XXX check this
-            divstages.append(FPDivStage0Mod(self.width, self.pspec))
-            # XXX if FPDivStage0Mod is to be used to convert from
-            # FPSCData into DivPipeCoreInputData, rather than
-            # DivPipeCoreSetupStage conforming *to* FPSCData format,
-            # then DivPipeCoreSetupStage needs to be added here:
+        # here is where the intermediary stages are added.
+        # n_stages is adjusted (in pipeline.py), reduced to take
+        # into account the extra processing that self.begin and self.end
+        # will add.
+        for count in range(self.n_stages): # number of combinatorial stages
+            # XXX: this can actually be entirely dropped...
+            divstages.append(FPDivStage1Mod(self.width, self.pspec))
+
+            # ... and replaced with this.
             # vvvvvvv
-            # FIXME divstages.append(DivPipeCoreSetupStage(something))
+            #divstages.append(DivPipeCalculateStage(core_config, count))
             # ^^^^^^^
 
-        for count in range(self.n_stages): # number of combinatorial stages
-            divstages.append(FPDivStage1Mod(self.width, self.pspec))
+        # does the final conversion from intermediary to output data
+        # vvvvvvv
+        # FIXME divstages.append(DivPipeFinalStage(something))
+        # ^^^^^^^
 
-        if self.end: # XXX check this
-            divstages.append(FPDivStage2Mod(self.width, self.pspec))
+        # does conversion from DivPipeOutputData into
+        # FPAddStage1Data format (bad name, TODO, doesn't matter),
+        # so that post-normalisation and corrections can take over
+        divstages.append(FPDivStage2Mod(self.width, self.pspec))
 
         chain = StageChain(divstages)
         chain.setup(m, i)
index 824f6d274579c6d4aeb2008aa842a75758f5f602..1b58b091960ea90a92db5d4bfa14b0b3d4b21532 100644 (file)
@@ -4,38 +4,55 @@ Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
 
 Stack looks like this:
 
-scnorm   - FPDIVSpecialCasesDeNorm ispec FPADDBaseData  ospec FPSCData
+scnorm   - FPDIVSpecialCasesDeNorm ispec FPADDBaseData
+------                             ospec FPSCData
+
             StageChain: FPDIVSpecialCasesMod,
                         FPAddDeNormMod
 
-pipediv0 - FPDivStages(start=true) ispec FPSCData       ospec FPDivStage0Data
+pipediv0 - FPDivStagesSetup        ispec FPSCData
+--------                           ospec DivPipeCoreInterstageData
+
             StageChain: FPDivStage0Mod,
-                        FPDivStage1Mod,
+                        DivPipeCalculateStage,
                         ...
-                        FPDivStage1Mod
+                        DivPipeCalculateStage
 
-pipediv1 - FPDivStages()           ispec FPDivStage0Data ospec FPDivStage0Data
-            StageChain: FPDivStage1Mod,
+pipediv1 - FPDivStagesIntermediate ispec DivPipeCoreInterstageData
+--------                           ospec DivPipeCoreInterstageData
+
+            StageChain: DivPipeCalculateStage,
                         ...
-                        FPDivStage1Mod
+                        DivPipeCalculateStage
 ...
 ...
 
-pipediv5 - FPDivStages(end=true    ispec FPDivStage0Data ospec FPAddStage1Data
-            StageChain: FPDivStage1Mod,
+pipediv5 - FPDivStageFinal         ispec FPDivStage0Data
+--------                           ospec FPAddStage1Data
+
+            StageChain: DivPipeCalculateStage,
                         ...
-                        FPDivStage1Mod,
+                        DivPipeCalculateStage,
+                        DivPipeFinalStage,
                         FPDivStage2Mod
 
-normpack - FPNormToPack            ispec FPAddStage1Data ospec FPPackData
+normpack - FPNormToPack            ispec FPAddStage1Data
+--------                           ospec FPPackData
+
             StageChain: Norm1ModSingle,
                         RoundMod,
                         CorrectionsMod,
                         PackMod
 
-the number of combinatorial StageChains (n_combinatorial_stages) in
+the number of combinatorial StageChains (n_comb_stages) in
 FPDivStages is an argument arranged to get the length of the whole
 pipeline down to sane numbers.
+
+the reason for keeping the number of stages down is that for every
+pipeline clock delay, a corresponding ReservationStation is needed.
+if there are 24 pipeline stages, we need a whopping TWENTY FOUR
+RS's.  that's far too many.  6 is just about an acceptable number.
+even 8 is starting to get alarmingly high.
 """
 
 from nmigen import Module
@@ -49,35 +66,50 @@ from ieee754.fpcommon.denorm import FPSCData
 from ieee754.fpcommon.pack import FPPackData
 from ieee754.fpcommon.normtopack import FPNormToPack
 from .specialcases import FPDIVSpecialCasesDeNorm
-from .divstages import FPDivStages
+from .divstages import (FPDivStagesSetup,
+                        FPDivStagesIntermediate,
+                        FPDivStagesFinal)
 
 
 
 class FPDIVBasePipe(ControlBase):
     def __init__(self, width, pspec):
         ControlBase.__init__(self)
-        self.pipestart = FPDIVSpecialCasesDeNorm(width, pspec)
-        pipechain = []
-        n_stages = 6 # TODO
-        n_combinatorial_stages = 2 # TODO
-        for i in range(n_stages):
-            begin = i == 0 # needs to convert input from pipestart ospec
-            end = i == n_stages - 1 # needs to convert output to pipeend ispec
-            pipechain.append(FPDivStages(width, pspec,
-                                         n_combinatorial_stages,
-                                         begin, end))
-        self.pipechain = pipechain
-        self.pipeend = FPNormToPack(width, pspec)
-
-        self._eqs = self.connect([self.pipestart] + pipechain + [self.pipeend])
+        self.width = width
+        self.pspec = pspec
 
     def elaborate(self, platform):
         m = ControlBase.elaborate(self, platform)
-        m.submodules.scnorm = self.pipestart
-        for i, p in enumerate(self.pipechain):
+
+        pipestart = FPDIVSpecialCasesDeNorm(self.width, self.pspec)
+        pipechain = []
+        n_stages = 6      # TODO (depends on width)
+        n_comb_stages = 3 # TODO (depends on how many RS's we want)
+                          # to which the answer: "as few as possible"
+                          # is required.  too many ReservationStations
+                          # means "big problems".
+        for i in range(n_stages):
+            if i == 0: # needs to convert input from pipestart ospec
+                kls = FPDivStagesSetup
+                n_comb_stages -= 1 # reduce due to work done at start
+            elif i == n_stages - 1: # needs to convert output to pipeend ispec
+                kls = FPDivStagesFinal
+                n_comb_stages -= 1 # reduce due to work done at end?
+            else:
+                kls = FPDivStagesIntermediate
+            pipechain.append(kls(self.width, self.pspec, n_comb_stages))
+
+        pipeend = FPNormToPack(self.width, self.pspec)
+
+        # add submodules
+        m.submodules.scnorm = pipestart
+        for i, p in enumerate(pipechain):
             setattr(m.submodules, "pipediv%d" % i, p)
-        m.submodules.normpack = self.pipeend
-        m.d.comb += self._eqs
+        m.submodules.normpack = pipeend
+
+        # ControlBase.connect creates (returns) the "eqs" needed
+        m.d.comb += self.connect([pipestart] + pipechain + [pipeend])
+
         return m