comment out DIV unit for now
[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 - ShiftRot (perhaps not too many of these)
20
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:
27
28 - MUL (all versions including MAC)
29 - DIV (including modulo)
30
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
35 Stations.
36
37 see:
38
39 * https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
40
41 """
42
43 # imports
44
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
49
50 # pipeline / spec imports
51
52 from soc.fu.alu.pipeline import ALUBasePipe
53 from soc.fu.alu.pipe_data import ALUPipeSpec
54
55 from soc.fu.logical.pipeline import LogicalBasePipe
56 from soc.fu.logical.pipe_data import LogicalPipeSpec
57
58 from soc.fu.cr.pipeline import CRBasePipe
59 from soc.fu.cr.pipe_data import CRPipeSpec
60
61 from soc.fu.branch.pipeline import BranchBasePipe
62 from soc.fu.branch.pipe_data import BranchPipeSpec
63
64 from soc.fu.shift_rot.pipeline import ShiftRotBasePipe
65 from soc.fu.shift_rot.pipe_data import ShiftRotPipeSpec
66
67 from soc.fu.trap.pipeline import TrapBasePipe
68 from soc.fu.trap.pipe_data import TrapPipeSpec
69
70 from soc.fu.div.pipeline import DIVBasePipe
71 from soc.fu.div.pipe_data import DIVPipeSpec
72
73 from soc.fu.ldst.pipe_data import LDSTPipeSpec
74 from soc.experiment.compldst_multi import LDSTCompUnit # special-case
75
76
77 ###################################################################
78 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
79
80 class FunctionUnitBaseSingle(MultiCompUnit):
81 """FunctionUnitBaseSingle
82
83 main "glue" class that brings everything together.
84 ONLY use this class for single-stage pipelines.
85
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
90
91 note that it is through MultiCompUnit.get_in/out that we *actually*
92 connect up the association between regspec variable names (defined
93 in the pipe_data).
94
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.
98 """
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
105
106
107 ##############################################################
108 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
109
110 class FunctionUnitBaseMulti:
111 pass
112
113
114 ######################################################################
115 ###### actual Function Units: these are "single" stage pipelines #####
116
117 class ALUFunctionUnit(FunctionUnitBaseSingle):
118 fnunit = Function.ALU
119 def __init__(self): super().__init__(ALUPipeSpec, ALUBasePipe)
120
121 class LogicalFunctionUnit(FunctionUnitBaseSingle):
122 fnunit = Function.LOGICAL
123 def __init__(self): super().__init__(LogicalPipeSpec, LogicalBasePipe)
124
125 class CRFunctionUnit(FunctionUnitBaseSingle):
126 fnunit = Function.CR
127 def __init__(self): super().__init__(CRPipeSpec, CRBasePipe)
128
129 class BranchFunctionUnit(FunctionUnitBaseSingle):
130 fnunit = Function.BRANCH
131 def __init__(self): super().__init__(BranchPipeSpec, BranchBasePipe)
132
133 class ShiftRotFunctionUnit(FunctionUnitBaseSingle):
134 fnunit = Function.SHIFT_ROT
135 def __init__(self): super().__init__(ShiftRotPipeSpec, ShiftRotBasePipe)
136
137 class DIVFunctionUnit(FunctionUnitBaseSingle):
138 fnunit = Function.DIV
139 def __init__(self): super().__init__(DIVPipeSpec, DIVBasePipe)
140
141 class TrapFunctionUnit(FunctionUnitBaseSingle):
142 fnunit = Function.TRAP
143 def __init__(self): super().__init__(TrapPipeSpec, TrapBasePipe)
144
145 # special-case
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)
153
154
155 #####################################################################
156 ###### actual Function Units: these are "multi" stage pipelines #####
157
158 # TODO: ReservationStations-based.
159
160
161 # simple one-only function unit class, for test purposes
162 class AllFunctionUnits(Elaboratable):
163 """AllFunctionUnits
164
165 creates a dictionary of Function Units according to required spec.
166 tuple is of:
167
168 * name of ALU,
169 * quantity of FUs required
170 * type of FU required
171
172 """
173 def __init__(self, pilist=None, addrwid=6):
174 self.fus = {}
175 for (name, qty, kls) in (('alu', 1, ALUFunctionUnit),
176 ('cr', 1, CRFunctionUnit),
177 ('branch', 1, BranchFunctionUnit),
178 ('trap', 1, TrapFunctionUnit),
179 # far too large at the moment
180 #('div', 1, DIVFunctionUnit),
181 ('logical', 1, LogicalFunctionUnit),
182 ('shiftrot', 1, ShiftRotFunctionUnit),
183 ):
184 for i in range(qty):
185 self.fus["%s%d" % (name, i)] = kls()
186 if pilist is None:
187 return
188 for i, pi in enumerate(pilist):
189 self.fus["ldst%d" % (i)] = LDSTFunctionUnit(pi, addrwid)
190
191 def elaborate(self, platform):
192 m = Module()
193 for (name, fu) in self.fus.items():
194 setattr(m.submodules, name, fu)
195 return m
196
197 def __iter__(self):
198 for (name, fu) in self.fus.items():
199 yield from fu.ports()
200
201 def ports(self):
202 return list(self)
203
204
205 def tst_single_fus_il():
206 for (name, kls) in (('alu', ALUFunctionUnit),
207 ('cr', CRFunctionUnit),
208 ('branch', BranchFunctionUnit),
209 ('trap', TrapFunctionUnit),
210 ('logical', LogicalFunctionUnit),
211 ('shiftrot', ShiftRotFunctionUnit)):
212 fu = kls()
213 vl = rtlil.convert(fu, ports=fu.ports())
214 with open("fu_%s.il" % name, "w") as f:
215 f.write(vl)
216
217
218 def tst_all_fus():
219 dut = AllFunctionUnits()
220 vl = rtlil.convert(dut, ports=dut.ports())
221 with open("all_fus.il", "w") as f:
222 f.write(vl)
223
224 if __name__ == '__main__':
225 tst_single_fus_il()
226 tst_all_fus()