dcache.py commit first full tranlation pass, about five percent left
[soc.git] / src / soc / fu / compunits / compunits.py
1 ###################################################################
2 """Function Units Construction
3
4 This module pulls all of the pipelines together (soc.fu.*) and, using
5 the regspec and Computation Unit APIs, constructs Scoreboard-aware
6 Function Units that may systematically and automatically be wired up
7 to appropriate Register Files.
8
9 Two types exist:
10
11 * Single-cycle Function Units. these are FUs that will only block for
12 one cycle. it is expected that multiple of these be instantiated,
13 because they are simple and trivial, and not many gates.
14
15 - ALU, Logical: definitely several
16 - CR: not so many needed (perhaps)
17 - Branch: one or two of these (depending on speculation run-ahead)
18 - Trap: yeah really only one of these
19 - SPR: again, only one.
20 - ShiftRot (perhaps not too many of these)
21
22 * Multi-cycle (and FSM) Function Units. these are FUs that can only
23 handle a limited number of values, and take several cycles to complete.
24 Given that under Scoreboard Management, start and completion must be
25 fully managed, a "Reservation Station" style approach is required:
26 *one* multiple-stage (N stage) pipelines need a minimum of N (plural)
27 "CompUnit" front-ends. this includes:
28
29 - MUL (all versions including MAC)
30 - DIV (including modulo)
31
32 In either case, there will be multiple MultiCompUnits: it's just that
33 single-cycle ones are instantiated individually (one single-cycle pipeline
34 per MultiCompUnit, and multi-cycle ones need to be instantiated en-masse,
35 where *only one* actual pipeline (or FSM) has *multiple* Reservation
36 Stations.
37
38 see:
39
40 * https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
41
42 """
43
44 # imports
45
46 from nmigen import Elaboratable, Module
47 from nmigen.cli import rtlil
48 from soc.experiment.compalu_multi import MultiCompUnit
49 from soc.decoder.power_enums import Function
50
51 # pipeline / spec imports
52
53 from soc.fu.alu.pipeline import ALUBasePipe
54 from soc.fu.alu.pipe_data import ALUPipeSpec
55
56 from soc.fu.logical.pipeline import LogicalBasePipe
57 from soc.fu.logical.pipe_data import LogicalPipeSpec
58
59 from soc.fu.cr.pipeline import CRBasePipe
60 from soc.fu.cr.pipe_data import CRPipeSpec
61
62 from soc.fu.branch.pipeline import BranchBasePipe
63 from soc.fu.branch.pipe_data import BranchPipeSpec
64
65 from soc.fu.shift_rot.pipeline import ShiftRotBasePipe
66 from soc.fu.shift_rot.pipe_data import ShiftRotPipeSpec
67
68 from soc.fu.spr.pipeline import SPRBasePipe
69 from soc.fu.spr.pipe_data import SPRPipeSpec
70
71 from soc.fu.trap.pipeline import TrapBasePipe
72 from soc.fu.trap.pipe_data import TrapPipeSpec
73
74 from soc.fu.div.pipeline import DivBasePipe
75 from soc.fu.div.pipe_data import DivPipeSpecFSMDivCore
76
77 from soc.fu.mul.pipeline import MulBasePipe
78 from soc.fu.mul.pipe_data import MulPipeSpec
79
80 from soc.fu.ldst.pipe_data import LDSTPipeSpec
81 from soc.experiment.compldst_multi import LDSTCompUnit # special-case
82
83
84 ###################################################################
85 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
86
87 class FunctionUnitBaseSingle(MultiCompUnit):
88 """FunctionUnitBaseSingle
89
90 main "glue" class that brings everything together.
91 ONLY use this class for single-stage pipelines.
92
93 * :speckls: - the specification. contains regspec and op subset info,
94 and contains common "stuff" like the pipeline ctx,
95 what type of nmutil pipeline base is to be used (etc)
96 * :pipekls: - the type of pipeline. actually connects things together
97
98 note that it is through MultiCompUnit.get_in/out that we *actually*
99 connect up the association between regspec variable names (defined
100 in the pipe_data).
101
102 note that the rdflags function obtains (dynamically, from instruction
103 decoding) which read-register ports are to be requested. this is not
104 ideal (it could be a lot neater) but works for now.
105 """
106
107 def __init__(self, speckls, pipekls, idx):
108 alu_name = "alu_%s%d" % (self.fnunit.name.lower(), idx)
109 pspec = speckls(id_wid=2) # spec (NNNPipeSpec instance)
110 opsubset = pspec.opsubsetkls # get the operand subset class
111 regspec = pspec.regspec # get the regspec
112 alu = pipekls(pspec) # create actual NNNBasePipe
113 super().__init__(regspec, alu, opsubset, name=alu_name) # MultiCompUnit
114
115
116 ##############################################################
117 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
118
119 class FunctionUnitBaseMulti:
120 pass
121
122
123 ######################################################################
124 ###### actual Function Units: these are "single" stage pipelines #####
125
126 class ALUFunctionUnit(FunctionUnitBaseSingle):
127 fnunit = Function.ALU
128
129 def __init__(self, idx):
130 super().__init__(ALUPipeSpec, ALUBasePipe, idx)
131
132
133 class LogicalFunctionUnit(FunctionUnitBaseSingle):
134 fnunit = Function.LOGICAL
135
136 def __init__(self, idx):
137 super().__init__(LogicalPipeSpec, LogicalBasePipe, idx)
138
139
140 class CRFunctionUnit(FunctionUnitBaseSingle):
141 fnunit = Function.CR
142
143 def __init__(self, idx):
144 super().__init__(CRPipeSpec, CRBasePipe, idx)
145
146
147 class BranchFunctionUnit(FunctionUnitBaseSingle):
148 fnunit = Function.BRANCH
149
150 def __init__(self, idx):
151 super().__init__(BranchPipeSpec, BranchBasePipe, idx)
152
153
154 class ShiftRotFunctionUnit(FunctionUnitBaseSingle):
155 fnunit = Function.SHIFT_ROT
156
157 def __init__(self, idx):
158 super().__init__(ShiftRotPipeSpec, ShiftRotBasePipe, idx)
159
160
161 class DivFunctionUnit(FunctionUnitBaseSingle):
162 fnunit = Function.DIV
163
164 def __init__(self, idx):
165 super().__init__(DivPipeSpecFSMDivCore, DivBasePipe, idx)
166
167
168 class MulFunctionUnit(FunctionUnitBaseSingle):
169 fnunit = Function.MUL
170
171 def __init__(self, idx):
172 super().__init__(MulPipeSpec, MulBasePipe, idx)
173
174
175 class TrapFunctionUnit(FunctionUnitBaseSingle):
176 fnunit = Function.TRAP
177
178 def __init__(self, idx):
179 super().__init__(TrapPipeSpec, TrapBasePipe, idx)
180
181
182 class SPRFunctionUnit(FunctionUnitBaseSingle):
183 fnunit = Function.SPR
184
185 def __init__(self, idx):
186 super().__init__(SPRPipeSpec, SPRBasePipe, idx)
187
188
189 # special-case: LD/ST conforms to the CompUnit API but is not a pipeline
190
191 class LDSTFunctionUnit(LDSTCompUnit):
192 fnunit = Function.LDST
193
194 def __init__(self, pi, awid, idx):
195 alu_name = "ldst_%s%d" % (self.fnunit.name.lower(), idx)
196 pspec = LDSTPipeSpec(id_wid=2) # spec (NNNPipeSpec instance)
197 opsubset = pspec.opsubsetkls # get the operand subset class
198 regspec = pspec.regspec # get the regspec
199 super().__init__(pi, regspec, awid, opsubset, name=alu_name)
200
201
202 #####################################################################
203 ###### actual Function Units: these are "multi" stage pipelines #####
204
205 # TODO: ReservationStations-based.
206
207
208 # simple one-only function unit class, for test purposes
209 class AllFunctionUnits(Elaboratable):
210 """AllFunctionUnits
211
212 creates a dictionary of Function Units according to required spec.
213 tuple is of:
214
215 * name of ALU,
216 * quantity of FUs required
217 * type of FU required
218
219 """
220
221 def __init__(self, pspec, pilist=None):
222 addrwid = pspec.addr_wid
223 units = pspec.units
224 if not isinstance(units, dict):
225 units = {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1,
226 'spr': 1,
227 'logical': 1,
228 'mul': 1,
229 'div': 1, 'shiftrot': 1}
230 alus = {'alu': ALUFunctionUnit,
231 'cr': CRFunctionUnit,
232 'branch': BranchFunctionUnit,
233 'trap': TrapFunctionUnit,
234 'spr': SPRFunctionUnit,
235 'div': DivFunctionUnit,
236 'mul': MulFunctionUnit,
237 'logical': LogicalFunctionUnit,
238 'shiftrot': ShiftRotFunctionUnit,
239 }
240 self.fus = {}
241 for name, qty in units.items():
242 kls = alus[name]
243 for i in range(qty):
244 self.fus["%s%d" % (name, i)] = kls(i)
245 if pilist is None:
246 return
247 for i, pi in enumerate(pilist):
248 self.fus["ldst%d" % (i)] = LDSTFunctionUnit(pi, addrwid, i)
249
250 def elaborate(self, platform):
251 m = Module()
252 for (name, fu) in self.fus.items():
253 setattr(m.submodules, name, fu)
254 return m
255
256 def __iter__(self):
257 for (name, fu) in self.fus.items():
258 yield from fu.ports()
259
260 def ports(self):
261 return list(self)
262
263
264 def tst_single_fus_il():
265 for (name, kls) in (('alu', ALUFunctionUnit),
266 ('cr', CRFunctionUnit),
267 ('branch', BranchFunctionUnit),
268 ('trap', TrapFunctionUnit),
269 ('spr', SPRFunctionUnit),
270 ('mul', MulFunctionUnit),
271 ('logical', LogicalFunctionUnit),
272 ('shiftrot', ShiftRotFunctionUnit)):
273 fu = kls(0)
274 vl = rtlil.convert(fu, ports=fu.ports())
275 with open("fu_%s.il" % name, "w") as f:
276 f.write(vl)
277
278
279 def tst_all_fus():
280 dut = AllFunctionUnits()
281 vl = rtlil.convert(dut, ports=dut.ports())
282 with open("all_fus.il", "w") as f:
283 f.write(vl)
284
285
286 if __name__ == '__main__':
287 tst_single_fus_il()
288 tst_all_fus()