-"""IEEE Floating Point Divider Pipeline
+"""IEEE754 Floating Point Divider Pipeline
-Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
+Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+Copyright (C) 2019 Jacob Lifshay
+
+Relevant bugreports:
+* http://bugs.libre-riscv.org/show_bug.cgi?id=99
+* http://bugs.libre-riscv.org/show_bug.cgi?id=43
+* http://bugs.libre-riscv.org/show_bug.cgi?id=44
Stack looks like this:
FPAddDeNormMod
pipediv0 - FPDivStagesSetup ispec FPSCData
--------- ospec DivPipeCoreInterstageData
+-------- ospec DivPipeInterstageData
StageChain: FPDivStage0Mod,
DivPipeSetupStage,
...
DivPipeCalculateStage
-pipediv1 - FPDivStagesIntermediate ispec DivPipeCoreInterstageData
--------- ospec DivPipeCoreInterstageData
+pipediv1 - FPDivStagesIntermediate ispec DivPipeInterstageData
+-------- ospec DivPipeInterstageData
StageChain: DivPipeCalculateStage,
...
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.
+pipeline down to sane numbers. it specifies the number of "blocks"
+that will be combinatorially chained together.
the reason for keeping the number of stages down is that for every
pipeline clock delay, a corresponding ReservationStation is needed.
from ieee754.fpcommon.getop import FPADDBaseData
from ieee754.fpcommon.denorm import FPSCData
+from ieee754.fpcommon.fpbase import FPFormat
from ieee754.fpcommon.pack import FPPackData
from ieee754.fpcommon.normtopack import FPNormToPack
-from .specialcases import FPDIVSpecialCasesDeNorm
-from .divstages import (FPDivStagesSetup,
- FPDivStagesIntermediate,
- FPDivStagesFinal)
+from ieee754.fpdiv.specialcases import FPDIVSpecialCasesDeNorm
+from ieee754.fpdiv.divstages import (FPDivStagesSetup,
+ FPDivStagesIntermediate,
+ FPDivStagesFinal)
+from ieee754.pipeline import PipelineSpec
+from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreConfig
class FPDIVBasePipe(ControlBase):
def __init__(self, pspec):
- ControlBase.__init__(self)
self.pspec = pspec
-
- def elaborate(self, platform):
- m = ControlBase.elaborate(self, platform)
+ ControlBase.__init__(self)
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".
+ # to which the answer: "as few as possible"
+ # is required. too many ReservationStations
+ # means "big problems".
+
+ # get number of stages, set up loop.
+ n_stages = pspec.core_config.n_stages
+ max_n_comb_stages = self.pspec.n_comb_stages
+ print("n_stages", n_stages)
+ stage_idx = 0
- for i in range(n_stages):
+ end = False
+ while not end:
+ n_comb_stages = max_n_comb_stages
# needs to convert input from pipestart ospec
- if i == 0:
- kls = FPDivStagesSetup
- n_comb_stages -= 1 # reduce due to work done at start
+ if stage_idx == 0:
+ n_comb_stages -= 1
+ kls = FPDivStagesSetup # does n_comb_stages-1 calcs as well
# needs to convert output to pipeend ispec
- elif i == n_stages - 1:
- kls = FPDivStagesFinal
- n_comb_stages -= 1 # FIXME - reduce due to work done at end?
+ elif stage_idx + n_comb_stages >= n_stages:
+ kls = FPDivStagesFinal # does n_comb_stages-1 calcs as well
+ end = True
+ n_comb_stages = n_stages - stage_idx
# intermediary stage
else:
- kls = FPDivStagesIntermediate
+ kls = FPDivStagesIntermediate # does n_comb_stages calcs
+
+ # create (in each pipe) a StageChain n_comb_stages in length
+ pipechain.append(kls(self.pspec, n_comb_stages, stage_idx))
+ stage_idx += n_comb_stages # increment so that each CalcStage
+ # gets a (correct) unique index
- pipechain.append(kls(self.pspec, n_comb_stages))
+ self.pipechain = pipechain
# start and end: unpack/specialcases then normalisation/packing
- pipestart = FPDIVSpecialCasesDeNorm(self.pspec)
- pipeend = FPNormToPack(self.pspec)
+ self.pipestart = pipestart = FPDIVSpecialCasesDeNorm(self.pspec)
+ self.pipeend = pipeend = FPNormToPack(self.pspec)
+
+ self._eqs = self.connect([pipestart] + pipechain + [pipeend])
+
+ def elaborate(self, platform):
+ m = ControlBase.elaborate(self, platform)
# add submodules
- m.submodules.scnorm = pipestart
- for i, p in enumerate(pipechain):
+ m.submodules.scnorm = self.pipestart
+ for i, p in enumerate(self.pipechain):
setattr(m.submodules, "pipediv%d" % i, p)
- m.submodules.normpack = pipeend
+ m.submodules.normpack = self.pipeend
# ControlBase.connect creates the "eqs" needed to connect each pipe
- m.d.comb += self.connect([pipestart] + pipechain + [pipeend])
+ m.d.comb += self._eqs
return m
+def roundup(x, mod):
+ return x if x % mod == 0 else x + mod - x % mod
+
+
class FPDIVMuxInOut(ReservationStations):
""" Reservation-Station version of FPDIV pipeline.
:op_wid: - set this to the width of an operator which can
then be used to change the behaviour of the pipeline.
"""
- def __init__(self, width, num_rows, op_wid=0):
- self.id_wid = num_bits(width)
- self.pspec = {)
- self.pspec['width'] = width
- self.pspec['id_wid'] = self.id_wid
- self.pspec['op_wid'] = op_wid
+
+ def __init__(self, width, num_rows, op_wid=2):
+ self.id_wid = num_bits(num_rows)
+ self.pspec = PipelineSpec(width, self.id_wid, op_wid)
+
+ # get the standard mantissa width, store in the pspec
+ fmt = FPFormat.standard(width)
+ log2_radix = 3 # tested options so far: 1, 2 and 3.
+ n_comb_stages = 2 # 2 compute stages per pipeline stage
+
+ # extra bits needed: guard + round (sticky comes from remainer.bool())
+ fraction_width = fmt.fraction_width
+ fraction_width += 2
+
+ # rounding width to a multiple of log2_radix is not needed,
+ # DivPipeCoreCalculateStage just internally reduces log2_radix on
+ # the last stage
+ cfg = DivPipeCoreConfig(fmt.width, fraction_width, log2_radix)
+
+ self.pspec.fpformat = fmt
+ self.pspec.n_comb_stages = n_comb_stages
+ self.pspec.core_config = cfg
+
# XXX TODO - a class (or function?) that takes the pspec (right here)
# and creates... "something". that "something" MUST have an eq function
- # self.pspec['opkls'] = DivPipeCoreOperation
+ # new_pspec = deepcopy(self.pspec)
+ # new_pspec.opkls = DivPipeCoreOperation
+ # self.alu = FPDIVBasePipe(new_pspec)
self.alu = FPDIVBasePipe(self.pspec)
ReservationStations.__init__(self, num_rows)