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