add comments to power decoder
[soc.git] / src / soc / decoder / power_decoder.py
1 """Cascading Power ISA Decoder
2
3 This module uses CSV tables in a hierarchical/peer cascading fashion,
4 to create a multi-level instruction decoder by recognising appropriate
5 patterns. The output is a wide, flattened (1-level) series of bitfields,
6 suitable for a simple RISC engine.
7
8 This is based on Anton Blanchard's excellent microwatt work:
9 https://github.com/antonblanchard/microwatt/blob/master/decode1.vhdl
10
11 The basic principle is that the python code does the heavy lifting
12 (reading the CSV files, constructing the hierarchy), creating the HDL
13 AST with for-loops generating switch-case statements.
14
15 Where "normal" HDL would do this, in laborious excruciating detail:
16
17 switch (opcode & major_mask_bits):
18 case opcode_2: decode_opcode_2()
19 case opcode_19:
20 switch (opcode & minor_19_mask_bits)
21 case minor_opcode_19_operation_X:
22 case minor_opcode_19_operation_y:
23
24 we take *full* advantage of the decoupling between python and the
25 nmigen AST data structure, to do this:
26
27 with m.Switch(opcode & self.mask):
28 for case_bitmask in subcases:
29 with m.If(opcode & case_bitmask): {do_something}
30
31 this includes specifying the information sufficient to perform subdecoding.
32
33 create_pdecode()
34
35 the full hierarchical tree for decoding POWER9 is specified here
36
37 PowerDecoder
38
39 takes a *list* of CSV files with an associated bit-range that it
40 is requested to match against the "opcode" row of the CSV file.
41 This pattern can be either an integer, a binary number, *or* a
42 wildcard nmigen Case pattern of the form "001--1-100".
43
44 Subdecoders
45
46 these are *additional* cases with further decoding. The "pattern"
47 argument is specified as one of the Case statements (a peer of the
48 opcode row in the CSV file), and thus further fields of the opcode
49 may be decoded giving increasing levels of detail.
50
51 Top Level:
52
53 [ (extra.csv: bit-fields entire 32-bit range
54 opcode -> matches
55 000000---------------01000000000 -> ILLEGAL instruction
56 01100000000000000000000000000000 -> SIM_CONFIG instruction
57 ................................ ->
58 ),
59 (major.csv: first 6 bits ONLY
60 opcode -> matches
61 001100 -> ALU,OP_ADD (add)
62 001101 -> ALU,OP_ADD (another type of add)
63 ...... -> ...
64 ...... -> ...
65 subdecoders:
66 001011 this must match *MAJOR*.CSV
67 [ (minor_19.csv: bits 21 through 30 inclusive:
68 opcode -> matches
69 0b0000000000 -> ALU,OP_MCRF
70 ............ -> ....
71 ),
72 (minor_19_00000.csv: bits 21 through 25 inclusive:
73 opcode -> matches
74 0b00010 -> ALU,add_pcis
75 )
76 ]
77 ),
78 ]
79
80 """
81
82 from collections import namedtuple
83 from nmigen import Module, Elaboratable, Signal, Cat, Mux
84 from nmigen.cli import rtlil
85 from soc.decoder.power_enums import (Function, Form, InternalOp,
86 In1Sel, In2Sel, In3Sel, OutSel, RC, LdstLen,
87 CryIn, get_csv, single_bit_flags,
88 get_signal_name, default_values)
89 from collections import namedtuple
90 from soc.decoder.power_fields import DecodeFields
91 from soc.decoder.power_fieldsn import SigDecode, SignalBitRange
92
93
94 # key data structure in which the POWER decoder is specified,
95 # in a hierarchical fashion
96 Subdecoder = namedtuple("Subdecoder",
97 ["pattern", # the major pattern to search for (e.g. major opcode)
98 "opcodes", # a dictionary of minor patterns to find
99 "opint", # true => the pattern must not be in "10----11" format
100 "bitsel", # the bits (as a range) against which "pattern" matches
101 "suffix", # shift the opcode down before decoding
102 "subdecoders" # list of further subdecoders for *additional* matches,
103 # *ONLY* after "pattern" has *ALSO* been matched against.
104 ])
105
106
107 class PowerOp:
108 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
109 """
110
111 def __init__(self):
112 self.function_unit = Signal(Function, reset_less=True)
113 self.internal_op = Signal(InternalOp, reset_less=True)
114 self.form = Signal(Form, reset_less=True)
115 self.in1_sel = Signal(In1Sel, reset_less=True)
116 self.in2_sel = Signal(In2Sel, reset_less=True)
117 self.in3_sel = Signal(In3Sel, reset_less=True)
118 self.out_sel = Signal(OutSel, reset_less=True)
119 self.ldst_len = Signal(LdstLen, reset_less=True)
120 self.rc_sel = Signal(RC, reset_less=True)
121 self.cry_in = Signal(CryIn, reset_less=True)
122 for bit in single_bit_flags:
123 name = get_signal_name(bit)
124 setattr(self, name, Signal(reset_less=True, name=name))
125
126 def _eq(self, row=None):
127 if row is None:
128 row = default_values
129 res = [self.function_unit.eq(Function[row['unit']]),
130 self.form.eq(Form[row['form']]),
131 self.internal_op.eq(InternalOp[row['internal op']]),
132 self.in1_sel.eq(In1Sel[row['in1']]),
133 self.in2_sel.eq(In2Sel[row['in2']]),
134 self.in3_sel.eq(In3Sel[row['in3']]),
135 self.out_sel.eq(OutSel[row['out']]),
136 self.ldst_len.eq(LdstLen[row['ldst len']]),
137 self.rc_sel.eq(RC[row['rc']]),
138 self.cry_in.eq(CryIn[row['cry in']]),
139 ]
140 for bit in single_bit_flags:
141 sig = getattr(self, get_signal_name(bit))
142 res.append(sig.eq(int(row.get(bit, 0))))
143 return res
144
145 def eq(self, otherop):
146 res = [self.function_unit.eq(otherop.function_unit),
147 self.form.eq(otherop.form),
148 self.internal_op.eq(otherop.internal_op),
149 self.in1_sel.eq(otherop.in1_sel),
150 self.in2_sel.eq(otherop.in2_sel),
151 self.in3_sel.eq(otherop.in3_sel),
152 self.out_sel.eq(otherop.out_sel),
153 self.rc_sel.eq(otherop.rc_sel),
154 self.ldst_len.eq(otherop.ldst_len),
155 self.cry_in.eq(otherop.cry_in)]
156 for bit in single_bit_flags:
157 sig = getattr(self, get_signal_name(bit))
158 res.append(sig.eq(getattr(otherop, get_signal_name(bit))))
159 return res
160
161 def ports(self):
162 regular = [self.function_unit,
163 self.in1_sel,
164 self.in2_sel,
165 self.in3_sel,
166 self.out_sel,
167 self.ldst_len,
168 self.rc_sel,
169 self.internal_op,
170 self.form]
171 single_bit_ports = [getattr(self, get_signal_name(x))
172 for x in single_bit_flags]
173 return regular + single_bit_ports
174
175
176 class PowerDecoder(Elaboratable):
177 """PowerDecoder - decodes an incoming opcode into the type of operation
178 """
179
180 def __init__(self, width, dec):
181 if not isinstance(dec, list):
182 dec = [dec]
183 self.dec = dec
184 self.opcode_in = Signal(width, reset_less=True)
185
186 self.op = PowerOp()
187 for d in dec:
188 if d.suffix is not None and d.suffix >= width:
189 d.suffix = None
190 self.width = width
191
192 def suffix_mask(self, d):
193 return ((1 << d.suffix) - 1)
194
195 def divide_opcodes(self, d):
196 divided = {}
197 mask = self.suffix_mask(d)
198 print("mask", hex(mask))
199 for row in d.opcodes:
200 opcode = row['opcode']
201 if d.opint and '-' not in opcode:
202 opcode = int(opcode, 0)
203 key = opcode & mask
204 opcode = opcode >> d.suffix
205 if key not in divided:
206 divided[key] = []
207 r = row.copy()
208 r['opcode'] = opcode
209 divided[key].append(r)
210 return divided
211
212 def elaborate(self, platform):
213 m = Module()
214 comb = m.d.comb
215
216 # note: default opcode is "illegal" as this is a combinatorial block
217 # this only works because OP_ILLEGAL=0 and the default (unset) is 0
218
219 # go through the list of CSV decoders first
220 for d in self.dec:
221 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
222 reset_less=True)
223 comb += opcode_switch.eq(self.opcode_in[d.bitsel[0]:d.bitsel[1]])
224 if d.suffix:
225 opcodes = self.divide_opcodes(d)
226 opc_in = Signal(d.suffix, reset_less=True)
227 comb += opc_in.eq(opcode_switch[:d.suffix])
228 # begin the dynamic Switch statement here
229 with m.Switch(opc_in):
230 for key, row in opcodes.items():
231 bitsel = (d.suffix+d.bitsel[0], d.bitsel[1])
232 sd = Subdecoder(pattern=None, opcodes=row,
233 bitsel=bitsel, suffix=None,
234 opint=False, subdecoders=[])
235 subdecoder = PowerDecoder(width=32, dec=sd)
236 setattr(m.submodules, "dec_sub%d" % key, subdecoder)
237 comb += subdecoder.opcode_in.eq(self.opcode_in)
238 # add in the dynamic Case statement here
239 with m.Case(key):
240 comb += self.op.eq(subdecoder.op)
241 else:
242 # TODO: arguments, here (all of them) need to be a list.
243 # a for-loop around the *list* of decoder args.
244 with m.Switch(opcode_switch):
245 self.handle_subdecoders(m, d)
246 for row in d.opcodes:
247 opcode = row['opcode']
248 if d.opint and '-' not in opcode:
249 opcode = int(opcode, 0)
250 if not row['unit']:
251 continue
252 # add in the dynamic Case statement here
253 with m.Case(opcode):
254 comb += self.op._eq(row)
255 return m
256
257 def handle_subdecoders(self, m, d):
258 for dec in d.subdecoders:
259 subdecoder = PowerDecoder(self.width, dec)
260 if isinstance(dec, list): # XXX HACK: take first pattern
261 dec = dec[0]
262 setattr(m.submodules, "dec%d" % dec.pattern, subdecoder)
263 m.d.comb += subdecoder.opcode_in.eq(self.opcode_in)
264 with m.Case(dec.pattern):
265 m.d.comb += self.op.eq(subdecoder.op)
266
267 def ports(self):
268 return [self.opcode_in] + self.op.ports()
269
270
271 class TopPowerDecoder(PowerDecoder):
272 """TopPowerDecoder
273
274 top-level hierarchical decoder for POWER ISA
275 bigendian dynamically switches between big and little endian decoding
276 (reverses byte order). See V3.0B p44 1.11.2
277 """
278
279 def __init__(self, width, dec):
280 PowerDecoder.__init__(self, width, dec)
281 self.fields = df = DecodeFields(SignalBitRange, [self.opcode_in])
282 self.fields.create_specs()
283 self.raw_opcode_in = Signal.like(self.opcode_in, reset_less=True)
284 self.bigendian = Signal(reset_less=True)
285
286 for name, value in self.fields.common_fields.items():
287 sig = Signal(value[0:-1].shape(), reset_less=True, name=name)
288 setattr(self, name, sig)
289
290 # create signals for all field forms
291 self.form_names = forms = self.fields.instrs.keys()
292 self.sigforms = {}
293 for form in forms:
294 fields = self.fields.instrs[form]
295 fk = fields.keys()
296 Fields = namedtuple("Fields", fk)
297 sf = {}
298 for k, value in fields.items():
299 name = "%s_%s" % (form, k)
300 sig = Signal(value[0:-1].shape(), reset_less=True, name=name)
301 sf[k] = sig
302 instr = Fields(**sf)
303 setattr(self, "Form%s" % form, instr)
304 self.sigforms[form] = instr
305
306 def elaborate(self, platform):
307 m = PowerDecoder.elaborate(self, platform)
308 comb = m.d.comb
309 raw_be = self.raw_opcode_in
310 l = []
311 for i in range(0, self.width, 8):
312 l.append(raw_be[i:i+8])
313 l.reverse()
314 raw_le = Cat(*l)
315 comb += self.opcode_in.eq(Mux(self.bigendian, raw_be, raw_le))
316
317 # add all signal from commonly-used fields
318 for name, value in self.fields.common_fields.items():
319 sig = getattr(self, name)
320 comb += sig.eq(value[0:-1])
321
322 # link signals for all field forms
323 forms = self.form_names
324 for form in forms:
325 sf = self.sigforms[form]
326 fields = self.fields.instrs[form]
327 for k, value in fields.items():
328 sig = getattr(sf, k)
329 comb += sig.eq(value[0:-1])
330
331 return m
332
333 def ports(self):
334 return [self.raw_opcode_in, self.bigendian] + PowerDecoder.ports(self)
335
336
337 ####################################################
338 # PRIMARY FUNCTION SPECIFYING THE FULL POWER DECODER
339
340 def create_pdecode():
341 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
342 """
343
344 # minor 19 has extra patterns
345 m19 = []
346 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19.csv"),
347 opint=True, bitsel=(1, 11), suffix=None, subdecoders=[]))
348 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
349 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]))
350
351 # minor opcodes.
352 pminor = [
353 m19,
354 Subdecoder(pattern=30, opcodes=get_csv("minor_30.csv"),
355 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]),
356 Subdecoder(pattern=31, opcodes=get_csv("minor_31.csv"),
357 opint=True, bitsel=(1, 11), suffix=0b00101, subdecoders=[]),
358 Subdecoder(pattern=58, opcodes=get_csv("minor_58.csv"),
359 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
360 Subdecoder(pattern=62, opcodes=get_csv("minor_62.csv"),
361 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
362 ]
363
364 # top level: extra merged with major
365 dec = []
366 opcodes = get_csv("major.csv")
367 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
368 bitsel=(26, 32), suffix=None, subdecoders=pminor))
369 opcodes = get_csv("extra.csv")
370 dec.append(Subdecoder(pattern=None, opint=False, opcodes=opcodes,
371 bitsel=(0, 32), suffix=None, subdecoders=[]))
372
373 return TopPowerDecoder(32, dec)
374
375
376 if __name__ == '__main__':
377 pdecode = create_pdecode()
378 vl = rtlil.convert(pdecode, ports=pdecode.ports())
379 with open("decoder.il", "w") as f:
380 f.write(vl)