big (single-purpose) update: move width arg into pspec
[ieee754fpu.git] / src / ieee754 / fpdiv / pipeline.py
1 """IEEE Floating Point Divider Pipeline
2
3 Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
4
5 Stack looks like this:
6
7 scnorm - FPDIVSpecialCasesDeNorm ispec FPADDBaseData
8 ------ ospec FPSCData
9
10 StageChain: FPDIVSpecialCasesMod,
11 FPAddDeNormMod
12
13 pipediv0 - FPDivStagesSetup ispec FPSCData
14 -------- ospec DivPipeCoreInterstageData
15
16 StageChain: FPDivStage0Mod,
17 DivPipeSetupStage,
18 DivPipeCalculateStage,
19 ...
20 DivPipeCalculateStage
21
22 pipediv1 - FPDivStagesIntermediate ispec DivPipeCoreInterstageData
23 -------- ospec DivPipeCoreInterstageData
24
25 StageChain: DivPipeCalculateStage,
26 ...
27 DivPipeCalculateStage
28 ...
29 ...
30
31 pipediv5 - FPDivStageFinal ispec FPDivStage0Data
32 -------- ospec FPAddStage1Data
33
34 StageChain: DivPipeCalculateStage,
35 ...
36 DivPipeCalculateStage,
37 DivPipeFinalStage,
38 FPDivStage2Mod
39
40 normpack - FPNormToPack ispec FPAddStage1Data
41 -------- ospec FPPackData
42
43 StageChain: Norm1ModSingle,
44 RoundMod,
45 CorrectionsMod,
46 PackMod
47
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.
51
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.
57 """
58
59 from nmigen import Module
60 from nmigen.cli import main, verilog
61
62 from nmutil.singlepipe import ControlBase
63 from nmutil.concurrentunit import ReservationStations, num_bits
64
65 from ieee754.fpcommon.getop import FPADDBaseData
66 from ieee754.fpcommon.denorm import FPSCData
67 from ieee754.fpcommon.pack import FPPackData
68 from ieee754.fpcommon.normtopack import FPNormToPack
69 from .specialcases import FPDIVSpecialCasesDeNorm
70 from .divstages import (FPDivStagesSetup,
71 FPDivStagesIntermediate,
72 FPDivStagesFinal)
73
74
75 class FPDIVBasePipe(ControlBase):
76 def __init__(self, pspec):
77 ControlBase.__init__(self)
78 self.pspec = pspec
79
80 def elaborate(self, platform):
81 m = ControlBase.elaborate(self, platform)
82
83 pipechain = []
84 n_stages = 6 # TODO (depends on width)
85 n_comb_stages = 3 # TODO (depends on how many RS's we want)
86 # to which the answer: "as few as possible"
87 # is required. too many ReservationStations
88 # means "big problems".
89
90 for i in range(n_stages):
91
92 # needs to convert input from pipestart ospec
93 if i == 0:
94 kls = FPDivStagesSetup
95 n_comb_stages -= 1 # reduce due to work done at start
96
97 # needs to convert output to pipeend ispec
98 elif i == n_stages - 1:
99 kls = FPDivStagesFinal
100 n_comb_stages -= 1 # FIXME - reduce due to work done at end?
101
102 # intermediary stage
103 else:
104 kls = FPDivStagesIntermediate
105
106 pipechain.append(kls(self.pspec, n_comb_stages))
107
108 # start and end: unpack/specialcases then normalisation/packing
109 pipestart = FPDIVSpecialCasesDeNorm(self.pspec)
110 pipeend = FPNormToPack(self.pspec)
111
112 # add submodules
113 m.submodules.scnorm = pipestart
114 for i, p in enumerate(pipechain):
115 setattr(m.submodules, "pipediv%d" % i, p)
116 m.submodules.normpack = pipeend
117
118 # ControlBase.connect creates the "eqs" needed to connect each pipe
119 m.d.comb += self.connect([pipestart] + pipechain + [pipeend])
120
121 return m
122
123
124 class FPDIVMuxInOut(ReservationStations):
125 """ Reservation-Station version of FPDIV pipeline.
126
127 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
128 * N-stage divider pipeline
129 * fan-out on outputs (an array of FPPackData: z,mid)
130
131 Fan-in and Fan-out are combinatorial.
132
133 :op_wid: - set this to the width of an operator which can
134 then be used to change the behaviour of the pipeline.
135 """
136 def __init__(self, width, num_rows, op_wid=0):
137 self.id_wid = num_bits(width)
138 self.pspec = {'width': width, 'id_wid': self.id_wid, 'op_wid': op_wid}
139 self.alu = FPDIVBasePipe(self.pspec)
140 ReservationStations.__init__(self, num_rows)
141
142 def i_specfn(self):
143 return FPADDBaseData(self.pspec)
144
145 def o_specfn(self):
146 return FPPackData(self.pspec)