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