add in trap compunit
[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.ldst.pipe_data import LDSTPipeSpec
71 from soc.experiment.compldst_multi import LDSTCompUnit # special-case
72
73
74 ###################################################################
75 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
76
77 class FunctionUnitBaseSingle(MultiCompUnit):
78 """FunctionUnitBaseSingle
79
80 main "glue" class that brings everything together.
81 ONLY use this class for single-stage pipelines.
82
83 * :speckls: - the specification. contains regspec and op subset info,
84 and contains common "stuff" like the pipeline ctx,
85 what type of nmutil pipeline base is to be used (etc)
86 * :pipekls: - the type of pipeline. actually connects things together
87
88 note that it is through MultiCompUnit.get_in/out that we *actually*
89 connect up the association between regspec variable names (defined
90 in the pipe_data).
91
92 note that the rdflags function obtains (dynamically, from instruction
93 decoding) which read-register ports are to be requested. this is not
94 ideal (it could be a lot neater) but works for now.
95 """
96 def __init__(self, speckls, pipekls):
97 pspec = speckls(id_wid=2) # spec (NNNPipeSpec instance)
98 opsubset = pspec.opsubsetkls # get the operand subset class
99 regspec = pspec.regspec # get the regspec
100 alu = pipekls(pspec) # create actual NNNBasePipe
101 super().__init__(regspec, alu, opsubset) # pass to MultiCompUnit
102
103
104 ##############################################################
105 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
106
107 class FunctionUnitBaseMulti:
108 pass
109
110
111 ######################################################################
112 ###### actual Function Units: these are "single" stage pipelines #####
113
114 class ALUFunctionUnit(FunctionUnitBaseSingle):
115 fnunit = Function.ALU
116 def __init__(self): super().__init__(ALUPipeSpec, ALUBasePipe)
117
118 class LogicalFunctionUnit(FunctionUnitBaseSingle):
119 fnunit = Function.LOGICAL
120 def __init__(self): super().__init__(LogicalPipeSpec, LogicalBasePipe)
121
122 class CRFunctionUnit(FunctionUnitBaseSingle):
123 fnunit = Function.CR
124 def __init__(self): super().__init__(CRPipeSpec, CRBasePipe)
125
126 class BranchFunctionUnit(FunctionUnitBaseSingle):
127 fnunit = Function.BRANCH
128 def __init__(self): super().__init__(BranchPipeSpec, BranchBasePipe)
129
130 class ShiftRotFunctionUnit(FunctionUnitBaseSingle):
131 fnunit = Function.SHIFT_ROT
132 def __init__(self): super().__init__(ShiftRotPipeSpec, ShiftRotBasePipe)
133
134 class TrapFunctionUnit(FunctionUnitBaseSingle):
135 fnunit = Function.TRAP
136 def __init__(self): super().__init__(TrapPipeSpec, TrapBasePipe)
137
138 # special-case
139 class LDSTFunctionUnit(LDSTCompUnit):
140 fnunit = Function.LDST
141 def __init__(self, pi, awid):
142 pspec = LDSTPipeSpec(id_wid=2) # spec (NNNPipeSpec instance)
143 opsubset = pspec.opsubsetkls # get the operand subset class
144 regspec = pspec.regspec # get the regspec
145 super().__init__(pi, regspec, awid, opsubset)
146
147
148 #####################################################################
149 ###### actual Function Units: these are "multi" stage pipelines #####
150
151 # TODO: ReservationStations-based.
152
153
154 # simple one-only function unit class, for test purposes
155 class AllFunctionUnits(Elaboratable):
156 """AllFunctionUnits
157
158 creates a dictionary of Function Units according to required spec.
159 tuple is of:
160
161 * name of ALU,
162 * quantity of FUs required
163 * type of FU required
164
165 """
166 def __init__(self, pilist=None, addrwid=6):
167 self.fus = {}
168 for (name, qty, kls) in (('alu', 1, ALUFunctionUnit),
169 ('cr', 1, CRFunctionUnit),
170 ('branch', 1, BranchFunctionUnit),
171 ('logical', 1, LogicalFunctionUnit),
172 ('shiftrot', 1, ShiftRotFunctionUnit),
173 ):
174 for i in range(qty):
175 self.fus["%s%d" % (name, i)] = kls()
176 if pilist is None:
177 return
178 for i, pi in enumerate(pilist):
179 self.fus["ldst%d" % (i)] = LDSTFunctionUnit(pi, addrwid)
180
181 def elaborate(self, platform):
182 m = Module()
183 for (name, fu) in self.fus.items():
184 setattr(m.submodules, name, fu)
185 return m
186
187 def __iter__(self):
188 for (name, fu) in self.fus.items():
189 yield from fu.ports()
190
191 def ports(self):
192 return list(self)
193
194
195 def tst_single_fus_il():
196 for (name, kls) in (('alu', ALUFunctionUnit),
197 ('cr', CRFunctionUnit),
198 ('branch', BranchFunctionUnit),
199 ('trap', TrapFunctionUnit),
200 ('logical', LogicalFunctionUnit),
201 ('shiftrot', ShiftRotFunctionUnit)):
202 fu = kls()
203 vl = rtlil.convert(fu, ports=fu.ports())
204 with open("fu_%s.il" % name, "w") as f:
205 f.write(vl)
206
207
208 def tst_all_fus():
209 dut = AllFunctionUnits()
210 vl = rtlil.convert(dut, ports=dut.ports())
211 with open("all_fus.il", "w") as f:
212 f.write(vl)
213
214 if __name__ == '__main__':
215 tst_single_fus_il()
216 tst_all_fus()