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
52 # pipeline / spec imports
54 from soc
.fu
.alu
.pipeline
import ALUBasePipe
55 from soc
.fu
.alu
.pipe_data
import ALUPipeSpec
57 from soc
.fu
.logical
.pipeline
import LogicalBasePipe
58 from soc
.fu
.logical
.pipe_data
import LogicalPipeSpec
60 from soc
.fu
.cr
.pipeline
import CRBasePipe
61 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
63 from soc
.fu
.branch
.pipeline
import BranchBasePipe
64 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
66 from soc
.fu
.shift_rot
.pipeline
import ShiftRotBasePipe
67 from soc
.fu
.shift_rot
.pipe_data
import ShiftRotPipeSpec
69 from soc
.fu
.spr
.pipeline
import SPRBasePipe
70 from soc
.fu
.spr
.pipe_data
import SPRPipeSpec
72 from soc
.fu
.trap
.pipeline
import TrapBasePipe
73 from soc
.fu
.trap
.pipe_data
import TrapPipeSpec
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
79 from soc
.fu
.mmu
.fsm
import FSMMMUStage
80 from soc
.fu
.mmu
.pipe_data
import MMUPipeSpec
82 from soc
.fu
.mul
.pipeline
import MulBasePipe
83 from soc
.fu
.mul
.pipe_data
import MulPipeSpec
85 from soc
.fu
.ldst
.pipe_data
import LDSTPipeSpec
86 from soc
.experiment
.compldst_multi
import LDSTCompUnit
# special-case
89 ###################################################################
90 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
92 class FunctionUnitBaseSingle(MultiCompUnit
):
93 """FunctionUnitBaseSingle
95 main "glue" class that brings everything together.
96 ONLY use this class for single-stage pipelines.
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
103 note that it is through MultiCompUnit.get_in/out that we *actually*
104 connect up the association between regspec variable names (defined
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.
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
119 super().__init
__(regspec
, alu
, opsubset
, name
=alu_name
) # MultiCompUnit
122 ##############################################################
123 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
125 class FunctionUnitBaseMulti
:
129 ######################################################################
130 ###### actual Function Units: these are "single" stage pipelines #####
132 class ALUFunctionUnit(FunctionUnitBaseSingle
):
133 fnunit
= Function
.ALU
135 def __init__(self
, idx
):
136 super().__init
__(ALUPipeSpec
, ALUBasePipe
, idx
)
139 class LogicalFunctionUnit(FunctionUnitBaseSingle
):
140 fnunit
= Function
.LOGICAL
142 def __init__(self
, idx
):
143 super().__init
__(LogicalPipeSpec
, LogicalBasePipe
, idx
)
146 class CRFunctionUnit(FunctionUnitBaseSingle
):
149 def __init__(self
, idx
):
150 super().__init
__(CRPipeSpec
, CRBasePipe
, idx
)
153 class BranchFunctionUnit(FunctionUnitBaseSingle
):
154 fnunit
= Function
.BRANCH
156 def __init__(self
, idx
):
157 super().__init
__(BranchPipeSpec
, BranchBasePipe
, idx
)
160 class ShiftRotFunctionUnit(FunctionUnitBaseSingle
):
161 fnunit
= Function
.SHIFT_ROT
163 def __init__(self
, idx
):
164 super().__init
__(ShiftRotPipeSpec
, ShiftRotBasePipe
, idx
)
167 class DivFSMFunctionUnit(FunctionUnitBaseSingle
):
168 fnunit
= Function
.DIV
170 def __init__(self
, idx
):
171 super().__init
__(DivPipeSpecFSMDivCore
, DivBasePipe
, idx
)
174 class MMUFSMFunctionUnit(FunctionUnitBaseSingle
):
175 fnunit
= Function
.MMU
177 def __init__(self
, idx
):
178 super().__init
__(MMUPipeSpec
, FSMMMUStage
, idx
)
181 class DivPipeFunctionUnit(FunctionUnitBaseSingle
):
182 fnunit
= Function
.DIV
184 def __init__(self
, idx
):
185 super().__init
__(DivPipeSpecDivPipeCore
, DivBasePipe
, idx
)
188 class MulFunctionUnit(FunctionUnitBaseSingle
):
189 fnunit
= Function
.MUL
191 def __init__(self
, idx
):
192 super().__init
__(MulPipeSpec
, MulBasePipe
, idx
)
195 class TrapFunctionUnit(FunctionUnitBaseSingle
):
196 fnunit
= Function
.TRAP
198 def __init__(self
, idx
):
199 super().__init
__(TrapPipeSpec
, TrapBasePipe
, idx
)
202 class SPRFunctionUnit(FunctionUnitBaseSingle
):
203 fnunit
= Function
.SPR
205 def __init__(self
, idx
):
206 super().__init
__(SPRPipeSpec
, SPRBasePipe
, idx
)
209 # special-case: LD/ST conforms to the CompUnit API but is not a pipeline
211 class LDSTFunctionUnit(LDSTCompUnit
):
212 fnunit
= Function
.LDST
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
)
223 #####################################################################
224 ###### actual Function Units: these are "multi" stage pipelines #####
226 # TODO: ReservationStations-based.
228 # simple one-only function unit class, for test purposes
229 class AllFunctionUnits(Elaboratable
):
232 creates a dictionary of Function Units according to required spec.
236 * quantity of FUs required
237 * type of FU required
241 def __init__(self
, pspec
, pilist
=None, div_fsm
=True):
242 addrwid
= pspec
.addr_wid
244 microwatt_mmu
= hasattr(pspec
, "mmu") and pspec
.mmu
== True
245 print("AllFunctionUnits.microwatt_mmu="+str(microwatt_mmu
))
246 if not isinstance(units
, dict):
247 units
= {'alu': 1, 'cr': 1, 'branch': 1, 'trap': 1,
251 'div': 1, 'shiftrot': 1}
254 alus
= {'alu': ALUFunctionUnit
,
255 'cr': CRFunctionUnit
,
256 'branch': BranchFunctionUnit
,
257 'trap': TrapFunctionUnit
,
258 'spr': SPRFunctionUnit
,
259 'mul': MulFunctionUnit
,
260 'mmu': MMUFSMFunctionUnit
,
261 'logical': LogicalFunctionUnit
,
262 'shiftrot': ShiftRotFunctionUnit
,
265 alus
['div'] = DivFSMFunctionUnit
267 alus
['div'] = DivPipeFunctionUnit
270 for name
, qty
in units
.items():
273 self
.fus
["%s%d" % (name
, i
)] = kls(i
)
275 print("cut here ==============================")
276 alu
= self
.fus
["mmu0"].alu
283 print ("pilist", pilist
)
284 for i
, pi
in enumerate(pilist
):
285 self
.fus
["ldst%d" % (i
)] = LDSTFunctionUnit(pi
, addrwid
, i
)
287 def get_fu(self
, name
):
288 return self
.fus
.get(name
)
290 def elaborate(self
, platform
):
292 for (name
, fu
) in self
.fus
.items():
293 setattr(m
.submodules
, name
, fu
)
297 for (name
, fu
) in self
.fus
.items():
298 yield from fu
.ports()
304 def tst_single_fus_il():
305 for (name
, kls
) in (('alu', ALUFunctionUnit
),
306 ('cr', CRFunctionUnit
),
307 ('branch', BranchFunctionUnit
),
308 ('trap', TrapFunctionUnit
),
309 ('spr', SPRFunctionUnit
),
310 ('mul', MulFunctionUnit
),
311 ('logical', LogicalFunctionUnit
),
312 ('shiftrot', ShiftRotFunctionUnit
)):
314 vl
= rtlil
.convert(fu
, ports
=fu
.ports())
315 with
open("fu_%s.il" % name
, "w") as f
:
320 pspec
= TestMemPspec(ldst_ifacetype
='testpi',
325 dut
= AllFunctionUnits(pspec
)
326 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
327 with
open("all_fus.il", "w") as f
:
331 if __name__
== '__main__':