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 nmigen
import Module
67 from nmigen
.cli
import main
, verilog
69 from nmutil
.singlepipe
import ControlBase
70 from nmutil
.concurrentunit
import ReservationStations
, num_bits
72 from ieee754
.fpcommon
.getop
import FPADDBaseData
73 from ieee754
.fpcommon
.denorm
import FPSCData
74 from ieee754
.fpcommon
.fpbase
import FPFormat
75 from ieee754
.fpcommon
.pack
import FPPackData
76 from ieee754
.fpcommon
.normtopack
import FPNormToPack
77 from ieee754
.fpdiv
.specialcases
import FPDIVSpecialCasesDeNorm
78 from ieee754
.fpdiv
.divstages
import (FPDivStagesSetup
,
79 FPDivStagesIntermediate
,
81 from ieee754
.pipeline
import PipelineSpec
82 from ieee754
.div_rem_sqrt_rsqrt
.core
import DivPipeCoreConfig
85 class FPDIVBasePipe(ControlBase
):
86 def __init__(self
, pspec
):
88 ControlBase
.__init
__(self
)
91 # to which the answer: "as few as possible"
92 # is required. too many ReservationStations
93 # means "big problems".
95 # get number of stages, set up loop.
96 n_stages
= pspec
.core_config
.n_stages
97 max_n_comb_stages
= self
.pspec
.n_comb_stages
98 print("n_stages", n_stages
)
104 n_comb_stages
= max_n_comb_stages
105 # needs to convert input from pipestart ospec
108 kls
= FPDivStagesSetup
# does n_comb_stages-1 calcs as well
110 # needs to convert output to pipeend ispec
111 elif stage_idx
+ n_comb_stages
>= n_stages
:
112 kls
= FPDivStagesFinal
# does n_comb_stages-1 calcs as well
114 n_comb_stages
= n_stages
- stage_idx
118 kls
= FPDivStagesIntermediate
# does n_comb_stages calcs
120 # create (in each pipe) a StageChain n_comb_stages in length
121 pipechain
.append(kls(self
.pspec
, n_comb_stages
, stage_idx
))
122 stage_idx
+= n_comb_stages
# increment so that each CalcStage
123 # gets a (correct) unique index
125 self
.pipechain
= pipechain
127 # start and end: unpack/specialcases then normalisation/packing
128 self
.pipestart
= pipestart
= FPDIVSpecialCasesDeNorm(self
.pspec
)
129 self
.pipeend
= pipeend
= FPNormToPack(self
.pspec
)
131 self
._eqs
= self
.connect([pipestart
] + pipechain
+ [pipeend
])
133 def elaborate(self
, platform
):
134 m
= ControlBase
.elaborate(self
, platform
)
137 m
.submodules
.scnorm
= self
.pipestart
138 for i
, p
in enumerate(self
.pipechain
):
139 setattr(m
.submodules
, "pipediv%d" % i
, p
)
140 m
.submodules
.normpack
= self
.pipeend
142 # ControlBase.connect creates the "eqs" needed to connect each pipe
143 m
.d
.comb
+= self
._eqs
149 return x
if x
% mod
== 0 else x
+ mod
- x
% mod
152 class FPDIVMuxInOut(ReservationStations
):
153 """ Reservation-Station version of FPDIV pipeline.
155 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
156 * N-stage divider pipeline
157 * fan-out on outputs (an array of FPPackData: z,mid)
159 Fan-in and Fan-out are combinatorial.
161 :op_wid: - set this to the width of an operator which can
162 then be used to change the behaviour of the pipeline.
165 def __init__(self
, width
, num_rows
, op_wid
=2):
166 self
.id_wid
= num_bits(num_rows
)
167 self
.pspec
= PipelineSpec(width
, self
.id_wid
, op_wid
)
169 # get the standard mantissa width, store in the pspec
170 fmt
= FPFormat
.standard(width
)
171 log2_radix
= 3 # tested options so far: 1, 2 and 3.
172 n_comb_stages
= 2 # 2 compute stages per pipeline stage
174 # extra bits needed: guard + round (sticky comes from remainer.bool())
175 fraction_width
= fmt
.fraction_width
178 # rounding width to a multiple of log2_radix is not needed,
179 # DivPipeCoreCalculateStage just internally reduces log2_radix on
181 cfg
= DivPipeCoreConfig(fmt
.width
, fraction_width
, log2_radix
)
183 self
.pspec
.fpformat
= fmt
184 self
.pspec
.n_comb_stages
= n_comb_stages
185 self
.pspec
.core_config
= cfg
187 # XXX TODO - a class (or function?) that takes the pspec (right here)
188 # and creates... "something". that "something" MUST have an eq function
189 # new_pspec = deepcopy(self.pspec)
190 # new_pspec.opkls = DivPipeCoreOperation
191 # self.alu = FPDIVBasePipe(new_pspec)
192 self
.alu
= FPDIVBasePipe(self
.pspec
)
193 ReservationStations
.__init
__(self
, num_rows
)
196 return FPADDBaseData(self
.pspec
)
199 return FPPackData(self
.pspec
)