fix unit tests due to change in using pspec
[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, idx):
100 alu_name = "alu_%s%d" % (self.fnunit.name.lower(), idx)
101 pspec = speckls(id_wid=2) # spec (NNNPipeSpec instance)
102 opsubset = pspec.opsubsetkls # get the operand subset class
103 regspec = pspec.regspec # get the regspec
104 alu = pipekls(pspec) # create actual NNNBasePipe
105 super().__init__(regspec, alu, opsubset, name=alu_name) # MultiCompUnit
106
107
108 ##############################################################
109 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
110
111 class FunctionUnitBaseMulti:
112 pass
113
114
115 ######################################################################
116 ###### actual Function Units: these are "single" stage pipelines #####
117
118 class ALUFunctionUnit(FunctionUnitBaseSingle):
119 fnunit = Function.ALU
120 def __init__(self, idx):
121 super().__init__(ALUPipeSpec, ALUBasePipe, idx)
122
123 class LogicalFunctionUnit(FunctionUnitBaseSingle):
124 fnunit = Function.LOGICAL
125 def __init__(self, idx):
126 super().__init__(LogicalPipeSpec, LogicalBasePipe, idx)
127
128 class CRFunctionUnit(FunctionUnitBaseSingle):
129 fnunit = Function.CR
130 def __init__(self, idx):
131 super().__init__(CRPipeSpec, CRBasePipe, idx)
132
133 class BranchFunctionUnit(FunctionUnitBaseSingle):
134 fnunit = Function.BRANCH
135 def __init__(self, idx):
136 super().__init__(BranchPipeSpec, BranchBasePipe, idx)
137
138 class ShiftRotFunctionUnit(FunctionUnitBaseSingle):
139 fnunit = Function.SHIFT_ROT
140 def __init__(self, idx):
141 super().__init__(ShiftRotPipeSpec, ShiftRotBasePipe, idx)
142
143 class DIVFunctionUnit(FunctionUnitBaseSingle):
144 fnunit = Function.DIV
145 def __init__(self, idx):
146 super().__init__(DIVPipeSpec, DIVBasePipe, idx)
147
148 class TrapFunctionUnit(FunctionUnitBaseSingle):
149 fnunit = Function.TRAP
150 def __init__(self, idx):
151 super().__init__(TrapPipeSpec, TrapBasePipe, idx)
152
153 # special-case
154 class LDSTFunctionUnit(LDSTCompUnit):
155 fnunit = Function.LDST
156 def __init__(self, pi, awid, idx):
157 pspec = LDSTPipeSpec(id_wid=2) # spec (NNNPipeSpec instance)
158 opsubset = pspec.opsubsetkls # get the operand subset class
159 regspec = pspec.regspec # get the regspec
160 super().__init__(pi, regspec, awid, opsubset)
161
162
163 #####################################################################
164 ###### actual Function Units: these are "multi" stage pipelines #####
165
166 # TODO: ReservationStations-based.
167
168
169 # simple one-only function unit class, for test purposes
170 class AllFunctionUnits(Elaboratable):
171 """AllFunctionUnits
172
173 creates a dictionary of Function Units according to required spec.
174 tuple is of:
175
176 * name of ALU,
177 * quantity of FUs required
178 * type of FU required
179
180 """
181 def __init__(self, pspec, pilist=None, addrwid=6):
182 self.fus = {}
183 for (name, qty, kls) in (('alu', 1, ALUFunctionUnit),
184 ('cr', 1, CRFunctionUnit),
185 ('branch', 1, BranchFunctionUnit),
186 ('trap', 1, TrapFunctionUnit),
187 # far too large at the moment
188 #('div', 1, DIVFunctionUnit),
189 ('logical', 1, LogicalFunctionUnit),
190 ('shiftrot', 1, ShiftRotFunctionUnit),
191 ):
192 for i in range(qty):
193 self.fus["%s%d" % (name, i)] = kls(i)
194 if pilist is None:
195 return
196 for i, pi in enumerate(pilist):
197 self.fus["ldst%d" % (i)] = LDSTFunctionUnit(pi, addrwid, i)
198
199 def elaborate(self, platform):
200 m = Module()
201 for (name, fu) in self.fus.items():
202 setattr(m.submodules, name, fu)
203 return m
204
205 def __iter__(self):
206 for (name, fu) in self.fus.items():
207 yield from fu.ports()
208
209 def ports(self):
210 return list(self)
211
212
213 def tst_single_fus_il():
214 for (name, kls) in (('alu', ALUFunctionUnit),
215 ('cr', CRFunctionUnit),
216 ('branch', BranchFunctionUnit),
217 ('trap', TrapFunctionUnit),
218 ('logical', LogicalFunctionUnit),
219 ('shiftrot', ShiftRotFunctionUnit)):
220 fu = kls(0)
221 vl = rtlil.convert(fu, ports=fu.ports())
222 with open("fu_%s.il" % name, "w") as f:
223 f.write(vl)
224
225
226 def tst_all_fus():
227 dut = AllFunctionUnits()
228 vl = rtlil.convert(dut, ports=dut.ports())
229 with open("all_fus.il", "w") as f:
230 f.write(vl)
231
232 if __name__ == '__main__':
233 tst_single_fus_il()
234 tst_all_fus()