4129d36891e641e588abf9918830b02188880894
[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 from soc.config.test.test_loadstore import TestMemPspec
51
52 # pipeline / spec imports
53
54 from soc.fu.alu.pipeline import ALUBasePipe
55 from soc.fu.alu.pipe_data import ALUPipeSpec
56
57 from soc.fu.logical.pipeline import LogicalBasePipe
58 from soc.fu.logical.pipe_data import LogicalPipeSpec
59
60 from soc.fu.cr.pipeline import CRBasePipe
61 from soc.fu.cr.pipe_data import CRPipeSpec
62
63 from soc.fu.branch.pipeline import BranchBasePipe
64 from soc.fu.branch.pipe_data import BranchPipeSpec
65
66 from soc.fu.shift_rot.pipeline import ShiftRotBasePipe
67 from soc.fu.shift_rot.pipe_data import ShiftRotPipeSpec
68
69 from soc.fu.spr.pipeline import SPRBasePipe
70 from soc.fu.spr.pipe_data import SPRPipeSpec
71
72 from soc.fu.trap.pipeline import TrapBasePipe
73 from soc.fu.trap.pipe_data import TrapPipeSpec
74
75 from soc.fu.div.pipeline import DivBasePipe
76 from soc.fu.div.pipe_data import DivPipeSpecFSMDivCore
77 from soc.fu.div.pipe_data import DivPipeSpecDivPipeCore
78
79 from soc.fu.mmu.fsm import FSMMMUStage
80 from soc.fu.mmu.pipe_data import MMUPipeSpec
81
82 from soc.fu.mul.pipeline import MulBasePipe
83 from soc.fu.mul.pipe_data import MulPipeSpec
84
85 from soc.fu.ldst.pipe_data import LDSTPipeSpec
86 from soc.experiment.compldst_multi import LDSTCompUnit # special-case
87
88
89 ###################################################################
90 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
91
92 class FunctionUnitBaseSingle(MultiCompUnit):
93 """FunctionUnitBaseSingle
94
95 main "glue" class that brings everything together.
96 ONLY use this class for single-stage pipelines.
97
98 * :speckls: - the specification. contains regspec and op subset info,
99 and contains common "stuff" like the pipeline ctx,
100 what type of nmutil pipeline base is to be used (etc)
101 * :pipekls: - the type of pipeline. actually connects things together
102
103 note that it is through MultiCompUnit.get_in/out that we *actually*
104 connect up the association between regspec variable names (defined
105 in the pipe_data).
106
107 note that the rdflags function obtains (dynamically, from instruction
108 decoding) which read-register ports are to be requested. this is not
109 ideal (it could be a lot neater) but works for now.
110 """
111
112 def __init__(self, speckls, pipekls, idx):
113 alu_name = "alu_%s%d" % (self.fnunit.name.lower(), idx)
114 pspec = speckls(id_wid=2) # spec (NNNPipeSpec instance)
115 opsubset = pspec.opsubsetkls # get the operand subset class
116 regspec = pspec.regspec # get the regspec
117 alu = pipekls(pspec) # create actual NNNBasePipe
118 self.pspec = pspec
119 super().__init__(regspec, alu, opsubset, name=alu_name) # MultiCompUnit
120
121
122 ##############################################################
123 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
124
125 class FunctionUnitBaseMulti:
126 pass
127
128
129 ######################################################################
130 ###### actual Function Units: these are "single" stage pipelines #####
131
132 class ALUFunctionUnit(FunctionUnitBaseSingle):
133 fnunit = Function.ALU
134
135 def __init__(self, idx):
136 super().__init__(ALUPipeSpec, ALUBasePipe, idx)
137
138
139 class LogicalFunctionUnit(FunctionUnitBaseSingle):
140 fnunit = Function.LOGICAL
141
142 def __init__(self, idx):
143 super().__init__(LogicalPipeSpec, LogicalBasePipe, idx)
144
145
146 class CRFunctionUnit(FunctionUnitBaseSingle):
147 fnunit = Function.CR
148
149 def __init__(self, idx):
150 super().__init__(CRPipeSpec, CRBasePipe, idx)
151
152
153 class BranchFunctionUnit(FunctionUnitBaseSingle):
154 fnunit = Function.BRANCH
155
156 def __init__(self, idx):
157 super().__init__(BranchPipeSpec, BranchBasePipe, idx)
158
159
160 class ShiftRotFunctionUnit(FunctionUnitBaseSingle):
161 fnunit = Function.SHIFT_ROT
162
163 def __init__(self, idx):
164 super().__init__(ShiftRotPipeSpec, ShiftRotBasePipe, idx)
165
166
167 class DivFSMFunctionUnit(FunctionUnitBaseSingle):
168 fnunit = Function.DIV
169
170 def __init__(self, idx):
171 super().__init__(DivPipeSpecFSMDivCore, DivBasePipe, idx)
172
173
174 class MMUFSMFunctionUnit(FunctionUnitBaseSingle):
175 fnunit = Function.MMU
176
177 def __init__(self, idx):
178 super().__init__(MMUPipeSpec, FSMMMUStage, idx)
179
180
181 class DivPipeFunctionUnit(FunctionUnitBaseSingle):
182 fnunit = Function.DIV
183
184 def __init__(self, idx):
185 super().__init__(DivPipeSpecDivPipeCore, DivBasePipe, idx)
186
187
188 class MulFunctionUnit(FunctionUnitBaseSingle):
189 fnunit = Function.MUL
190
191 def __init__(self, idx):
192 super().__init__(MulPipeSpec, MulBasePipe, idx)
193
194
195 class TrapFunctionUnit(FunctionUnitBaseSingle):
196 fnunit = Function.TRAP
197
198 def __init__(self, idx):
199 super().__init__(TrapPipeSpec, TrapBasePipe, idx)
200
201
202 class SPRFunctionUnit(FunctionUnitBaseSingle):
203 fnunit = Function.SPR
204
205 def __init__(self, idx):
206 super().__init__(SPRPipeSpec, SPRBasePipe, idx)
207
208
209 # special-case: LD/ST conforms to the CompUnit API but is not a pipeline
210
211 class LDSTFunctionUnit(LDSTCompUnit):
212 fnunit = Function.LDST
213
214 def __init__(self, pi, awid, idx):
215 alu_name = "ldst_%s%d" % (self.fnunit.name.lower(), idx)
216 pspec = LDSTPipeSpec(id_wid=2) # spec (NNNPipeSpec instance)
217 opsubset = pspec.opsubsetkls # get the operand subset class
218 regspec = pspec.regspec # get the regspec
219 self.opsubsetkls = opsubset
220 super().__init__(pi, regspec, awid, opsubset, name=alu_name)
221
222
223 #####################################################################
224 ###### actual Function Units: these are "multi" stage pipelines #####
225
226 # TODO: ReservationStations-based.
227
228 # simple one-only function unit class, for test purposes
229 class AllFunctionUnits(Elaboratable):
230 """AllFunctionUnits
231
232 creates a dictionary of Function Units according to required spec.
233 tuple is of:
234
235 * name of ALU,
236 * quantity of FUs required
237 * type of FU required
238
239 """
240
241 def __init__(self, pspec, pilist=None, div_fsm=True,microwatt_mmu = False):
242 addrwid = pspec.addr_wid
243 units = pspec.units
244 if not isinstance(units, dict):
245 units = {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1,
246 'spr': 1,
247 'logical': 1,
248 'mul': 1,
249 'div': 1, 'shiftrot': 1}
250 if microwatt_mmu:
251 units['mmu'] = 1
252 alus = {'alu': ALUFunctionUnit,
253 'cr': CRFunctionUnit,
254 'branch': BranchFunctionUnit,
255 'trap': TrapFunctionUnit,
256 'spr': SPRFunctionUnit,
257 'mul': MulFunctionUnit,
258 'mmu': MMUFSMFunctionUnit,
259 'logical': LogicalFunctionUnit,
260 'shiftrot': ShiftRotFunctionUnit,
261 }
262 if div_fsm:
263 alus['div'] = DivFSMFunctionUnit
264 else:
265 alus['div'] = DivPipeFunctionUnit
266
267 self.fus = {}
268 for name, qty in units.items():
269 kls = alus[name]
270 for i in range(qty):
271 self.fus["%s%d" % (name, i)] = kls(i)
272 if microwatt_mmu:
273 print("cut here ==============================")
274 alu = self.fus["mmu0"].alu
275 print("alu",alu)
276 pi = alu.pi
277 print("pi",pi)
278 pilist = [pi]
279 if pilist is None:
280 return
281 for i, pi in enumerate(pilist):
282 self.fus["ldst%d" % (i)] = LDSTFunctionUnit(pi, addrwid, i)
283
284 def elaborate(self, platform):
285 m = Module()
286 for (name, fu) in self.fus.items():
287 setattr(m.submodules, name, fu)
288 return m
289
290 def __iter__(self):
291 for (name, fu) in self.fus.items():
292 yield from fu.ports()
293
294 def ports(self):
295 return list(self)
296
297
298 def tst_single_fus_il():
299 for (name, kls) in (('alu', ALUFunctionUnit),
300 ('cr', CRFunctionUnit),
301 ('branch', BranchFunctionUnit),
302 ('trap', TrapFunctionUnit),
303 ('spr', SPRFunctionUnit),
304 ('mul', MulFunctionUnit),
305 ('logical', LogicalFunctionUnit),
306 ('shiftrot', ShiftRotFunctionUnit)):
307 fu = kls(0)
308 vl = rtlil.convert(fu, ports=fu.ports())
309 with open("fu_%s.il" % name, "w") as f:
310 f.write(vl)
311
312
313 def tst_all_fus():
314 pspec = TestMemPspec(ldst_ifacetype='testpi',
315 imem_ifacetype='',
316 addr_wid=48,
317 mask_wid=8,
318 reg_wid=64)
319 dut = AllFunctionUnits(pspec)
320 vl = rtlil.convert(dut, ports=dut.ports())
321 with open("all_fus.il", "w") as f:
322 f.write(vl)
323
324
325 if __name__ == '__main__':
326 tst_single_fus_il()
327 tst_all_fus()