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