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
.ldst
.pipe_data
import LDSTPipeSpec
68 from soc
.experiment
.compldst_multi
import LDSTCompUnit
# special-case
71 ###################################################################
72 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
74 class FunctionUnitBaseSingle(MultiCompUnit
):
75 """FunctionUnitBaseSingle
77 main "glue" class that brings everything together.
78 ONLY use this class for single-stage pipelines.
80 * :speckls: - the specification. contains regspec and op subset info,
81 and contains common "stuff" like the pipeline ctx,
82 what type of nmutil pipeline base is to be used (etc)
83 * :pipekls: - the type of pipeline. actually connects things together
85 note that it is through MultiCompUnit.get_in/out that we *actually*
86 connect up the association between regspec variable names (defined
89 note that the rdflags function obtains (dynamically, from instruction
90 decoding) which read-register ports are to be requested. this is not
91 ideal (it could be a lot neater) but works for now.
93 def __init__(self
, speckls
, pipekls
):
94 pspec
= speckls(id_wid
=2) # spec (NNNPipeSpec instance)
95 opsubset
= pspec
.opsubsetkls
# get the operand subset class
96 regspec
= pspec
.regspec
# get the regspec
97 alu
= pipekls(pspec
) # create actual NNNBasePipe
98 super().__init
__(regspec
, alu
, opsubset
) # pass to MultiCompUnit
101 ##############################################################
102 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
104 class FunctionUnitBaseMulti
:
108 ######################################################################
109 ###### actual Function Units: these are "single" stage pipelines #####
111 class ALUFunctionUnit(FunctionUnitBaseSingle
):
112 fnunit
= Function
.ALU
113 def __init__(self
): super().__init
__(ALUPipeSpec
, ALUBasePipe
)
115 class LogicalFunctionUnit(FunctionUnitBaseSingle
):
116 fnunit
= Function
.LOGICAL
117 def __init__(self
): super().__init
__(LogicalPipeSpec
, LogicalBasePipe
)
119 class CRFunctionUnit(FunctionUnitBaseSingle
):
121 def __init__(self
): super().__init
__(CRPipeSpec
, CRBasePipe
)
123 class BranchFunctionUnit(FunctionUnitBaseSingle
):
124 fnunit
= Function
.BRANCH
125 def __init__(self
): super().__init
__(BranchPipeSpec
, BranchBasePipe
)
127 class ShiftRotFunctionUnit(FunctionUnitBaseSingle
):
128 fnunit
= Function
.SHIFT_ROT
129 def __init__(self
): super().__init
__(ShiftRotPipeSpec
, ShiftRotBasePipe
)
132 class LDSTFunctionUnit(LDSTCompUnit
):
133 fnunit
= Function
.ALU
134 def __init__(self
, pi
, awid
):
135 pspec
= LDSTPipeSpec(id_wid
=2) # spec (NNNPipeSpec instance)
136 opsubset
= pspec
.opsubsetkls
# get the operand subset class
137 regspec
= pspec
.regspec
# get the regspec
138 super().__init
__(pi
, regspec
, awid
, opsubset
)
141 #####################################################################
142 ###### actual Function Units: these are "multi" stage pipelines #####
144 # TODO: ReservationStations-based.
147 # simple one-only function unit class, for test purposes
148 class AllFunctionUnits(Elaboratable
):
151 creates a dictionary of Function Units according to required spec.
155 * quantity of FUs required
156 * type of FU required
161 for (name
, qty
, kls
) in (('alu', 1, ALUFunctionUnit
),
162 ('cr', 1, CRFunctionUnit
),
163 ('branch', 1, BranchFunctionUnit
),
164 ('logical', 1, LogicalFunctionUnit
),
165 ('shiftrot', 1, ShiftRotFunctionUnit
)
168 self
.fus
["%s%d" % (name
, i
)] = kls()
170 def elaborate(self
, platform
):
172 for (name
, fu
) in self
.fus
.items():
173 setattr(m
.submodules
, name
, fu
)
177 for (name
, fu
) in self
.fus
.items():
178 yield from fu
.ports()
184 def tst_single_fus_il():
185 for (name
, kls
) in (('alu', ALUFunctionUnit
),
186 ('cr', CRFunctionUnit
),
187 ('branch', BranchFunctionUnit
),
188 ('logical', LogicalFunctionUnit
),
189 ('shiftrot', ShiftRotFunctionUnit
)):
191 vl
= rtlil
.convert(fu
, ports
=fu
.ports())
192 with
open("fu_%s.il" % name
, "w") as f
:
197 dut
= AllFunctionUnits()
198 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
199 with
open("all_fus.il", "w") as f
:
202 if __name__
== '__main__':