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