reorg and add in more TODO pointers for DivPipe*Stage blocks to be added
[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 DivPipeCalculateStage,
18 ...
19 DivPipeCalculateStage
20
21 pipediv1 - FPDivStagesIntermediate ispec DivPipeCoreInterstageData
22 -------- ospec DivPipeCoreInterstageData
23
24 StageChain: DivPipeCalculateStage,
25 ...
26 DivPipeCalculateStage
27 ...
28 ...
29
30 pipediv5 - FPDivStageFinal ispec FPDivStage0Data
31 -------- ospec FPAddStage1Data
32
33 StageChain: DivPipeCalculateStage,
34 ...
35 DivPipeCalculateStage,
36 DivPipeFinalStage,
37 FPDivStage2Mod
38
39 normpack - FPNormToPack ispec FPAddStage1Data
40 -------- ospec FPPackData
41
42 StageChain: Norm1ModSingle,
43 RoundMod,
44 CorrectionsMod,
45 PackMod
46
47 the number of combinatorial StageChains (n_comb_stages) in
48 FPDivStages is an argument arranged to get the length of the whole
49 pipeline down to sane numbers.
50
51 the reason for keeping the number of stages down is that for every
52 pipeline clock delay, a corresponding ReservationStation is needed.
53 if there are 24 pipeline stages, we need a whopping TWENTY FOUR
54 RS's. that's far too many. 6 is just about an acceptable number.
55 even 8 is starting to get alarmingly high.
56 """
57
58 from nmigen import Module
59 from nmigen.cli import main, verilog
60
61 from nmutil.singlepipe import ControlBase
62 from nmutil.concurrentunit import ReservationStations, num_bits
63
64 from ieee754.fpcommon.getop import FPADDBaseData
65 from ieee754.fpcommon.denorm import FPSCData
66 from ieee754.fpcommon.pack import FPPackData
67 from ieee754.fpcommon.normtopack import FPNormToPack
68 from .specialcases import FPDIVSpecialCasesDeNorm
69 from .divstages import (FPDivStagesSetup,
70 FPDivStagesIntermediate,
71 FPDivStagesFinal)
72
73
74
75 class FPDIVBasePipe(ControlBase):
76 def __init__(self, width, pspec):
77 ControlBase.__init__(self)
78 self.width = width
79 self.pspec = pspec
80
81 def elaborate(self, platform):
82 m = ControlBase.elaborate(self, platform)
83
84 pipestart = FPDIVSpecialCasesDeNorm(self.width, self.pspec)
85 pipechain = []
86 n_stages = 6 # TODO (depends on width)
87 n_comb_stages = 3 # TODO (depends on how many RS's we want)
88 # to which the answer: "as few as possible"
89 # is required. too many ReservationStations
90 # means "big problems".
91 for i in range(n_stages):
92 if i == 0: # needs to convert input from pipestart ospec
93 kls = FPDivStagesSetup
94 n_comb_stages -= 1 # reduce due to work done at start
95 elif i == n_stages - 1: # needs to convert output to pipeend ispec
96 kls = FPDivStagesFinal
97 n_comb_stages -= 1 # reduce due to work done at end?
98 else:
99 kls = FPDivStagesIntermediate
100 pipechain.append(kls(self.width, self.pspec, n_comb_stages))
101
102 pipeend = FPNormToPack(self.width, self.pspec)
103
104 # add submodules
105 m.submodules.scnorm = pipestart
106 for i, p in enumerate(pipechain):
107 setattr(m.submodules, "pipediv%d" % i, p)
108 m.submodules.normpack = pipeend
109
110 # ControlBase.connect creates (returns) the "eqs" needed
111 m.d.comb += self.connect([pipestart] + pipechain + [pipeend])
112
113 return m
114
115
116 class FPDIVMuxInOut(ReservationStations):
117 """ Reservation-Station version of FPDIV pipeline.
118
119 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
120 * N-stage divider pipeline
121 * fan-out on outputs (an array of FPPackData: z,mid)
122
123 Fan-in and Fan-out are combinatorial.
124
125 :op_wid: - set this to the width of an operator which can
126 then be used to change the behaviour of the pipeline.
127 """
128 def __init__(self, width, num_rows, op_wid=0):
129 self.width = width
130 self.id_wid = num_bits(width)
131 self.pspec = {'id_wid': self.id_wid, 'op_wid': op_wid}
132 self.alu = FPDIVBasePipe(width, self.pspec)
133 ReservationStations.__init__(self, num_rows)
134
135 def i_specfn(self):
136 return FPADDBaseData(self.width, self.pspec)
137
138 def o_specfn(self):
139 return FPPackData(self.width, self.pspec)