98912b0d4473605b0ff13a9624b45a5030f534a4
[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, MicrOp,
86 In1Sel, In2Sel, In3Sel, OutSel,
87 RC, LdstLen, LDSTMode, CryIn, get_csv,
88 single_bit_flags, CRInSel,
89 CROutSel, get_signal_name,
90 default_values, insns, asmidx)
91 from soc.decoder.power_fields import DecodeFields
92 from soc.decoder.power_fieldsn import SigDecode, SignalBitRange
93
94
95 # key data structure in which the POWER decoder is specified,
96 # in a hierarchical fashion
97 Subdecoder = namedtuple("Subdecoder",
98 ["pattern", # the major pattern to search for (e.g. major opcode)
99 "opcodes", # a dictionary of minor patterns to find
100 "opint", # true => the pattern must not be in "10----11" format
101 # the bits (as a range) against which "pattern" matches
102 "bitsel",
103 "suffix", # shift the opcode down before decoding
104 "subdecoders" # list of further subdecoders for *additional* matches,
105 # *ONLY* after "pattern" has *ALSO* been matched against.
106 ])
107
108
109 class PowerOp:
110 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
111
112 this is an internal data structure, set up by reading CSV files
113 (which uses _eq to initialise each instance, not eq)
114
115 the "public" API (as far as actual usage as a useful decoder is concerned)
116 is Decode2ToExecute1Type
117 """
118
119 def __init__(self, incl_asm=True):
120 self.function_unit = Signal(Function, reset_less=True)
121 self.internal_op = Signal(MicrOp, reset_less=True)
122 self.form = Signal(Form, reset_less=True)
123 if incl_asm: # for simulator only
124 self.asmcode = Signal(8, reset_less=True)
125 self.in1_sel = Signal(In1Sel, reset_less=True)
126 self.in2_sel = Signal(In2Sel, reset_less=True)
127 self.in3_sel = Signal(In3Sel, reset_less=True)
128 self.out_sel = Signal(OutSel, reset_less=True)
129 self.cr_in = Signal(CRInSel, reset_less=True)
130 self.cr_out = Signal(CROutSel, reset_less=True)
131 self.ldst_len = Signal(LdstLen, reset_less=True)
132 self.upd = Signal(LDSTMode, reset_less=True)
133 self.rc_sel = Signal(RC, reset_less=True)
134 self.cry_in = Signal(CryIn, reset_less=True)
135 for bit in single_bit_flags:
136 name = get_signal_name(bit)
137 setattr(self, name, Signal(reset_less=True, name=name))
138
139 def _eq(self, row=None):
140 if row is None:
141 row = default_values
142 # TODO: this conversion process from a dict to an object
143 # should really be done using e.g. namedtuple and then
144 # call eq not _eq
145 if False: # debugging
146 if row['CR in'] == '1':
147 import pdb
148 pdb.set_trace()
149 print(row)
150 if row['CR out'] == '0':
151 import pdb
152 pdb.set_trace()
153 print(row)
154 print(row)
155 ldst_mode = row['upd']
156 if ldst_mode.isdigit():
157 ldst_mode = LDSTMode(int(ldst_mode))
158 else:
159 ldst_mode = LDSTMode[ldst_mode]
160 res = [self.function_unit.eq(Function[row['unit']]),
161 self.form.eq(Form[row['form']]),
162 self.internal_op.eq(MicrOp[row['internal op']]),
163 self.in1_sel.eq(In1Sel[row['in1']]),
164 self.in2_sel.eq(In2Sel[row['in2']]),
165 self.in3_sel.eq(In3Sel[row['in3']]),
166 self.out_sel.eq(OutSel[row['out']]),
167 self.cr_in.eq(CRInSel[row['CR in']]),
168 self.cr_out.eq(CROutSel[row['CR out']]),
169 self.ldst_len.eq(LdstLen[row['ldst len']]),
170 self.upd.eq(ldst_mode),
171 self.rc_sel.eq(RC[row['rc']]),
172 self.cry_in.eq(CryIn[row['cry in']]),
173 ]
174 if False:
175 print(row.keys())
176 asmcode = row['comment']
177 if hasattr(self, "asmcode") and asmcode in asmidx:
178 res.append(self.asmcode.eq(asmidx[asmcode]))
179 for bit in single_bit_flags:
180 sig = getattr(self, get_signal_name(bit))
181 res.append(sig.eq(int(row.get(bit, 0))))
182 return res
183
184 def eq(self, otherop):
185 res = [self.function_unit.eq(otherop.function_unit),
186 self.form.eq(otherop.form),
187 self.internal_op.eq(otherop.internal_op),
188 self.in1_sel.eq(otherop.in1_sel),
189 self.in2_sel.eq(otherop.in2_sel),
190 self.in3_sel.eq(otherop.in3_sel),
191 self.out_sel.eq(otherop.out_sel),
192 self.cr_in.eq(otherop.cr_in),
193 self.cr_out.eq(otherop.cr_out),
194 self.rc_sel.eq(otherop.rc_sel),
195 self.ldst_len.eq(otherop.ldst_len),
196 self.upd.eq(otherop.upd),
197 self.cry_in.eq(otherop.cry_in)]
198 for bit in single_bit_flags:
199 sig = getattr(self, get_signal_name(bit))
200 res.append(sig.eq(getattr(otherop, get_signal_name(bit))))
201 if hasattr(self, "asmcode"):
202 res.append(self.asmcode.eq(otherop.asmcode))
203 return res
204
205 def ports(self):
206 regular = [self.function_unit,
207 self.in1_sel,
208 self.in2_sel,
209 self.in3_sel,
210 self.out_sel,
211 self.cr_in,
212 self.cr_out,
213 self.ldst_len,
214 self.rc_sel,
215 self.internal_op,
216 self.form]
217 if hasattr(self, "asmcode"):
218 regular.append(self.asmcode)
219 single_bit_ports = [getattr(self, get_signal_name(x))
220 for x in single_bit_flags]
221 return regular + single_bit_ports
222
223
224 class PowerDecoder(Elaboratable):
225 """PowerDecoder - decodes an incoming opcode into the type of operation
226 """
227
228 def __init__(self, width, dec):
229 if not isinstance(dec, list):
230 dec = [dec]
231 self.dec = dec
232 self.opcode_in = Signal(width, reset_less=True)
233
234 self.op = PowerOp()
235 for d in dec:
236 if d.suffix is not None and d.suffix >= width:
237 d.suffix = None
238 self.width = width
239
240 def suffix_mask(self, d):
241 return ((1 << d.suffix) - 1)
242
243 def divide_opcodes(self, d):
244 divided = {}
245 mask = self.suffix_mask(d)
246 print("mask", hex(mask))
247 for row in d.opcodes:
248 opcode = row['opcode']
249 if d.opint and '-' not in opcode:
250 opcode = int(opcode, 0)
251 key = opcode & mask
252 opcode = opcode >> d.suffix
253 if key not in divided:
254 divided[key] = []
255 r = row.copy()
256 r['opcode'] = opcode
257 divided[key].append(r)
258 return divided
259
260 def elaborate(self, platform):
261 m = Module()
262 comb = m.d.comb
263
264 # note: default opcode is "illegal" as this is a combinatorial block
265 # this only works because OP_ILLEGAL=0 and the default (unset) is 0
266
267 # go through the list of CSV decoders first
268 for d in self.dec:
269 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
270 reset_less=True)
271 comb += opcode_switch.eq(self.opcode_in[d.bitsel[0]:d.bitsel[1]])
272 if d.suffix:
273 opcodes = self.divide_opcodes(d)
274 opc_in = Signal(d.suffix, reset_less=True)
275 comb += opc_in.eq(opcode_switch[:d.suffix])
276 # begin the dynamic Switch statement here
277 with m.Switch(opc_in):
278 for key, row in opcodes.items():
279 bitsel = (d.suffix+d.bitsel[0], d.bitsel[1])
280 sd = Subdecoder(pattern=None, opcodes=row,
281 bitsel=bitsel, suffix=None,
282 opint=False, subdecoders=[])
283 subdecoder = PowerDecoder(width=32, dec=sd)
284 setattr(m.submodules, "dec_sub%d" % key, subdecoder)
285 comb += subdecoder.opcode_in.eq(self.opcode_in)
286 # add in the dynamic Case statement here
287 with m.Case(key):
288 comb += self.op.eq(subdecoder.op)
289 else:
290 # TODO: arguments, here (all of them) need to be a list.
291 # a for-loop around the *list* of decoder args.
292 with m.Switch(opcode_switch):
293 self.handle_subdecoders(m, d)
294 for row in d.opcodes:
295 opcode = row['opcode']
296 if d.opint and '-' not in opcode:
297 opcode = int(opcode, 0)
298 if not row['unit']:
299 continue
300 # add in the dynamic Case statement here
301 with m.Case(opcode):
302 comb += self.op._eq(row)
303 return m
304
305 def handle_subdecoders(self, m, d):
306 for dec in d.subdecoders:
307 subdecoder = PowerDecoder(self.width, dec)
308 if isinstance(dec, list): # XXX HACK: take first pattern
309 dec = dec[0]
310 setattr(m.submodules, "dec%d" % dec.pattern, subdecoder)
311 m.d.comb += subdecoder.opcode_in.eq(self.opcode_in)
312 with m.Case(dec.pattern):
313 m.d.comb += self.op.eq(subdecoder.op)
314
315 def ports(self):
316 return [self.opcode_in] + self.op.ports()
317
318
319 class TopPowerDecoder(PowerDecoder):
320 """TopPowerDecoder
321
322 top-level hierarchical decoder for POWER ISA
323 bigendian dynamically switches between big and little endian decoding
324 (reverses byte order). See V3.0B p44 1.11.2
325 """
326
327 def __init__(self, width, dec):
328 PowerDecoder.__init__(self, width, dec)
329 self.fields = df = DecodeFields(SignalBitRange, [self.opcode_in])
330 self.fields.create_specs()
331 self.raw_opcode_in = Signal.like(self.opcode_in, reset_less=True)
332 self.bigendian = Signal(reset_less=True)
333
334 for name, value in self.fields.common_fields.items():
335 sig = Signal(value[0:-1].shape(), reset_less=True, name=name)
336 setattr(self, name, sig)
337
338 # create signals for all field forms
339 self.form_names = forms = self.fields.instrs.keys()
340 self.sigforms = {}
341 for form in forms:
342 fields = self.fields.instrs[form]
343 fk = fields.keys()
344 Fields = namedtuple("Fields", fk)
345 sf = {}
346 for k, value in fields.items():
347 name = "%s_%s" % (form, k)
348 sig = Signal(value[0:-1].shape(), reset_less=True, name=name)
349 sf[k] = sig
350 instr = Fields(**sf)
351 setattr(self, "Form%s" % form, instr)
352 self.sigforms[form] = instr
353
354 def elaborate(self, platform):
355 m = PowerDecoder.elaborate(self, platform)
356 comb = m.d.comb
357 # raw opcode in assumed to be in LE order: byte-reverse it to get BE
358 raw_le = self.raw_opcode_in
359 l = []
360 for i in range(0, self.width, 8):
361 l.append(raw_le[i:i+8])
362 l.reverse()
363 raw_be = Cat(*l)
364 comb += self.opcode_in.eq(Mux(self.bigendian, raw_be, raw_le))
365
366 # add all signal from commonly-used fields
367 for name, value in self.fields.common_fields.items():
368 sig = getattr(self, name)
369 comb += sig.eq(value[0:-1])
370
371 # link signals for all field forms
372 forms = self.form_names
373 for form in forms:
374 sf = self.sigforms[form]
375 fields = self.fields.instrs[form]
376 for k, value in fields.items():
377 sig = getattr(sf, k)
378 comb += sig.eq(value[0:-1])
379
380 return m
381
382 def ports(self):
383 return [self.raw_opcode_in, self.bigendian] + PowerDecoder.ports(self)
384
385
386 ####################################################
387 # PRIMARY FUNCTION SPECIFYING THE FULL POWER DECODER
388
389 def create_pdecode():
390 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
391 """
392
393 # minor 19 has extra patterns
394 m19 = []
395 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19.csv"),
396 opint=True, bitsel=(1, 11), suffix=None, subdecoders=[]))
397 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
398 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]))
399
400 # minor opcodes.
401 pminor = [
402 m19,
403 Subdecoder(pattern=30, opcodes=get_csv("minor_30.csv"),
404 opint=True, bitsel=(1, 5), suffix=None, subdecoders=[]),
405 Subdecoder(pattern=31, opcodes=get_csv("minor_31.csv"),
406 opint=True, bitsel=(1, 11), suffix=0b00101, subdecoders=[]),
407 Subdecoder(pattern=58, opcodes=get_csv("minor_58.csv"),
408 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
409 Subdecoder(pattern=62, opcodes=get_csv("minor_62.csv"),
410 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
411 ]
412
413 # top level: extra merged with major
414 dec = []
415 opcodes = get_csv("major.csv")
416 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
417 bitsel=(26, 32), suffix=None, subdecoders=pminor))
418 opcodes = get_csv("extra.csv")
419 dec.append(Subdecoder(pattern=None, opint=False, opcodes=opcodes,
420 bitsel=(0, 32), suffix=None, subdecoders=[]))
421
422 return TopPowerDecoder(32, dec)
423
424
425 if __name__ == '__main__':
426 pdecode = create_pdecode()
427 vl = rtlil.convert(pdecode, ports=pdecode.ports())
428 with open("decoder.il", "w") as f:
429 f.write(vl)