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