1 ###################################################################
2 """Function Units Construction
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.
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.
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)
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:
29 - MUL (all versions including MAC)
30 - DIV (including modulo)
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
40 * https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
46 from nmigen
import Elaboratable
, Module
47 from nmigen
.cli
import rtlil
48 from soc
.experiment
.compalu_multi
import MultiCompUnit
49 from openpower
.decoder
.power_enums
import Function
50 from soc
.config
.test
.test_loadstore
import TestMemPspec
51 from nmutil
.concurrentunit
import ReservationStations2
53 # pipeline / spec imports
55 from soc
.fu
.alu
.pipeline
import ALUBasePipe
56 from soc
.fu
.alu
.pipe_data
import ALUPipeSpec
58 from soc
.fu
.logical
.pipeline
import LogicalBasePipe
59 from soc
.fu
.logical
.pipe_data
import LogicalPipeSpec
61 from soc
.fu
.cr
.pipeline
import CRBasePipe
62 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
64 from soc
.fu
.branch
.pipeline
import BranchBasePipe
65 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
67 from soc
.fu
.shift_rot
.pipeline
import ShiftRotBasePipe
68 from soc
.fu
.shift_rot
.pipe_data
import ShiftRotPipeSpec
70 from soc
.fu
.spr
.pipeline
import SPRBasePipe
71 from soc
.fu
.spr
.pipe_data
import SPRPipeSpec
73 from soc
.fu
.trap
.pipeline
import TrapBasePipe
74 from soc
.fu
.trap
.pipe_data
import TrapPipeSpec
76 from soc
.fu
.div
.pipeline
import DivBasePipe
77 from soc
.fu
.div
.pipe_data
import DivPipeSpecFSMDivCore
78 from soc
.fu
.div
.pipe_data
import DivPipeSpecDivPipeCore
80 from soc
.fu
.mmu
.fsm
import FSMMMUStage
81 from soc
.fu
.mmu
.pipe_data
import MMUPipeSpec
83 from soc
.fu
.mul
.pipeline
import MulBasePipe
84 from soc
.fu
.mul
.pipe_data
import MulPipeSpec
86 from soc
.fu
.ldst
.pipe_data
import LDSTPipeSpec
87 from soc
.experiment
.compldst_multi
import LDSTCompUnit
# special-case
90 ###################################################################
91 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
93 class FunctionUnitBaseSingle(MultiCompUnit
):
94 """FunctionUnitBaseSingle
96 main "glue" class that brings everything together.
97 ONLY use this class for single-stage pipelines.
99 * :speckls: - the specification. contains regspec and op subset info,
100 and contains common "stuff" like the pipeline ctx,
101 what type of nmutil pipeline base is to be used (etc)
102 * :pipekls: - the type of pipeline. actually connects things together
104 note that it is through MultiCompUnit.get_in/out that we *actually*
105 connect up the association between regspec variable names (defined
108 note that the rdflags function obtains (dynamically, from instruction
109 decoding) which read-register ports are to be requested. this is not
110 ideal (it could be a lot neater) but works for now.
112 also note: additional members, fu.rd_latches and fu.wr_latches
113 are replaced, here, by core.py. those contain the latched
114 read/write register information which the FU needs in order
115 to actually read (and write) the correct register number
118 def __init__(self
, speckls
, pipekls
, idx
):
119 alu_name
= "alu_%s%d" % (self
.fnunit
.name
.lower(), idx
)
120 pspec
= speckls(id_wid
=2) # spec (NNNPipeSpec instance)
121 opsubset
= pspec
.opsubsetkls
# get the operand subset class
122 regspec
= pspec
.regspec
# get the regspec
123 alu
= pipekls(pspec
) # create actual NNNBasePipe
125 super().__init
__(regspec
, alu
, opsubset
, name
=alu_name
) # MultiCompUnit
126 # these are set to None for now: core get_byregfiles fills them in
128 self
.fu_rdlatches
= None
129 self
.fu_wrlatches
= None
132 ##############################################################
133 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
135 class FunctionUnitBaseMulti(ReservationStations2
):
136 """FunctionUnitBaseMulti
138 similar to FunctionUnitBaseSingle except it creates a list
139 of MultiCompUnit instances all using the same ALU instance.
141 * :speckls: - the specification. contains regspec and op subset info,
142 and contains common "stuff" like the pipeline ctx,
143 what type of nmutil pipeline base is to be used (etc)
144 * :pipekls: - the type of pipeline. actually connects things together
146 * :num_rows: - number of ReservationStations wrapped around the FU
148 note that it is through MultiCompUnit.get_in/out that we *actually*
149 connect up the association between regspec variable names (defined
152 note that the rdflags function obtains (dynamically, from instruction
153 decoding) which read-register ports are to be requested. this is not
154 ideal (it could be a lot neater) but works for now.
157 def __init__(self
, speckls
, pipekls
, num_rows
):
158 id_wid
= num_rows
.bit_length()
159 pspec
= speckls(id_wid
=id_wid
) # spec (NNNPipeSpec instance)
160 opsubset
= pspec
.opsubsetkls
# get the operand subset class
161 regspec
= pspec
.regspec
# get the regspec
162 alu
= pipekls(pspec
) # create actual NNNBasePipe
164 alu_name
= self
.fnunit
.name
.lower()
165 super().__init
__(alu
, num_rows
, alu_name
) # initialise fan-in/fan-out
167 for idx
in range(num_rows
):
168 alu_name
= "alu_%s%d" % (alu_name
, idx
)
169 palu
= self
.pseudoalus
[idx
]
170 cu
= MultiCompUnit(regspec
, palu
, opsubset
, name
=alu_name
)
171 cu
.fnunit
= self
.fnunit
175 ######################################################################
176 ###### actual Function Units: these are "single" stage pipelines #####
178 #class ALUFunctionUnit(FunctionUnitBaseSingle):
179 class ALUFunctionUnit(FunctionUnitBaseMulti
):
180 fnunit
= Function
.ALU
182 def __init__(self
, idx
):
183 super().__init
__(ALUPipeSpec
, ALUBasePipe
, 1)
186 #class LogicalFunctionUnit(FunctionUnitBaseSingle):
187 class LogicalFunctionUnit(FunctionUnitBaseMulti
):
188 fnunit
= Function
.LOGICAL
190 def __init__(self
, idx
):
191 super().__init
__(LogicalPipeSpec
, LogicalBasePipe
, idx
)
194 #class CRFunctionUnit(FunctionUnitBaseSingle):
195 class CRFunctionUnit(FunctionUnitBaseMulti
):
198 def __init__(self
, idx
):
199 super().__init
__(CRPipeSpec
, CRBasePipe
, idx
)
202 #class BranchFunctionUnit(FunctionUnitBaseSingle):
203 class BranchFunctionUnit(FunctionUnitBaseMulti
):
204 fnunit
= Function
.BRANCH
206 def __init__(self
, idx
):
207 super().__init
__(BranchPipeSpec
, BranchBasePipe
, idx
)
210 #class ShiftRotFunctionUnit(FunctionUnitBaseSingle):
211 class ShiftRotFunctionUnit(FunctionUnitBaseMulti
):
212 fnunit
= Function
.SHIFT_ROT
214 def __init__(self
, idx
):
215 super().__init
__(ShiftRotPipeSpec
, ShiftRotBasePipe
, idx
)
218 class DivFSMFunctionUnit(FunctionUnitBaseSingle
):
219 fnunit
= Function
.DIV
221 def __init__(self
, idx
):
222 super().__init
__(DivPipeSpecFSMDivCore
, DivBasePipe
, idx
)
225 class MMUFSMFunctionUnit(FunctionUnitBaseSingle
):
226 fnunit
= Function
.MMU
228 def __init__(self
, idx
):
229 super().__init
__(MMUPipeSpec
, FSMMMUStage
, idx
)
232 class DivPipeFunctionUnit(FunctionUnitBaseSingle
):
233 fnunit
= Function
.DIV
235 def __init__(self
, idx
):
236 super().__init
__(DivPipeSpecDivPipeCore
, DivBasePipe
, idx
)
239 #class MulFunctionUnit(FunctionUnitBaseSingle):
240 class MulFunctionUnit(FunctionUnitBaseMulti
):
241 fnunit
= Function
.MUL
243 def __init__(self
, idx
):
244 super().__init
__(MulPipeSpec
, MulBasePipe
, idx
)
247 class TrapFunctionUnit(FunctionUnitBaseSingle
):
248 fnunit
= Function
.TRAP
250 def __init__(self
, idx
):
251 super().__init
__(TrapPipeSpec
, TrapBasePipe
, idx
)
254 class SPRFunctionUnit(FunctionUnitBaseSingle
):
255 fnunit
= Function
.SPR
257 def __init__(self
, idx
):
258 super().__init
__(SPRPipeSpec
, SPRBasePipe
, idx
)
261 # special-case: LD/ST conforms to the CompUnit API but is not a pipeline
263 class LDSTFunctionUnit(LDSTCompUnit
):
264 fnunit
= Function
.LDST
266 def __init__(self
, pi
, awid
, idx
):
267 alu_name
= "ldst_%s%d" % (self
.fnunit
.name
.lower(), idx
)
268 pspec
= LDSTPipeSpec(id_wid
=2) # spec (NNNPipeSpec instance)
269 opsubset
= pspec
.opsubsetkls
# get the operand subset class
270 regspec
= pspec
.regspec
# get the regspec
271 self
.opsubsetkls
= opsubset
272 super().__init
__(pi
, regspec
, awid
, opsubset
, name
=alu_name
)
275 #####################################################################
276 ###### actual Function Units: these are "multi" stage pipelines #####
278 # TODO: ReservationStations-based.
280 # simple one-only function unit class, for test purposes
281 class AllFunctionUnits(Elaboratable
):
284 creates a dictionary of Function Units according to required spec.
288 * quantity of FUs required
289 * type of FU required
293 def __init__(self
, pspec
, pilist
=None, div_fsm
=True):
294 addrwid
= pspec
.addr_wid
296 microwatt_mmu
= hasattr(pspec
, "mmu") and pspec
.mmu
== True
297 print("AllFunctionUnits.microwatt_mmu="+str(microwatt_mmu
))
298 if not isinstance(units
, dict):
299 units
= {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1,
303 'div': 1, 'shiftrot': 1}
306 alus
= {'alu': ALUFunctionUnit
,
307 'cr': CRFunctionUnit
,
308 'branch': BranchFunctionUnit
,
309 'trap': TrapFunctionUnit
,
310 'spr': SPRFunctionUnit
,
311 'mul': MulFunctionUnit
,
312 'mmu': MMUFSMFunctionUnit
,
313 'logical': LogicalFunctionUnit
,
314 'shiftrot': ShiftRotFunctionUnit
,
317 alus
['div'] = DivFSMFunctionUnit
319 alus
['div'] = DivPipeFunctionUnit
321 # create dictionary of Function Units
323 self
.actual_alus
= {}
324 for name
, qty
in units
.items():
326 if issubclass(kls
, FunctionUnitBaseMulti
):
327 fu
= kls(qty
) # create just the one ALU but many "fronts"
328 self
.actual_alus
[name
] = fu
# to be made a module of AllFUs
330 self
.fus
["%s%d" % (name
, i
)] = fu
.cu
[i
]
333 self
.fus
["%s%d" % (name
, i
)] = kls(i
)
335 # debug print for MMU ALU
337 alu
= self
.fus
["mmu0"].alu
338 print("MMU alu", alu
)
340 # if any PortInterfaces, we want LDST Units.
343 print ("pilist", pilist
)
344 for i
, pi
in enumerate(pilist
):
345 self
.fus
["ldst%d" % (i
)] = LDSTFunctionUnit(pi
, addrwid
, i
)
347 # extract exceptions from any FunctionUnits for easy access
349 for name
, alu
in self
.fus
.items():
350 if hasattr(alu
, "exc_o"):
351 print ("FU exceptions", name
, type(alu
.exc_o
), alu
.exc_o
)
352 self
.excs
[name
] = alu
.exc_o
354 def get_exc(self
, name
):
355 return self
.excs
.get(name
)
357 def get_fu(self
, name
):
358 return self
.fus
.get(name
)
360 def elaborate(self
, platform
):
362 # add MultiCompUnit modules (Single CompUnits add their own ALU)
363 for (name
, fu
) in self
.fus
.items():
364 setattr(m
.submodules
, name
, fu
)
365 # if any ReservationStations, there is only one ALU per RS so add that
366 for (name
, alu
) in self
.actual_alus
.items():
367 setattr(m
.submodules
, name
, alu
)
371 for (name
, fu
) in self
.fus
.items():
372 yield from fu
.ports()
378 def tst_single_fus_il():
379 for (name
, kls
) in (('alu', ALUFunctionUnit
),
380 ('cr', CRFunctionUnit
),
381 ('branch', BranchFunctionUnit
),
382 ('trap', TrapFunctionUnit
),
383 ('spr', SPRFunctionUnit
),
384 ('mul', MulFunctionUnit
),
385 ('logical', LogicalFunctionUnit
),
386 ('shiftrot', ShiftRotFunctionUnit
)):
388 vl
= rtlil
.convert(fu
, ports
=fu
.ports())
389 with
open("fu_%s.il" % name
, "w") as f
:
394 pspec
= TestMemPspec(ldst_ifacetype
='testpi',
399 dut
= AllFunctionUnits(pspec
)
400 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
401 with
open("all_fus.il", "w") as f
:
405 if __name__
== '__main__':