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