# 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)
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
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