-"""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:
-scnorm - FPDIVSpecialCasesDeNorm ispec FPADDBaseData
+scnorm - FPDIVSpecialCasesDeNorm ispec FPBaseData
------ ospec FPSCData
StageChain: FPDIVSpecialCasesMod,
pipediv0 - FPDivStagesSetup ispec FPSCData
-------- ospec DivPipeInterstageData
- StageChain: FPDivStage0Mod,
+ StageChain: FPDivPreFPAdjust,
DivPipeSetupStage,
DivPipeCalculateStage,
...
...
pipediv5 - FPDivStageFinal ispec FPDivStage0Data
--------- ospec FPAddStage1Data
+-------- ospec FPPostCalcData
StageChain: DivPipeCalculateStage,
...
DivPipeCalculateStage,
DivPipeFinalStage,
- FPDivStage2Mod
+ FPDivPostToFPFormat
-normpack - FPNormToPack ispec FPAddStage1Data
+normpack - FPNormToPack ispec FPPostCalcData
-------- ospec FPPackData
StageChain: Norm1ModSingle,
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.
even 8 is starting to get alarmingly high.
"""
-from nmigen import Module
-from nmigen.cli import main, verilog
-
from nmutil.singlepipe import ControlBase
from nmutil.concurrentunit import ReservationStations, num_bits
-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 ieee754.fpdiv.specialcases import FPDIVSpecialCasesDeNorm
from ieee754.fpdiv.divstages import (FPDivStagesSetup,
FPDivStagesFinal)
from ieee754.pipeline import PipelineSpec
from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreConfig
+from nmutil.dynamicpipe import MaskCancellableRedir
class FPDIVBasePipe(ControlBase):
def __init__(self, pspec):
self.pspec = pspec
- ControlBase.__init__(self)
+ ControlBase.__init__(self, maskwid=pspec.maskwid)
pipechain = []
- 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".
# get number of stages, set up loop.
n_stages = pspec.core_config.n_stages
- print ("n_stages", n_stages)
+ max_n_comb_stages = self.pspec.n_comb_stages
+ print("n_stages", n_stages)
stage_idx = 0
end = False
while not end:
+ n_comb_stages = max_n_comb_stages
# needs to convert input from pipestart ospec
if stage_idx == 0:
- kls = FPDivStagesSetup # does n_comb_stages-1 calcs as well
+ n_comb_stages -= 1
+ kls = FPDivStagesSetup # does n_comb_stages-1 calcs as well
# needs to convert output to pipeend ispec
elif stage_idx + n_comb_stages >= n_stages:
- kls = FPDivStagesFinal # does n_comb_stages-1 calcs as well
+ kls = FPDivStagesFinal # does n_comb_stages-1 calcs as well
end = True
n_comb_stages = n_stages - stage_idx
# intermediary stage
else:
- kls = FPDivStagesIntermediate # does n_comb_stages calcs
+ 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
+ stage_idx += n_comb_stages # increment so that each CalcStage
+ # gets a (correct) unique index
self.pipechain = pipechain
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.
- * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
+ * fan-in on inputs (an array of FPBaseData: a,b,mid)
* N-stage divider pipeline
* fan-out on outputs (an array of FPPackData: z,mid)
then be used to change the behaviour of the pipeline.
"""
- def __init__(self, width, num_rows, op_wid=1):
- self.id_wid = num_bits(width)
+ 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 HOWEVER...
+
+ # get the standard mantissa width, store in the pspec
fmt = FPFormat.standard(width)
- log2_radix = 2
-
- # ...5 extra bits on the mantissa: MSB is zero, MSB-1 is 1
- # then there is guard, round and sticky at the LSB end.
- # also: round up to nearest radix
- if width == 16:
- extra = 5
- elif width == 32:
- extra = 6
- elif width == 64:
- extra = 5
- fmt.m_width = roundup(fmt.m_width + extra, log2_radix)
- print ("width", fmt.m_width)
-
- cfg = DivPipeCoreConfig(fmt.m_width, fmt.fraction_width, log2_radix)
+ log2_radix = 3 # tested options so far: 1, 2 and 3.
+ n_comb_stages = 2 # 2 compute stages per pipeline stage
+ maskwid = 1 # SIMD width effectively
+ # 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.pipekls = MaskCancellableRedir
+ self.pspec.maskwid = maskwid * num_rows # RS gets just maskwid
self.pspec.fpformat = fmt
- self.pspec.log2_radix = log2_radix
+ 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)
# new_pspec.opkls = DivPipeCoreOperation
# self.alu = FPDIVBasePipe(new_pspec)
self.alu = FPDIVBasePipe(self.pspec)
- ReservationStations.__init__(self, num_rows)
-
- def i_specfn(self):
- return FPADDBaseData(self.pspec)
-
- def o_specfn(self):
- return FPPackData(self.pspec)
+ ReservationStations.__init__(self, num_rows, maskwid=maskwid)