add in TstL0CacheBuffer but disable temporarily
[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.ldst.pipe_data import LDSTPipeSpec
68 from soc.experiment.compldst_multi import LDSTCompUnit # special-case
69
70
71 ###################################################################
72 ###### FunctionUnitBaseSingle - use to make single-stge pipes #####
73
74 class FunctionUnitBaseSingle(MultiCompUnit):
75 """FunctionUnitBaseSingle
76
77 main "glue" class that brings everything together.
78 ONLY use this class for single-stage pipelines.
79
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
84
85 note that it is through MultiCompUnit.get_in/out that we *actually*
86 connect up the association between regspec variable names (defined
87 in the pipe_data).
88
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.
92 """
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
99
100
101 ##############################################################
102 # TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
103
104 class FunctionUnitBaseMulti:
105 pass
106
107
108 ######################################################################
109 ###### actual Function Units: these are "single" stage pipelines #####
110
111 class ALUFunctionUnit(FunctionUnitBaseSingle):
112 fnunit = Function.ALU
113 def __init__(self): super().__init__(ALUPipeSpec, ALUBasePipe)
114
115 class LogicalFunctionUnit(FunctionUnitBaseSingle):
116 fnunit = Function.LOGICAL
117 def __init__(self): super().__init__(LogicalPipeSpec, LogicalBasePipe)
118
119 class CRFunctionUnit(FunctionUnitBaseSingle):
120 fnunit = Function.CR
121 def __init__(self): super().__init__(CRPipeSpec, CRBasePipe)
122
123 class BranchFunctionUnit(FunctionUnitBaseSingle):
124 fnunit = Function.BRANCH
125 def __init__(self): super().__init__(BranchPipeSpec, BranchBasePipe)
126
127 class ShiftRotFunctionUnit(FunctionUnitBaseSingle):
128 fnunit = Function.SHIFT_ROT
129 def __init__(self): super().__init__(ShiftRotPipeSpec, ShiftRotBasePipe)
130
131 # special-case
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)
139
140
141 #####################################################################
142 ###### actual Function Units: these are "multi" stage pipelines #####
143
144 # TODO: ReservationStations-based.
145
146
147 # simple one-only function unit class, for test purposes
148 class AllFunctionUnits(Elaboratable):
149 """AllFunctionUnits
150
151 creates a dictionary of Function Units according to required spec.
152 tuple is of:
153
154 * name of ALU,
155 * quantity of FUs required
156 * type of FU required
157
158 """
159 def __init__(self, pilist=None, addrwid=6):
160 self.fus = {}
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),
166 ):
167 for i in range(qty):
168 self.fus["%s%d" % (name, i)] = kls()
169 if pilist is None:
170 return
171 for i, pi in enumerate(pilist):
172 self.fus["ldst%d" % (i)] = LDSTFunctionUnit(pi, addrwid)
173
174 def elaborate(self, platform):
175 m = Module()
176 for (name, fu) in self.fus.items():
177 setattr(m.submodules, name, fu)
178 return m
179
180 def __iter__(self):
181 for (name, fu) in self.fus.items():
182 yield from fu.ports()
183
184 def ports(self):
185 return list(self)
186
187
188 def tst_single_fus_il():
189 for (name, kls) in (('alu', ALUFunctionUnit),
190 ('cr', CRFunctionUnit),
191 ('branch', BranchFunctionUnit),
192 ('logical', LogicalFunctionUnit),
193 ('shiftrot', ShiftRotFunctionUnit)):
194 fu = kls()
195 vl = rtlil.convert(fu, ports=fu.ports())
196 with open("fu_%s.il" % name, "w") as f:
197 f.write(vl)
198
199
200 def tst_all_fus():
201 dut = AllFunctionUnits()
202 vl = rtlil.convert(dut, ports=dut.ports())
203 with open("all_fus.il", "w") as f:
204 f.write(vl)
205
206 if __name__ == '__main__':
207 tst_single_fus_il()
208 tst_all_fus()