8d7fcfa921b1dbbee1e5dc65303338818861bd16
[openpower-isa.git] / src / openpower / decoder / power_decoder.py
1 """Cascading Power ISA Decoder
2
3 License: LGPLv3+
4
5 # Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6 # Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
7
8 This module uses CSV tables in a hierarchical/peer cascading fashion,
9 to create a multi-level instruction decoder by recognising appropriate
10 patterns. The output is a wide, flattened (1-level) series of bitfields,
11 suitable for a simple RISC engine.
12
13 This is based on Anton Blanchard's excellent microwatt work:
14 https://github.com/antonblanchard/microwatt/blob/master/decode1.vhdl
15
16 The basic principle is that the python code does the heavy lifting
17 (reading the CSV files, constructing the hierarchy), creating the HDL
18 AST with for-loops generating switch-case statements.
19
20 Where "normal" HDL would do this, in laborious excruciating detail:
21
22 switch (opcode & major_mask_bits):
23 case opcode_2: decode_opcode_2()
24 case opcode_19:
25 switch (opcode & minor_19_mask_bits)
26 case minor_opcode_19_operation_X:
27 case minor_opcode_19_operation_y:
28
29 we take *full* advantage of the decoupling between python and the
30 nmigen AST data structure, to do this:
31
32 with m.Switch(opcode & self.mask):
33 for case_bitmask in subcases:
34 with m.If(opcode & case_bitmask): {do_something}
35
36 this includes specifying the information sufficient to perform subdecoding.
37
38 create_pdecode()
39
40 the full hierarchical tree for decoding POWER9 is specified here
41 subsetting is possible by specifying col_subset (row_subset TODO)
42
43 PowerDecoder
44
45 takes a *list* of CSV files with an associated bit-range that it
46 is requested to match against the "opcode" row of the CSV file.
47 This pattern can be either an integer, a binary number, *or* a
48 wildcard nmigen Case pattern of the form "001--1-100".
49
50 Subdecoders
51
52 these are *additional* cases with further decoding. The "pattern"
53 argument is specified as one of the Case statements (a peer of the
54 opcode row in the CSV file), and thus further fields of the opcode
55 may be decoded giving increasing levels of detail.
56
57 Top Level:
58
59 [ (extra.csv: bit-fields entire 32-bit range
60 opcode -> matches
61 000000---------------01000000000 -> ILLEGAL instruction
62 01100000000000000000000000000000 -> SIM_CONFIG instruction
63 ................................ ->
64 ),
65 (major.csv: first 6 bits ONLY
66 opcode -> matches
67 001100 -> ALU,OP_ADD (add)
68 001101 -> ALU,OP_ADD (another type of add)
69 ...... -> ...
70 ...... -> ...
71 subdecoders:
72 001011 this must match *MAJOR*.CSV
73 [ (minor_19.csv: bits 21 through 30 inclusive:
74 opcode -> matches
75 0b0000000000 -> ALU,OP_MCRF
76 ............ -> ....
77 ),
78 (minor_19_00000.csv: bits 21 through 25 inclusive:
79 opcode -> matches
80 0b00010 -> ALU,add_pcis
81 )
82 ]
83 ),
84 ]
85
86
87 """
88
89 import gc
90 from collections import namedtuple
91 from nmigen import Module, Elaboratable, Signal, Cat, Mux
92 from nmigen.cli import rtlil
93 from openpower.decoder.power_enums import (Function, Form, MicrOp,
94 In1Sel, In2Sel, In3Sel, OutSel,
95 SVEXTRA, SVEtype, SVPtype, # Simple-V
96 RC, LdstLen, LDSTMode, CryIn,
97 single_bit_flags, CRInSel,
98 CROutSel, get_signal_name,
99 default_values, insns, asmidx)
100 from openpower.decoder.power_fields import DecodeFields
101 from openpower.decoder.power_fieldsn import SigDecode, SignalBitRange
102 from openpower.decoder.power_svp64 import SVP64RM
103
104 from openpower.util import log
105
106 # key data structure in which the POWER decoder is specified,
107 # in a hierarchical fashion
108 Subdecoder = namedtuple( # fix autoformatter
109 "Subdecoder",
110 ["pattern", # the major pattern to search for (e.g. major opcode)
111 "opcodes", # a dictionary of minor patterns to find
112 "opint", # true => the pattern must not be in "10----11" format
113 # the bits (as a range) against which "pattern" matches
114 "bitsel",
115 "suffix", # shift the opcode down before decoding
116 "subdecoders" # list of further subdecoders for *additional* matches,
117 # *ONLY* after "pattern" has *ALSO* been matched against.
118 ])
119
120 power_op_types = {'function_unit': Function,
121 'internal_op': MicrOp,
122 'form': Form,
123 'asmcode': 8,
124 'SV_Etype': SVEtype,
125 'SV_Ptype': SVPtype,
126 'in1_sel': In1Sel,
127 'in2_sel': In2Sel,
128 'in3_sel': In3Sel,
129 'out_sel': OutSel,
130 'cr_in': CRInSel,
131 'cr_out': CROutSel,
132 'sv_in1': SVEXTRA,
133 'sv_in2': SVEXTRA,
134 'sv_in3': SVEXTRA,
135 'sv_out': SVEXTRA,
136 'sv_out2': SVEXTRA,
137 'sv_cr_in': SVEXTRA,
138 'sv_cr_out': SVEXTRA,
139 'ldst_len': LdstLen,
140 'upd': LDSTMode,
141 'rc_sel': RC,
142 'cry_in': CryIn
143 }
144
145 power_op_csvmap = {'function_unit': 'unit',
146 'form': 'form',
147 'internal_op': 'internal op',
148 'in1_sel': 'in1',
149 'in2_sel': 'in2',
150 'in3_sel': 'in3',
151 'out_sel': 'out',
152 'sv_in1': 'sv_in1',
153 'sv_in2': 'sv_in2',
154 'sv_in3': 'sv_in3',
155 'sv_out': 'sv_out',
156 'sv_out2': 'sv_out2',
157 'sv_cr_in': 'sv_cr_in',
158 'sv_cr_out': 'sv_cr_out',
159 'SV_Etype': 'SV_Etype',
160 'SV_Ptype': 'SV_Ptype',
161 'cr_in': 'CR in',
162 'cr_out': 'CR out',
163 'ldst_len': 'ldst len',
164 'upd': 'upd',
165 'rc_sel': 'rc',
166 'cry_in': 'cry in',
167 }
168
169
170 def get_pname(field, pname):
171 if pname is None:
172 return field
173 return "%s_%s" % (pname, field)
174
175
176 class PowerOp:
177 """PowerOp - a dynamic class that stores (subsets of) CSV rows of data
178 about a PowerISA instruction. this is a "micro-code" expanded format
179 which generates an awful lot of wires, hence the subsetting
180 """
181
182 def __init__(self, incl_asm=True, name=None, subset=None, fields=None):
183 self.name = name
184 self.subset = subset
185 if fields is not None:
186 for k, v in fields.items():
187 setattr(self, k, v)
188 return
189 debug_report = set()
190 fields = set()
191 for field, ptype in power_op_types.items():
192 fields.add(field)
193 if subset and field not in subset:
194 continue
195 fname = get_pname(field, name)
196 setattr(self, field, Signal(ptype, reset_less=True, name=fname))
197 debug_report.add(field)
198 for bit in single_bit_flags:
199 field = get_signal_name(bit)
200 fields.add(field)
201 if subset and field not in subset:
202 continue
203 debug_report.add(field)
204 fname = get_pname(field, name)
205 setattr(self, field, Signal(reset_less=True, name=fname))
206 self._fields = fields
207 # comment out, bit too high debug level
208 #print("PowerOp debug", name, debug_report)
209 #print(" fields", fields)
210
211 @staticmethod
212 def like(other):
213 """PowerOp.like: creates a duplicate of a given PowerOp instance
214 """
215 fields = {}
216 for fname in other._fields:
217 sig = getattr(other, fname, None)
218 if sig is not None:
219 fields[fname] = sig.__class__.like(sig)
220 return PowerOp(subset=other.subset, fields=fields)
221
222 def _eq(self, row=None):
223 if row is None:
224 row = default_values
225 # TODO: this conversion process from a dict to an object
226 # should really be done using e.g. namedtuple and then
227 # call eq not _eq
228 if False: # debugging
229 if row['CR in'] == '1':
230 import pdb
231 pdb.set_trace()
232 log(row)
233 if row['CR out'] == '0':
234 import pdb
235 pdb.set_trace()
236 log(row)
237 log(row)
238 ldst_mode = row['upd']
239 if ldst_mode.isdigit():
240 row['upd'] = int(ldst_mode)
241 res = []
242 for field, ptype in power_op_types.items():
243 if not hasattr(self, field):
244 continue
245 if field not in power_op_csvmap:
246 continue
247 csvname = power_op_csvmap[field]
248 # log(field, ptype, csvname, row)
249 val = row[csvname]
250 if csvname == 'upd' and isinstance(val, int): # LDSTMode different
251 val = ptype(val)
252 else:
253 val = ptype[val]
254 res.append(getattr(self, field).eq(val))
255 if False:
256 log(row.keys())
257 asmcode = row['comment']
258 # process the comment field, strip out "equals" for FP
259 if "=" in asmcode:
260 asmcode = asmcode.split("=")[-1]
261 log ("asmcode stripping =", asmcode,
262 asmcode in asmidx, hasattr(self, "asmcode"))
263 if hasattr(self, "asmcode") and asmcode in asmidx:
264 res.append(self.asmcode.eq(asmidx[asmcode]))
265 for bit in single_bit_flags:
266 field = get_signal_name(bit)
267 if not hasattr(self, field):
268 continue
269 sig = getattr(self, field)
270 res.append(sig.eq(int(row.get(bit, 0))))
271 return res
272
273 def _get_eq(self, res, field, otherop):
274 copyfrom = getattr(otherop, field, None)
275 copyto = getattr(self, field, None)
276 if copyfrom is not None and copyto is not None:
277 res.append(copyto.eq(copyfrom))
278
279 def eq(self, otherop):
280 res = []
281 for field in power_op_types.keys():
282 self._get_eq(res, field, otherop)
283 for bit in single_bit_flags:
284 self._get_eq(res, get_signal_name(bit), otherop)
285 return res
286
287 def ports(self):
288 res = []
289 for field in power_op_types.keys():
290 if hasattr(self, field):
291 res.append(getattr(self, field))
292 if hasattr(self, "asmcode"):
293 res.append(self.asmcode)
294 for field in single_bit_flags:
295 field = get_signal_name(field)
296 if hasattr(self, field):
297 res.append(getattr(self, field))
298 return res
299
300
301 class PowerDecoder(Elaboratable):
302 """PowerDecoder - decodes an incoming opcode into the type of operation
303
304 this is a recursive algorithm, creating Switch statements that can
305 have further match-and-decode on other parts of the opcode field before
306 finally landing at a "this CSV entry details gets returned" thing.
307
308 the complicating factor is the row and col subsetting. column subsetting
309 dynamically chooses only the CSV columns requested, whilst row subsetting
310 allows a function to be called on the row to determine if the Case
311 statement is to be generated for that row. this not only generates
312 completely different Decoders, it also means that some sub-decoders
313 will turn up blank (empty switch statements). if that happens we do
314 not want the parent to include a Mux for an entirely blank switch statement
315 so we have to store the switch/case statements in a tree, and
316 post-analyse it.
317
318 the reason for the tree is because elaborate can only be called *after*
319 the constructor is called. all quite messy.
320 """
321
322 def __init__(self, width, dec, name=None, col_subset=None, row_subset=None):
323 self.actually_does_something = False
324 self.pname = name
325 self.col_subset = col_subset
326 self.row_subsetfn = row_subset
327 if not isinstance(dec, list):
328 dec = [dec]
329 self.dec = dec
330 self.opcode_in = Signal(width, reset_less=True)
331
332 self.op = PowerOp(name=name, subset=col_subset)
333 for d in dec:
334 if d.suffix is not None and d.suffix >= width:
335 d.suffix = None
336 self.width = width
337
338 def suffix_mask(self, d):
339 return ((1 << d.suffix) - 1)
340
341 def divide_opcodes(self, d):
342 divided = {}
343 mask = self.suffix_mask(d)
344 #print("mask", hex(mask))
345 for row in d.opcodes:
346 opcode = row['opcode']
347 if d.opint and '-' not in opcode:
348 opcode = int(opcode, 0)
349 key = opcode & mask
350 opcode = opcode >> d.suffix
351 if key not in divided:
352 divided[key] = []
353 r = row.copy()
354 r['opcode'] = opcode
355 divided[key].append(r)
356 return divided
357
358 def tree_analyse(self):
359 self.decs = decs = []
360 self.submodules = submodules = {}
361 self.eqs = eqs = []
362
363 # go through the list of CSV decoders first
364 for d in self.dec:
365 cases = []
366 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
367 reset_less=True)
368 eq = []
369 case_does_something = False
370 look_for = self.opcode_in[d.bitsel[0]:d.bitsel[1]]
371 eq.append(opcode_switch.eq(look_for))
372 if d.suffix:
373 opcodes = self.divide_opcodes(d)
374 opc_in = Signal(d.suffix, reset_less=True)
375 eq.append(opc_in.eq(opcode_switch[:d.suffix]))
376 # begin the dynamic Switch statement here
377 switch_case = {}
378 cases.append([opc_in, switch_case])
379 sub_eqs = []
380 for key, row in opcodes.items():
381 bitsel = (d.suffix+d.bitsel[0], d.bitsel[1])
382 sd = Subdecoder(pattern=None, opcodes=row,
383 bitsel=bitsel, suffix=None,
384 opint=False, subdecoders=[])
385 mname = get_pname("dec_sub%d" % key, self.pname)
386 subdecoder = PowerDecoder(width=32, dec=sd,
387 name=mname,
388 col_subset=self.col_subset,
389 row_subset=self.row_subsetfn)
390 if not subdecoder.tree_analyse():
391 del subdecoder
392 continue
393 submodules[mname] = subdecoder
394 sub_eqs.append(subdecoder.opcode_in.eq(self.opcode_in))
395 # add in the dynamic Case statement here
396 switch_case[key] = self.op.eq(subdecoder.op)
397 self.actually_does_something = True
398 case_does_something = True
399 if case_does_something:
400 eq += sub_eqs
401 else:
402 # TODO: arguments, here (all of them) need to be a list.
403 # a for-loop around the *list* of decoder args.
404 switch_case = {}
405 cases.append([opcode_switch, switch_case])
406 seqs = self.handle_subdecoders(switch_case, submodules, d)
407 if seqs:
408 case_does_something = True
409 eq += seqs
410 for row in d.opcodes:
411 opcode = row['opcode']
412 if d.opint and '-' not in opcode:
413 opcode = int(opcode, 0)
414 if not row['unit']:
415 continue
416 if self.row_subsetfn:
417 if not self.row_subsetfn(opcode, row):
418 continue
419 # add in the dynamic Case statement here
420 switch_case[opcode] = self.op._eq(row)
421 self.actually_does_something = True
422 case_does_something = True
423
424 if cases:
425 decs.append(cases)
426 if case_does_something:
427 eqs += eq
428 #print("submodule eqs", self.pname, eq)
429
430 #print("submodules", self.pname, submodules)
431
432 gc.collect()
433 return self.actually_does_something
434
435 def handle_subdecoders(self, switch_case, submodules, d):
436 eqs = []
437 for dlist in d.subdecoders:
438 if not isinstance(dlist, list): # XXX HACK: take first pattern
439 dlist = [dlist]
440 for dec in dlist:
441 #print("subdec", dec.pattern, self.pname)
442 mname = get_pname("dec%d" % dec.pattern, self.pname)
443 if mname in submodules:
444 # sigh, HACK...
445 mname += "_1"
446 assert mname not in submodules
447 subdecoder = PowerDecoder(self.width, dec,
448 name=mname,
449 col_subset=self.col_subset,
450 row_subset=self.row_subsetfn)
451 log ("subdecoder", mname, subdecoder)
452 if not subdecoder.tree_analyse(): # doesn't do anything
453 log ("analysed, DELETING", mname)
454 del subdecoder
455 continue # skip
456 submodules[mname] = subdecoder
457 eqs.append(subdecoder.opcode_in.eq(self.opcode_in))
458 switch_case[dec.pattern] = self.op.eq(subdecoder.op)
459 self.actually_does_something = True
460
461 return eqs
462
463 def elaborate(self, platform):
464 #print("decoder elaborate", self.pname, self.submodules)
465 m = Module()
466 comb = m.d.comb
467
468 comb += self.eqs
469
470 for mname, subdecoder in self.submodules.items():
471 setattr(m.submodules, mname, subdecoder)
472
473 for switch_case in self.decs:
474 for (switch, cases) in switch_case:
475 with m.Switch(switch):
476 for key, eqs in cases.items():
477 with m.Case(key):
478 comb += eqs
479 return m
480
481 def ports(self):
482 return [self.opcode_in] + self.op.ports()
483
484
485 class TopPowerDecoder(PowerDecoder):
486 """TopPowerDecoder
487
488 top-level hierarchical decoder for POWER ISA
489 bigendian dynamically switches between big and little endian decoding
490 (reverses byte order). See V3.0B p44 1.11.2
491 """
492
493 def __init__(self, width, dec, name=None, col_subset=None, row_subset=None):
494 PowerDecoder.__init__(self, width, dec, name, col_subset, row_subset)
495 self.fields = df = DecodeFields(SignalBitRange, [self.opcode_in])
496 self.fields.create_specs()
497 self.raw_opcode_in = Signal.like(self.opcode_in, reset_less=True)
498 self.bigendian = Signal(reset_less=True)
499
500 for fname, value in self.fields.common_fields.items():
501 signame = get_pname(fname, name)
502 sig = Signal(value[0:-1].shape(), reset_less=True, name=signame)
503 setattr(self, fname, sig)
504
505 # create signals for all field forms
506 forms = self.form_names
507 self.sigforms = {}
508 for form in forms:
509 fields = self.fields.instrs[form]
510 fk = fields.keys()
511 Fields = namedtuple("Fields", fk)
512 sf = {}
513 for k, value in fields.items():
514 fname = "%s_%s" % (form, k)
515 sig = Signal(value[0:-1].shape(), reset_less=True, name=fname)
516 sf[k] = sig
517 instr = Fields(**sf)
518 setattr(self, "Form%s" % form, instr)
519 self.sigforms[form] = instr
520
521 self.tree_analyse()
522
523 @property
524 def form_names(self):
525 return self.fields.instrs.keys()
526
527 def elaborate(self, platform):
528 m = PowerDecoder.elaborate(self, platform)
529 comb = m.d.comb
530 # sigh duplicated in SVP64PowerDecoder
531 # raw opcode in assumed to be in LE order: byte-reverse it to get BE
532 raw_le = self.raw_opcode_in
533 l = []
534 for i in range(0, self.width, 8):
535 l.append(raw_le[i:i+8])
536 l.reverse()
537 raw_be = Cat(*l)
538 comb += self.opcode_in.eq(Mux(self.bigendian, raw_be, raw_le))
539
540 # add all signal from commonly-used fields
541 for fname, value in self.fields.common_fields.items():
542 sig = getattr(self, fname)
543 comb += sig.eq(value[0:-1])
544
545 # link signals for all field forms
546 forms = self.form_names
547 for form in forms:
548 sf = self.sigforms[form]
549 fields = self.fields.instrs[form]
550 for k, value in fields.items():
551 sig = getattr(sf, k)
552 comb += sig.eq(value[0:-1])
553
554 return m
555
556 def ports(self):
557 return [self.raw_opcode_in, self.bigendian] + PowerDecoder.ports(self)
558
559
560 #############################################################
561 # PRIMARY FUNCTION SPECIFYING ALTERNATIVE SVP64 POWER DECODER
562
563 def create_pdecode_svp64_ldst(name=None, col_subset=None, row_subset=None,
564 include_fp=False):
565 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
566
567 subsetting of the PowerOp decoding is possible by setting col_subset
568 """
569 log ("create_pdecode_svp64_ldst", name, col_subset, row_subset, include_fp)
570
571 # some alteration to the CSV files is required for SV so we use
572 # a class to do it
573 isa = SVP64RM()
574 get_csv = isa.get_svp64_csv
575
576 # minor opcodes.
577 pminor = [
578 Subdecoder(pattern=58, opcodes=get_csv("svldst_minor_58.csv"),
579 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
580 # nope - needs 4-in regs
581 #Subdecoder(pattern=62, opcodes=get_csv("svldst_minor_62.csv"),
582 # opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
583 ]
584
585 # FP 63L/H decoders. TODO: move mffsfamily to separate subdecoder
586 if False and include_fp:
587 pminor.append(
588 Subdecoder(pattern=63, opcodes=get_csv("minor_63.csv"),
589 opint=False, bitsel=(1, 11), suffix=None,
590 subdecoders=[]),
591 )
592 pminor.append(
593 Subdecoder(pattern=59, opcodes=get_csv("minor_59.csv"),
594 opint=False, bitsel=(1, 11), suffix=None,
595 subdecoders=[]),
596 )
597
598 # top level: extra merged with major
599 dec = []
600 opcodes = get_csv("svldst_major.csv")
601 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
602 bitsel=(26, 32), suffix=None, subdecoders=pminor))
603
604 return TopPowerDecoder(32, dec, name=name, col_subset=col_subset,
605 row_subset=row_subset)
606
607
608 ####################################################
609 # PRIMARY FUNCTION SPECIFYING THE FULL POWER DECODER
610
611 def create_pdecode(name=None, col_subset=None, row_subset=None,
612 include_fp=False):
613 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
614
615 subsetting of the PowerOp decoding is possible by setting col_subset
616 """
617 log ("create_pdecode", name, col_subset, row_subset, include_fp)
618
619 # some alteration to the CSV files is required for SV so we use
620 # a class to do it
621 isa = SVP64RM()
622 get_csv = isa.get_svp64_csv
623
624 # minor 19 has extra patterns
625 m19 = []
626 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19.csv"),
627 opint=True, bitsel=(1, 11), suffix=None,
628 subdecoders=[]))
629 # XXX problem with sub-decoders (can only handle one),
630 # sort this another time
631 #m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
632 # opint=True, bitsel=(1, 6), suffix=None,
633 # subdecoders=[]))
634
635 # minor opcodes.
636 pminor = [
637 m19,
638 Subdecoder(pattern=30, opcodes=get_csv("minor_30.csv"),
639 opint=True, bitsel=(1, 5), suffix=None, subdecoders=[]),
640 Subdecoder(pattern=31, opcodes=get_csv("minor_31.csv"),
641 opint=True, bitsel=(1, 11), suffix=0b00101, subdecoders=[]),
642 Subdecoder(pattern=58, opcodes=get_csv("minor_58.csv"),
643 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
644 Subdecoder(pattern=62, opcodes=get_csv("minor_62.csv"),
645 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
646 Subdecoder(pattern=22, opcodes=get_csv("minor_22.csv"),
647 opint=True, bitsel=(1, 5), suffix=None, subdecoders=[]),
648 ]
649
650 # FP 63L/H decoders. TODO: move mffsfamily to separate subdecoder
651 if include_fp:
652 pminor.append(
653 Subdecoder(pattern=63, opcodes=get_csv("minor_63.csv"),
654 opint=False, bitsel=(1, 11), suffix=None,
655 subdecoders=[]),
656 )
657 pminor.append(
658 Subdecoder(pattern=59, opcodes=get_csv("minor_59.csv"),
659 opint=False, bitsel=(1, 11), suffix=None,
660 subdecoders=[]),
661 )
662
663 # top level: extra merged with major
664 dec = []
665 opcodes = get_csv("major.csv")
666 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
667 bitsel=(26, 32), suffix=None, subdecoders=pminor))
668 opcodes = get_csv("extra.csv")
669 dec.append(Subdecoder(pattern=None, opint=False, opcodes=opcodes,
670 bitsel=(0, 32), suffix=None, subdecoders=[]))
671
672 return TopPowerDecoder(32, dec, name=name, col_subset=col_subset,
673 row_subset=row_subset)
674
675
676 if __name__ == '__main__':
677
678 if True:
679 # row subset
680
681 def rowsubsetfn(opcode, row):
682 log("row_subset", opcode, row)
683 return row['unit'] == 'FPU'
684
685 pdecode = create_pdecode(name="rowsub",
686 col_subset={'opcode', 'function_unit',
687 'form'},
688 row_subset=rowsubsetfn,
689 include_fp=True)
690 vl = rtlil.convert(pdecode, ports=pdecode.ports())
691 with open("row_subset_decoder.il", "w") as f:
692 f.write(vl)
693
694 # col subset
695
696 pdecode = create_pdecode(name="fusubset", col_subset={'function_unit'})
697 vl = rtlil.convert(pdecode, ports=pdecode.ports())
698 with open("col_subset_decoder.il", "w") as f:
699 f.write(vl)
700
701 # full decoder
702 pdecode = create_pdecode(include_fp=True)
703 vl = rtlil.convert(pdecode, ports=pdecode.ports())
704 with open("decoder.il", "w") as f:
705 f.write(vl)
706
707 # full SVP64 decoder
708 pdecode = create_pdecode_svp64_ldst(include_fp=True)
709 vl = rtlil.convert(pdecode, ports=pdecode.ports())
710 with open("decoder_svp64.il", "w") as f:
711 f.write(vl)