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