1 """IEEE754 Floating Point Divider Pipeline
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 Copyright (C) 2019 Jacob Lifshay
7 * http://bugs.libre-riscv.org/show_bug.cgi?id=99
8 * http://bugs.libre-riscv.org/show_bug.cgi?id=43
9 * http://bugs.libre-riscv.org/show_bug.cgi?id=44
11 Stack looks like this:
13 scnorm - FPDIVSpecialCasesDeNorm ispec FPADDBaseData
16 StageChain: FPDIVSpecialCasesMod,
19 pipediv0 - FPDivStagesSetup ispec FPSCData
20 -------- ospec DivPipeInterstageData
22 StageChain: FPDivStage0Mod,
24 DivPipeCalculateStage,
28 pipediv1 - FPDivStagesIntermediate ispec DivPipeInterstageData
29 -------- ospec DivPipeInterstageData
31 StageChain: DivPipeCalculateStage,
37 pipediv5 - FPDivStageFinal ispec FPDivStage0Data
38 -------- ospec FPPostCalcData
40 StageChain: DivPipeCalculateStage,
42 DivPipeCalculateStage,
46 normpack - FPNormToPack ispec FPPostCalcData
47 -------- ospec FPPackData
49 StageChain: Norm1ModSingle,
54 the number of combinatorial StageChains (n_comb_stages) in
55 FPDivStages is an argument arranged to get the length of the whole
56 pipeline down to sane numbers. it specifies the number of "blocks"
57 that will be combinatorially chained together.
59 the reason for keeping the number of stages down is that for every
60 pipeline clock delay, a corresponding ReservationStation is needed.
61 if there are 24 pipeline stages, we need a whopping TWENTY FOUR
62 RS's. that's far too many. 6 is just about an acceptable number.
63 even 8 is starting to get alarmingly high.
66 from nmutil
.singlepipe
import ControlBase
67 from nmutil
.concurrentunit
import ReservationStations
, num_bits
69 from ieee754
.fpcommon
.getop
import FPADDBaseData
70 from ieee754
.fpcommon
.denorm
import FPSCData
71 from ieee754
.fpcommon
.fpbase
import FPFormat
72 from ieee754
.fpcommon
.pack
import FPPackData
73 from ieee754
.fpcommon
.normtopack
import FPNormToPack
74 from ieee754
.fpdiv
.specialcases
import FPDIVSpecialCasesDeNorm
75 from ieee754
.fpdiv
.divstages
import (FPDivStagesSetup
,
76 FPDivStagesIntermediate
,
78 from ieee754
.pipeline
import PipelineSpec
79 from ieee754
.div_rem_sqrt_rsqrt
.core
import DivPipeCoreConfig
82 class FPDIVBasePipe(ControlBase
):
83 def __init__(self
, pspec
):
85 ControlBase
.__init
__(self
)
88 # to which the answer: "as few as possible"
89 # is required. too many ReservationStations
90 # means "big problems".
92 # get number of stages, set up loop.
93 n_stages
= pspec
.core_config
.n_stages
94 max_n_comb_stages
= self
.pspec
.n_comb_stages
95 print("n_stages", n_stages
)
101 n_comb_stages
= max_n_comb_stages
102 # needs to convert input from pipestart ospec
105 kls
= FPDivStagesSetup
# does n_comb_stages-1 calcs as well
107 # needs to convert output to pipeend ispec
108 elif stage_idx
+ n_comb_stages
>= n_stages
:
109 kls
= FPDivStagesFinal
# does n_comb_stages-1 calcs as well
111 n_comb_stages
= n_stages
- stage_idx
115 kls
= FPDivStagesIntermediate
# does n_comb_stages calcs
117 # create (in each pipe) a StageChain n_comb_stages in length
118 pipechain
.append(kls(self
.pspec
, n_comb_stages
, stage_idx
))
119 stage_idx
+= n_comb_stages
# increment so that each CalcStage
120 # gets a (correct) unique index
122 self
.pipechain
= pipechain
124 # start and end: unpack/specialcases then normalisation/packing
125 self
.pipestart
= pipestart
= FPDIVSpecialCasesDeNorm(self
.pspec
)
126 self
.pipeend
= pipeend
= FPNormToPack(self
.pspec
)
128 self
._eqs
= self
.connect([pipestart
] + pipechain
+ [pipeend
])
130 def elaborate(self
, platform
):
131 m
= ControlBase
.elaborate(self
, platform
)
134 m
.submodules
.scnorm
= self
.pipestart
135 for i
, p
in enumerate(self
.pipechain
):
136 setattr(m
.submodules
, "pipediv%d" % i
, p
)
137 m
.submodules
.normpack
= self
.pipeend
139 # ControlBase.connect creates the "eqs" needed to connect each pipe
140 m
.d
.comb
+= self
._eqs
146 return x
if x
% mod
== 0 else x
+ mod
- x
% mod
149 class FPDIVMuxInOut(ReservationStations
):
150 """ Reservation-Station version of FPDIV pipeline.
152 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
153 * N-stage divider pipeline
154 * fan-out on outputs (an array of FPPackData: z,mid)
156 Fan-in and Fan-out are combinatorial.
158 :op_wid: - set this to the width of an operator which can
159 then be used to change the behaviour of the pipeline.
162 def __init__(self
, width
, num_rows
, op_wid
=2):
163 self
.id_wid
= num_bits(num_rows
)
164 self
.pspec
= PipelineSpec(width
, self
.id_wid
, op_wid
)
166 # get the standard mantissa width, store in the pspec
167 fmt
= FPFormat
.standard(width
)
168 log2_radix
= 3 # tested options so far: 1, 2 and 3.
169 n_comb_stages
= 2 # 2 compute stages per pipeline stage
171 # extra bits needed: guard + round (sticky comes from remainer.bool())
172 fraction_width
= fmt
.fraction_width
175 # rounding width to a multiple of log2_radix is not needed,
176 # DivPipeCoreCalculateStage just internally reduces log2_radix on
178 cfg
= DivPipeCoreConfig(fmt
.width
, fraction_width
, log2_radix
)
180 self
.pspec
.fpformat
= fmt
181 self
.pspec
.n_comb_stages
= n_comb_stages
182 self
.pspec
.core_config
= cfg
184 # XXX TODO - a class (or function?) that takes the pspec (right here)
185 # and creates... "something". that "something" MUST have an eq function
186 # new_pspec = deepcopy(self.pspec)
187 # new_pspec.opkls = DivPipeCoreOperation
188 # self.alu = FPDIVBasePipe(new_pspec)
189 self
.alu
= FPDIVBasePipe(self
.pspec
)
190 ReservationStations
.__init
__(self
, num_rows
)
193 return FPADDBaseData(self
.pspec
)
196 return FPPackData(self
.pspec
)