1 """IEEE Floating Point Divider Pipeline
3 Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
7 scnorm - FPDIVSpecialCasesDeNorm ispec FPADDBaseData
10 StageChain: FPDIVSpecialCasesMod,
13 pipediv0 - FPDivStagesSetup ispec FPSCData
14 -------- ospec DivPipeInterstageData
16 StageChain: FPDivStage0Mod,
18 DivPipeCalculateStage,
22 pipediv1 - FPDivStagesIntermediate ispec DivPipeInterstageData
23 -------- ospec DivPipeInterstageData
25 StageChain: DivPipeCalculateStage,
31 pipediv5 - FPDivStageFinal ispec FPDivStage0Data
32 -------- ospec FPAddStage1Data
34 StageChain: DivPipeCalculateStage,
36 DivPipeCalculateStage,
40 normpack - FPNormToPack ispec FPAddStage1Data
41 -------- ospec FPPackData
43 StageChain: Norm1ModSingle,
48 the number of combinatorial StageChains (n_comb_stages) in
49 FPDivStages is an argument arranged to get the length of the whole
50 pipeline down to sane numbers.
52 the reason for keeping the number of stages down is that for every
53 pipeline clock delay, a corresponding ReservationStation is needed.
54 if there are 24 pipeline stages, we need a whopping TWENTY FOUR
55 RS's. that's far too many. 6 is just about an acceptable number.
56 even 8 is starting to get alarmingly high.
59 from nmigen
import Module
60 from nmigen
.cli
import main
, verilog
62 from nmutil
.singlepipe
import ControlBase
63 from nmutil
.concurrentunit
import ReservationStations
, num_bits
65 from ieee754
.fpcommon
.getop
import FPADDBaseData
66 from ieee754
.fpcommon
.denorm
import FPSCData
67 from ieee754
.fpcommon
.fpbase
import FPFormat
68 from ieee754
.fpcommon
.pack
import FPPackData
69 from ieee754
.fpcommon
.normtopack
import FPNormToPack
70 from ieee754
.fpdiv
.specialcases
import FPDIVSpecialCasesDeNorm
71 from ieee754
.fpdiv
.divstages
import (FPDivStagesSetup
,
72 FPDivStagesIntermediate
,
74 from ieee754
.pipeline
import PipelineSpec
75 from ieee754
.div_rem_sqrt_rsqrt
.core
import DivPipeCoreConfig
78 class FPDIVBasePipe(ControlBase
):
79 def __init__(self
, pspec
):
81 ControlBase
.__init
__(self
)
84 # to which the answer: "as few as possible"
85 # is required. too many ReservationStations
86 # means "big problems".
88 # get number of stages, set up loop.
89 n_stages
= pspec
.core_config
.n_stages
90 max_n_comb_stages
= self
.pspec
.n_comb_stages
91 print("n_stages", n_stages
)
97 n_comb_stages
= max_n_comb_stages
98 # needs to convert input from pipestart ospec
101 kls
= FPDivStagesSetup
# does n_comb_stages-1 calcs as well
103 # needs to convert output to pipeend ispec
104 elif stage_idx
+ n_comb_stages
>= n_stages
:
105 kls
= FPDivStagesFinal
# does n_comb_stages-1 calcs as well
107 n_comb_stages
= n_stages
- stage_idx
111 kls
= FPDivStagesIntermediate
# does n_comb_stages calcs
113 # create (in each pipe) a StageChain n_comb_stages in length
114 pipechain
.append(kls(self
.pspec
, n_comb_stages
, stage_idx
))
115 stage_idx
+= n_comb_stages
# increment so that each CalcStage
116 # gets a (correct) unique index
118 self
.pipechain
= pipechain
120 # start and end: unpack/specialcases then normalisation/packing
121 self
.pipestart
= pipestart
= FPDIVSpecialCasesDeNorm(self
.pspec
)
122 self
.pipeend
= pipeend
= FPNormToPack(self
.pspec
)
124 self
._eqs
= self
.connect([pipestart
] + pipechain
+ [pipeend
])
126 def elaborate(self
, platform
):
127 m
= ControlBase
.elaborate(self
, platform
)
130 m
.submodules
.scnorm
= self
.pipestart
131 for i
, p
in enumerate(self
.pipechain
):
132 setattr(m
.submodules
, "pipediv%d" % i
, p
)
133 m
.submodules
.normpack
= self
.pipeend
135 # ControlBase.connect creates the "eqs" needed to connect each pipe
136 m
.d
.comb
+= self
._eqs
142 return x
if x
% mod
== 0 else x
+ mod
- x
% mod
145 class FPDIVMuxInOut(ReservationStations
):
146 """ Reservation-Station version of FPDIV pipeline.
148 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
149 * N-stage divider pipeline
150 * fan-out on outputs (an array of FPPackData: z,mid)
152 Fan-in and Fan-out are combinatorial.
154 :op_wid: - set this to the width of an operator which can
155 then be used to change the behaviour of the pipeline.
158 def __init__(self
, width
, num_rows
, op_wid
=2):
159 self
.id_wid
= num_bits(num_rows
)
160 self
.pspec
= PipelineSpec(width
, self
.id_wid
, op_wid
)
161 # get the standard mantissa width, store in the pspec
162 fmt
= FPFormat
.standard(width
)
163 log2_radix
= 3 # tested options so far: 1, 2 and 3.
165 fraction_width
= fmt
.fraction_width
167 # extra bits needed: guard + round
170 # rounding width to a multiple of log2_radix is not needed,
171 # DivPipeCoreCalculateStage just internally reduces log2_radix on
173 cfg
= DivPipeCoreConfig(fmt
.width
, fraction_width
, log2_radix
)
175 n_comb_stages
= (cfg
.n_stages
+ 1) // 2 # 2 compute steps per stage
177 self
.pspec
.fpformat
= fmt
178 self
.pspec
.n_comb_stages
= n_comb_stages
179 self
.pspec
.core_config
= cfg
181 # XXX TODO - a class (or function?) that takes the pspec (right here)
182 # and creates... "something". that "something" MUST have an eq function
183 # new_pspec = deepcopy(self.pspec)
184 # new_pspec.opkls = DivPipeCoreOperation
185 # self.alu = FPDIVBasePipe(new_pspec)
186 self
.alu
= FPDIVBasePipe(self
.pspec
)
187 ReservationStations
.__init
__(self
, num_rows
)
190 return FPADDBaseData(self
.pspec
)
193 return FPPackData(self
.pspec
)