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