From b9bb57fb96456389f07f468d41c744e904f3f54f Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Fri, 5 Jul 2019 14:24:49 +0100 Subject: [PATCH] reorg and add in more TODO pointers for DivPipe*Stage blocks to be added --- src/ieee754/fpdiv/divstages.py | 193 ++++++++++++++++++++++++++------- src/ieee754/fpdiv/pipeline.py | 94 ++++++++++------ 2 files changed, 215 insertions(+), 72 deletions(-) diff --git a/src/ieee754/fpdiv/divstages.py b/src/ieee754/fpdiv/divstages.py index c9813e45..b0c539f9 100644 --- a/src/ieee754/fpdiv/divstages.py +++ b/src/ieee754/fpdiv/divstages.py @@ -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) diff --git a/src/ieee754/fpdiv/pipeline.py b/src/ieee754/fpdiv/pipeline.py index 824f6d27..1b58b091 100644 --- a/src/ieee754/fpdiv/pipeline.py +++ b/src/ieee754/fpdiv/pipeline.py @@ -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 -- 2.30.2