add DIV function unit to compunits
[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 ('div', 1, DIVFunctionUnit),
180 ('logical', 1, LogicalFunctionUnit),
181 ('shiftrot', 1, ShiftRotFunctionUnit),
182 ):
183 for i in range(qty):
184 self.fus["%s%d" % (name, i)] = kls()
185 if pilist is None:
186 return
187 for i, pi in enumerate(pilist):
188 self.fus["ldst%d" % (i)] = LDSTFunctionUnit(pi, addrwid)
189
190 def elaborate(self, platform):
191 m = Module()
192 for (name, fu) in self.fus.items():
193 setattr(m.submodules, name, fu)
194 return m
195
196 def __iter__(self):
197 for (name, fu) in self.fus.items():
198 yield from fu.ports()
199
200 def ports(self):
201 return list(self)
202
203
204 def tst_single_fus_il():
205 for (name, kls) in (('alu', ALUFunctionUnit),
206 ('cr', CRFunctionUnit),
207 ('branch', BranchFunctionUnit),
208 ('trap', TrapFunctionUnit),
209 ('logical', LogicalFunctionUnit),
210 ('shiftrot', ShiftRotFunctionUnit)):
211 fu = kls()
212 vl = rtlil.convert(fu, ports=fu.ports())
213 with open("fu_%s.il" % name, "w") as f:
214 f.write(vl)
215
216
217 def tst_all_fus():
218 dut = AllFunctionUnits()
219 vl = rtlil.convert(dut, ports=dut.ports())
220 with open("all_fus.il", "w") as f:
221 f.write(vl)
222
223 if __name__ == '__main__':
224 tst_single_fus_il()
225 tst_all_fus()