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 - ShiftRot (perhaps not too many of these)
21 * Multi-cycle (and FSM) Function Units. these are FUs that can only
22 handle a limited number of values, and take several cycles to complete.
23 Given that under Scoreboard Management, start and completion must be
24 fully managed, a "Reservation Station" style approach is required:
25 *one* multiple-stage (N stage) pipelines need a minimum of N (plural)
26 "CompUnit" front-ends. this includes:
28 - MUL (all versions including MAC)
29 - DIV (including modulo)
31 In either case, there will be multiple MultiCompUnits: it's just that
32 single-cycle ones are instantiated individually (one single-cycle pipeline
33 per MultiCompUnit, and multi-cycle ones need to be instantiated en-masse,
34 where *only one* actual pipeline (or FSM) has *multiple* Reservation
39 * https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
45 from nmigen
import Elaboratable
, Module
46 from nmigen
.cli
import rtlil
47 from soc
.experiment
.compalu_multi
import MultiCompUnit
48 from soc
.decoder
.power_enums
import Function
50 # pipeline / spec imports
52 from soc
.fu
.alu
.pipeline
import ALUBasePipe
53 from soc
.fu
.alu
.pipe_data
import ALUPipeSpec
55 from soc
.fu
.logical
.pipeline
import LogicalBasePipe
56 from soc
.fu
.logical
.pipe_data
import LogicalPipeSpec
58 from soc
.fu
.cr
.pipeline
import CRBasePipe
59 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
61 from soc
.fu
.branch
.pipeline
import BranchBasePipe
62 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
64 from soc
.fu
.shift_rot
.pipeline
import ShiftRotBasePipe
65 from soc
.fu
.shift_rot
.pipe_data
import ShiftRotPipeSpec
67 from soc
.fu
.trap
.pipeline
import TrapBasePipe
68 from soc
.fu
.trap
.pipe_data
import TrapPipeSpec
70 from soc
.fu
.div
.pipeline
import DIVBasePipe
71 from soc
.fu
.div
.pipe_data
import DIVPipeSpec
73 from soc
.fu
.ldst
.pipe_data
import LDSTPipeSpec
74 from soc
.experiment
.compldst_multi
import LDSTCompUnit
# special-case
77 ###################################################################
78 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
80 class FunctionUnitBaseSingle(MultiCompUnit
):
81 """FunctionUnitBaseSingle
83 main "glue" class that brings everything together.
84 ONLY use this class for single-stage pipelines.
86 * :speckls: - the specification. contains regspec and op subset info,
87 and contains common "stuff" like the pipeline ctx,
88 what type of nmutil pipeline base is to be used (etc)
89 * :pipekls: - the type of pipeline. actually connects things together
91 note that it is through MultiCompUnit.get_in/out that we *actually*
92 connect up the association between regspec variable names (defined
95 note that the rdflags function obtains (dynamically, from instruction
96 decoding) which read-register ports are to be requested. this is not
97 ideal (it could be a lot neater) but works for now.
99 def __init__(self
, speckls
, pipekls
):
100 pspec
= speckls(id_wid
=2) # spec (NNNPipeSpec instance)
101 opsubset
= pspec
.opsubsetkls
# get the operand subset class
102 regspec
= pspec
.regspec
# get the regspec
103 alu
= pipekls(pspec
) # create actual NNNBasePipe
104 super().__init
__(regspec
, alu
, opsubset
) # pass to MultiCompUnit
107 ##############################################################
108 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
110 class FunctionUnitBaseMulti
:
114 ######################################################################
115 ###### actual Function Units: these are "single" stage pipelines #####
117 class ALUFunctionUnit(FunctionUnitBaseSingle
):
118 fnunit
= Function
.ALU
119 def __init__(self
): super().__init
__(ALUPipeSpec
, ALUBasePipe
)
121 class LogicalFunctionUnit(FunctionUnitBaseSingle
):
122 fnunit
= Function
.LOGICAL
123 def __init__(self
): super().__init
__(LogicalPipeSpec
, LogicalBasePipe
)
125 class CRFunctionUnit(FunctionUnitBaseSingle
):
127 def __init__(self
): super().__init
__(CRPipeSpec
, CRBasePipe
)
129 class BranchFunctionUnit(FunctionUnitBaseSingle
):
130 fnunit
= Function
.BRANCH
131 def __init__(self
): super().__init
__(BranchPipeSpec
, BranchBasePipe
)
133 class ShiftRotFunctionUnit(FunctionUnitBaseSingle
):
134 fnunit
= Function
.SHIFT_ROT
135 def __init__(self
): super().__init
__(ShiftRotPipeSpec
, ShiftRotBasePipe
)
137 class DIVFunctionUnit(FunctionUnitBaseSingle
):
138 fnunit
= Function
.DIV
139 def __init__(self
): super().__init
__(DIVPipeSpec
, DIVBasePipe
)
141 class TrapFunctionUnit(FunctionUnitBaseSingle
):
142 fnunit
= Function
.TRAP
143 def __init__(self
): super().__init
__(TrapPipeSpec
, TrapBasePipe
)
146 class LDSTFunctionUnit(LDSTCompUnit
):
147 fnunit
= Function
.LDST
148 def __init__(self
, pi
, awid
):
149 pspec
= LDSTPipeSpec(id_wid
=2) # spec (NNNPipeSpec instance)
150 opsubset
= pspec
.opsubsetkls
# get the operand subset class
151 regspec
= pspec
.regspec
# get the regspec
152 super().__init
__(pi
, regspec
, awid
, opsubset
)
155 #####################################################################
156 ###### actual Function Units: these are "multi" stage pipelines #####
158 # TODO: ReservationStations-based.
161 # simple one-only function unit class, for test purposes
162 class AllFunctionUnits(Elaboratable
):
165 creates a dictionary of Function Units according to required spec.
169 * quantity of FUs required
170 * type of FU required
173 def __init__(self
, pilist
=None, addrwid
=6):
175 for (name
, qty
, kls
) in (('alu', 1, ALUFunctionUnit
),
176 ('cr', 1, CRFunctionUnit
),
177 ('branch', 1, BranchFunctionUnit
),
178 ('trap', 1, TrapFunctionUnit
),
179 ('div', 1, DIVFunctionUnit
),
180 ('logical', 1, LogicalFunctionUnit
),
181 ('shiftrot', 1, ShiftRotFunctionUnit
),
184 self
.fus
["%s%d" % (name
, i
)] = kls()
187 for i
, pi
in enumerate(pilist
):
188 self
.fus
["ldst%d" % (i
)] = LDSTFunctionUnit(pi
, addrwid
)
190 def elaborate(self
, platform
):
192 for (name
, fu
) in self
.fus
.items():
193 setattr(m
.submodules
, name
, fu
)
197 for (name
, fu
) in self
.fus
.items():
198 yield from fu
.ports()
204 def tst_single_fus_il():
205 for (name
, kls
) in (('alu', ALUFunctionUnit
),
206 ('cr', CRFunctionUnit
),
207 ('branch', BranchFunctionUnit
),
208 ('trap', TrapFunctionUnit
),
209 ('logical', LogicalFunctionUnit
),
210 ('shiftrot', ShiftRotFunctionUnit
)):
212 vl
= rtlil
.convert(fu
, ports
=fu
.ports())
213 with
open("fu_%s.il" % name
, "w") as f
:
218 dut
= AllFunctionUnits()
219 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
220 with
open("all_fus.il", "w") as f
:
223 if __name__
== '__main__':