convert to DynamicPipe (default class in PipelineSpec: SimpleHandshake)
[ieee754fpu.git] / src / ieee754 / fpdiv / divstages.py
index d62db0de038a69ebe34aeb8573740c4baa7bbe2d..81f9f3118f70963d54e8179300279a40995ef296 100644 (file)
@@ -7,81 +7,156 @@ Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
 from nmigen import Module
 from nmigen.cli import main, verilog
 
-from nmutil.singlepipe import (StageChain, SimpleHandshake)
+from nmutil.singlepipe import StageChain
 
-from ieee754.fpcommon.fpbase import FPState
+from ieee754.pipeline import DynamicPipe
 from ieee754.fpcommon.denorm import FPSCData
 from ieee754.fpcommon.postcalc import FPAddStage1Data
+from ieee754.div_rem_sqrt_rsqrt.div_pipe import (DivPipeInterstageData,
+                                                 DivPipeSetupStage,
+                                                 DivPipeCalculateStage,
+                                                 DivPipeFinalStage,
+                                                )
 
 # TODO: write these
 from .div0 import FPDivStage0Mod
-from .div1 import FPDivStage1Mod
 from .div2 import FPDivStage2Mod
-from .div0 import FPDivStage0Data
 
 
-class FPDivStages(FPState, SimpleHandshake):
+class FPDivStagesSetup(DynamicPipe):
 
-    def __init__(self, width, pspec, n_stages, begin, end):
-        FPState.__init__(self, "align")
-        self.width = width
+    def __init__(self, pspec, n_stages, stage_offs):
         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()
+        self.stage_offs = stage_offs # each CalcStage needs *absolute* idx
+        super().__init__(pspec)
 
     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.pspec, False) # from denorm
 
-        if self.end: # TODO - this is for FPDivStage2Mod
-            # XXX TODO: replace with "intermediary" (DivPipeCoreInterstageData?)
-            return FPDivStage0Data(self.width, self.pspec) # DIV ispec (loop)
+    def ospec(self):
+        return DivPipeInterstageData(self.pspec) # DIV ospec (loop)
 
-        # TODO - this is for FPDivStage1Mod
-        # XXX TODO: replace with "intermediary" (DivPipeCoreInterstageData)
-        return FPDivStage0Data(self.width, self.pspec) # DIV ispec (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
+        """
+
+        divstages = []
+
+        # Converts from FPSCData into DivPipeInputData
+        divstages.append(FPDivStage0Mod(self.pspec))
+
+        # does 1 "convert" (actual processing) from DivPipeInputData
+        # into "intermediate" output (DivPipeInterstageData)
+        divstages.append(DivPipeSetupStage(self.pspec))
+
+        # here is where the intermediary stages are added.
+        # n_stages is adjusted (by pipeline.py), reduced to take
+        # into account extra processing that FPDivStage0Mod and DivPipeSetup
+        # might add.
+        for count in range(self.n_stages): # number of combinatorial stages
+            idx = count + self.stage_offs
+            divstages.append(DivPipeCalculateStage(self.pspec, idx))
+
+        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 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
+class FPDivStagesIntermediate(DynamicPipe):
 
+    def __init__(self, pspec, n_stages, stage_offs):
+        self.pspec = pspec
+        self.n_stages = n_stages # number of combinatorial stages
+        self.stage_offs = stage_offs # each CalcStage needs *absolute* idx
+        super().__init__(pspec)
+
+    def ispec(self):
         # TODO - this is for FPDivStage1Mod
-        # XXX TODO: replace with "intermediary" (DivPipeCoreInterstageData)
-        return FPDivStage0Data(self.width, self.pspec) # DIV ospec (loop)
+        return DivPipeInterstageData(self.pspec) # DIV ispec (loop)
+
+    def ospec(self):
+        # TODO - this is for FPDivStage1Mod
+        return DivPipeInterstageData(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
         """
 
-        # 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
+            idx = count + self.stage_offs
+            divstages.append(DivPipeCalculateStage(self.pspec, idx))
 
-        # end mode takes the DIV pipeline/chain data and munges it
-        # into the format that the normalisation can accept.
+        chain = StageChain(divstages)
+        chain.setup(m, i)
 
-        # 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
+        # output is from the last pipe stage
+        self.o = divstages[-1].o
 
-        divstages = []
+    def process(self, i):
+        return self.o
+
+
+class FPDivStagesFinal(DynamicPipe):
+
+    def __init__(self, pspec, n_stages, stage_offs):
+        self.pspec = pspec
+        self.n_stages = n_stages # number of combinatorial stages
+        self.stage_offs = stage_offs # each CalcStage needs *absolute* idx
+        super().__init__(pspec)
 
-        if self.begin: # XXX check this
-            divstages.append(FPDivStage0Mod(self.width, self.pspec))
+    def ispec(self):
+        return DivPipeInterstageData(self.pspec) # DIV ispec (loop)
+
+    def ospec(self):
+        # REQUIRED.  do NOT change.
+        return FPAddStage1Data(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
+        """
 
+        # takes the DIV pipeline/chain data and munges it
+        # into the format that the normalisation can accept.
+
+        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
-            divstages.append(FPDivStage1Mod(self.width, self.pspec))
+            idx = count + self.stage_offs
+            divstages.append(DivPipeCalculateStage(self.pspec, idx))
+
+        # does the final conversion from intermediary to output data
+        divstages.append(DivPipeFinalStage(self.pspec))
 
-        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.pspec))
 
         chain = StageChain(divstages)
         chain.setup(m, i)
@@ -91,9 +166,3 @@ class FPDivStages(FPState, SimpleHandshake):
 
     def process(self, i):
         return self.o
-
-    def action(self, m):
-        m.d.sync += self.m1o.eq(self.process(None))
-        m.next = "normalise_1"
-
-