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