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