1682941e1047afd5d442a904277aa013c29729ba
[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:
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 fields = {}
214 for fname in other._fields:
215 sig = getattr(other, fname)
216 fields[fname] = sig.__class__.like(sig)
217 return PowerOp(subset=other.subset, fields=fields)
218
219 def _eq(self, row=None):
220 if row is None:
221 row = default_values
222 # TODO: this conversion process from a dict to an object
223 # should really be done using e.g. namedtuple and then
224 # call eq not _eq
225 if False: # debugging
226 if row['CR in'] == '1':
227 import pdb
228 pdb.set_trace()
229 log(row)
230 if row['CR out'] == '0':
231 import pdb
232 pdb.set_trace()
233 log(row)
234 log(row)
235 ldst_mode = row['upd']
236 if ldst_mode.isdigit():
237 row['upd'] = int(ldst_mode)
238 res = []
239 for field, ptype in power_op_types.items():
240 if not hasattr(self, field):
241 continue
242 if field not in power_op_csvmap:
243 continue
244 csvname = power_op_csvmap[field]
245 # log(field, ptype, csvname, row)
246 val = row[csvname]
247 if csvname == 'upd' and isinstance(val, int): # LDSTMode different
248 val = ptype(val)
249 else:
250 val = ptype[val]
251 res.append(getattr(self, field).eq(val))
252 if False:
253 log(row.keys())
254 asmcode = row['comment']
255 # process the comment field, strip out "equals" for FP
256 if "=" in asmcode:
257 asmcode = asmcode.split("=")[-1]
258 log ("asmcode stripping =", asmcode,
259 asmcode in asmidx, hasattr(self, "asmcode"))
260 if hasattr(self, "asmcode") and asmcode in asmidx:
261 res.append(self.asmcode.eq(asmidx[asmcode]))
262 for bit in single_bit_flags:
263 field = get_signal_name(bit)
264 if not hasattr(self, field):
265 continue
266 sig = getattr(self, field)
267 res.append(sig.eq(int(row.get(bit, 0))))
268 return res
269
270 def _get_eq(self, res, field, otherop):
271 copyfrom = getattr(otherop, field, None)
272 copyto = getattr(self, field, None)
273 if copyfrom is not None and copyto is not None:
274 res.append(copyto.eq(copyfrom))
275
276 def eq(self, otherop):
277 res = []
278 for field in power_op_types.keys():
279 self._get_eq(res, field, otherop)
280 for bit in single_bit_flags:
281 self._get_eq(res, get_signal_name(bit), otherop)
282 return res
283
284 def ports(self):
285 res = []
286 for field in power_op_types.keys():
287 if hasattr(self, field):
288 res.append(getattr(self, field))
289 if hasattr(self, "asmcode"):
290 res.append(self.asmcode)
291 for field in single_bit_flags:
292 field = get_signal_name(field)
293 if hasattr(self, field):
294 res.append(getattr(self, field))
295 return res
296
297
298 class PowerDecoder(Elaboratable):
299 """PowerDecoder - decodes an incoming opcode into the type of operation
300
301 this is a recursive algorithm, creating Switch statements that can
302 have further match-and-decode on other parts of the opcode field before
303 finally landing at a "this CSV entry details gets returned" thing.
304
305 the complicating factor is the row and col subsetting. column subsetting
306 dynamically chooses only the CSV columns requested, whilst row subsetting
307 allows a function to be called on the row to determine if the Case
308 statement is to be generated for that row. this not only generates
309 completely different Decoders, it also means that some sub-decoders
310 will turn up blank (empty switch statements). if that happens we do
311 not want the parent to include a Mux for an entirely blank switch statement
312 so we have to store the switch/case statements in a tree, and
313 post-analyse it.
314
315 the reason for the tree is because elaborate can only be called *after*
316 the constructor is called. all quite messy.
317 """
318
319 def __init__(self, width, dec, name=None, col_subset=None, row_subset=None):
320 self.actually_does_something = False
321 self.pname = name
322 self.col_subset = col_subset
323 self.row_subsetfn = row_subset
324 if not isinstance(dec, list):
325 dec = [dec]
326 self.dec = dec
327 self.opcode_in = Signal(width, reset_less=True)
328
329 self.op = PowerOp(name=name, subset=col_subset)
330 for d in dec:
331 if d.suffix is not None and d.suffix >= width:
332 d.suffix = None
333 self.width = width
334
335 def suffix_mask(self, d):
336 return ((1 << d.suffix) - 1)
337
338 def divide_opcodes(self, d):
339 divided = {}
340 mask = self.suffix_mask(d)
341 #print("mask", hex(mask))
342 for row in d.opcodes:
343 opcode = row['opcode']
344 if d.opint and '-' not in opcode:
345 opcode = int(opcode, 0)
346 key = opcode & mask
347 opcode = opcode >> d.suffix
348 if key not in divided:
349 divided[key] = []
350 r = row.copy()
351 r['opcode'] = opcode
352 divided[key].append(r)
353 return divided
354
355 def tree_analyse(self):
356 self.decs = decs = []
357 self.submodules = submodules = {}
358 self.eqs = eqs = []
359
360 # go through the list of CSV decoders first
361 for d in self.dec:
362 cases = []
363 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
364 reset_less=True)
365 eq = []
366 case_does_something = False
367 eq.append(opcode_switch.eq(
368 self.opcode_in[d.bitsel[0]:d.bitsel[1]]))
369 if d.suffix:
370 opcodes = self.divide_opcodes(d)
371 opc_in = Signal(d.suffix, reset_less=True)
372 eq.append(opc_in.eq(opcode_switch[:d.suffix]))
373 # begin the dynamic Switch statement here
374 switch_case = {}
375 cases.append([opc_in, switch_case])
376 sub_eqs = []
377 for key, row in opcodes.items():
378 bitsel = (d.suffix+d.bitsel[0], d.bitsel[1])
379 sd = Subdecoder(pattern=None, opcodes=row,
380 bitsel=bitsel, suffix=None,
381 opint=False, subdecoders=[])
382 mname = get_pname("dec_sub%d" % key, self.pname)
383 subdecoder = PowerDecoder(width=32, dec=sd,
384 name=mname,
385 col_subset=self.col_subset,
386 row_subset=self.row_subsetfn)
387 if not subdecoder.tree_analyse():
388 del subdecoder
389 continue
390 submodules[mname] = subdecoder
391 sub_eqs.append(subdecoder.opcode_in.eq(self.opcode_in))
392 # add in the dynamic Case statement here
393 switch_case[key] = self.op.eq(subdecoder.op)
394 self.actually_does_something = True
395 case_does_something = True
396 if case_does_something:
397 eq += sub_eqs
398 else:
399 # TODO: arguments, here (all of them) need to be a list.
400 # a for-loop around the *list* of decoder args.
401 switch_case = {}
402 cases.append([opcode_switch, switch_case])
403 seqs = self.handle_subdecoders(switch_case, submodules, d)
404 if seqs:
405 case_does_something = True
406 eq += seqs
407 for row in d.opcodes:
408 opcode = row['opcode']
409 if d.opint and '-' not in opcode:
410 opcode = int(opcode, 0)
411 if not row['unit']:
412 continue
413 if self.row_subsetfn:
414 if not self.row_subsetfn(opcode, row):
415 continue
416 # add in the dynamic Case statement here
417 switch_case[opcode] = self.op._eq(row)
418 self.actually_does_something = True
419 case_does_something = True
420
421 if cases:
422 decs.append(cases)
423 if case_does_something:
424 eqs += eq
425 #print("submodule eqs", self.pname, eq)
426
427 #print("submodules", self.pname, submodules)
428
429 gc.collect()
430 return self.actually_does_something
431
432 def handle_subdecoders(self, switch_case, submodules, d):
433 eqs = []
434 for dlist in d.subdecoders:
435 if not isinstance(dlist, list): # XXX HACK: take first pattern
436 dlist = [dlist]
437 for dec in dlist:
438 #print("subdec", dec.pattern, self.pname)
439 mname = get_pname("dec%d" % dec.pattern, self.pname)
440 if mname in submodules:
441 # sigh, HACK...
442 mname += "_1"
443 assert mname not in submodules
444 subdecoder = PowerDecoder(self.width, dec,
445 name=mname,
446 col_subset=self.col_subset,
447 row_subset=self.row_subsetfn)
448 log ("subdecoder", mname, subdecoder)
449 if not subdecoder.tree_analyse(): # doesn't do anything
450 log ("analysed, DELETING", mname)
451 del subdecoder
452 continue # skip
453 submodules[mname] = subdecoder
454 eqs.append(subdecoder.opcode_in.eq(self.opcode_in))
455 switch_case[dec.pattern] = self.op.eq(subdecoder.op)
456 self.actually_does_something = True
457
458 return eqs
459
460 def elaborate(self, platform):
461 #print("decoder elaborate", self.pname, self.submodules)
462 m = Module()
463 comb = m.d.comb
464
465 comb += self.eqs
466
467 for mname, subdecoder in self.submodules.items():
468 setattr(m.submodules, mname, subdecoder)
469
470 for switch_case in self.decs:
471 for (switch, cases) in switch_case:
472 with m.Switch(switch):
473 for key, eqs in cases.items():
474 with m.Case(key):
475 comb += eqs
476 return m
477
478 def ports(self):
479 return [self.opcode_in] + self.op.ports()
480
481
482 class TopPowerDecoder(PowerDecoder):
483 """TopPowerDecoder
484
485 top-level hierarchical decoder for POWER ISA
486 bigendian dynamically switches between big and little endian decoding
487 (reverses byte order). See V3.0B p44 1.11.2
488 """
489
490 def __init__(self, width, dec, name=None, col_subset=None, row_subset=None):
491 PowerDecoder.__init__(self, width, dec, name, col_subset, row_subset)
492 self.fields = df = DecodeFields(SignalBitRange, [self.opcode_in])
493 self.fields.create_specs()
494 self.raw_opcode_in = Signal.like(self.opcode_in, reset_less=True)
495 self.bigendian = Signal(reset_less=True)
496
497 for fname, value in self.fields.common_fields.items():
498 signame = get_pname(fname, name)
499 sig = Signal(value[0:-1].shape(), reset_less=True, name=signame)
500 setattr(self, fname, sig)
501
502 # create signals for all field forms
503 forms = self.form_names
504 self.sigforms = {}
505 for form in forms:
506 fields = self.fields.instrs[form]
507 fk = fields.keys()
508 Fields = namedtuple("Fields", fk)
509 sf = {}
510 for k, value in fields.items():
511 fname = "%s_%s" % (form, k)
512 sig = Signal(value[0:-1].shape(), reset_less=True, name=fname)
513 sf[k] = sig
514 instr = Fields(**sf)
515 setattr(self, "Form%s" % form, instr)
516 self.sigforms[form] = instr
517
518 self.tree_analyse()
519
520 @property
521 def form_names(self):
522 return self.fields.instrs.keys()
523
524 def elaborate(self, platform):
525 m = PowerDecoder.elaborate(self, platform)
526 comb = m.d.comb
527 # sigh duplicated in SVP64PowerDecoder
528 # raw opcode in assumed to be in LE order: byte-reverse it to get BE
529 raw_le = self.raw_opcode_in
530 l = []
531 for i in range(0, self.width, 8):
532 l.append(raw_le[i:i+8])
533 l.reverse()
534 raw_be = Cat(*l)
535 comb += self.opcode_in.eq(Mux(self.bigendian, raw_be, raw_le))
536
537 # add all signal from commonly-used fields
538 for fname, value in self.fields.common_fields.items():
539 sig = getattr(self, fname)
540 comb += sig.eq(value[0:-1])
541
542 # link signals for all field forms
543 forms = self.form_names
544 for form in forms:
545 sf = self.sigforms[form]
546 fields = self.fields.instrs[form]
547 for k, value in fields.items():
548 sig = getattr(sf, k)
549 comb += sig.eq(value[0:-1])
550
551 return m
552
553 def ports(self):
554 return [self.raw_opcode_in, self.bigendian] + PowerDecoder.ports(self)
555
556
557 #############################################################
558 # PRIMARY FUNCTION SPECIFYING ALTERNATIVE SVP64 POWER DECODER
559
560 def create_pdecode_svp64(name=None, col_subset=None, row_subset=None,
561 include_fp=False):
562 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
563
564 subsetting of the PowerOp decoding is possible by setting col_subset
565 """
566 log ("create_pdecode_svp64", name, col_subset, row_subset, include_fp)
567
568 # some alteration to the CSV files is required for SV so we use
569 # a class to do it
570 isa = SVP64RM()
571 get_csv = isa.get_svp64_csv
572
573 # minor opcodes.
574 pminor = [
575 Subdecoder(pattern=58, opcodes=get_csv("svldst_minor_58.csv"),
576 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
577 # nope - needs 4-in regs
578 #Subdecoder(pattern=62, opcodes=get_csv("svldst_minor_62.csv"),
579 # opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
580 ]
581
582 # FP 63L/H decoders. TODO: move mffsfamily to separate subdecoder
583 if False and include_fp:
584 pminor.append(
585 Subdecoder(pattern=63, opcodes=get_csv("minor_63.csv"),
586 opint=False, bitsel=(1, 11), suffix=None,
587 subdecoders=[]),
588 )
589 pminor.append(
590 Subdecoder(pattern=59, opcodes=get_csv("minor_59.csv"),
591 opint=False, bitsel=(1, 11), suffix=None,
592 subdecoders=[]),
593 )
594
595 # top level: extra merged with major
596 dec = []
597 opcodes = get_csv("svldst_major.csv")
598 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
599 bitsel=(26, 32), suffix=None, subdecoders=pminor))
600
601 return TopPowerDecoder(32, dec, name=name, col_subset=col_subset,
602 row_subset=row_subset)
603
604
605 ####################################################
606 # PRIMARY FUNCTION SPECIFYING THE FULL POWER DECODER
607
608 def create_pdecode(name=None, col_subset=None, row_subset=None,
609 include_fp=False):
610 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
611
612 subsetting of the PowerOp decoding is possible by setting col_subset
613 """
614 log ("create_pdecode", name, col_subset, row_subset, include_fp)
615
616 # some alteration to the CSV files is required for SV so we use
617 # a class to do it
618 isa = SVP64RM()
619 get_csv = isa.get_svp64_csv
620
621 # minor 19 has extra patterns
622 m19 = []
623 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19.csv"),
624 opint=True, bitsel=(1, 11), suffix=None,
625 subdecoders=[]))
626 # XXX problem with sub-decoders (can only handle one),
627 # sort this another time
628 #m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
629 # opint=True, bitsel=(1, 6), suffix=None,
630 # subdecoders=[]))
631
632 # minor opcodes.
633 pminor = [
634 m19,
635 Subdecoder(pattern=30, opcodes=get_csv("minor_30.csv"),
636 opint=True, bitsel=(1, 5), suffix=None, subdecoders=[]),
637 Subdecoder(pattern=31, opcodes=get_csv("minor_31.csv"),
638 opint=True, bitsel=(1, 11), suffix=0b00101, subdecoders=[]),
639 Subdecoder(pattern=58, opcodes=get_csv("minor_58.csv"),
640 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
641 Subdecoder(pattern=62, opcodes=get_csv("minor_62.csv"),
642 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
643 Subdecoder(pattern=22, opcodes=get_csv("minor_22.csv"),
644 opint=True, bitsel=(1, 5), suffix=None, subdecoders=[]),
645 ]
646
647 # FP 63L/H decoders. TODO: move mffsfamily to separate subdecoder
648 if include_fp:
649 pminor.append(
650 Subdecoder(pattern=63, opcodes=get_csv("minor_63.csv"),
651 opint=False, bitsel=(1, 11), suffix=None,
652 subdecoders=[]),
653 )
654 pminor.append(
655 Subdecoder(pattern=59, opcodes=get_csv("minor_59.csv"),
656 opint=False, bitsel=(1, 11), suffix=None,
657 subdecoders=[]),
658 )
659
660 # top level: extra merged with major
661 dec = []
662 opcodes = get_csv("major.csv")
663 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
664 bitsel=(26, 32), suffix=None, subdecoders=pminor))
665 opcodes = get_csv("extra.csv")
666 dec.append(Subdecoder(pattern=None, opint=False, opcodes=opcodes,
667 bitsel=(0, 32), suffix=None, subdecoders=[]))
668
669 return TopPowerDecoder(32, dec, name=name, col_subset=col_subset,
670 row_subset=row_subset)
671
672
673 if __name__ == '__main__':
674
675 if True:
676 # row subset
677
678 def rowsubsetfn(opcode, row):
679 log("row_subset", opcode, row)
680 return row['unit'] == 'FPU'
681
682 pdecode = create_pdecode(name="rowsub",
683 col_subset={'opcode', 'function_unit',
684 'form'},
685 row_subset=rowsubsetfn,
686 include_fp=True)
687 vl = rtlil.convert(pdecode, ports=pdecode.ports())
688 with open("row_subset_decoder.il", "w") as f:
689 f.write(vl)
690
691 # col subset
692
693 pdecode = create_pdecode(name="fusubset", col_subset={'function_unit'})
694 vl = rtlil.convert(pdecode, ports=pdecode.ports())
695 with open("col_subset_decoder.il", "w") as f:
696 f.write(vl)
697
698 # full decoder
699 pdecode = create_pdecode(include_fp=True)
700 vl = rtlil.convert(pdecode, ports=pdecode.ports())
701 with open("decoder.il", "w") as f:
702 f.write(vl)
703
704 # full SVP64 decoder
705 pdecode = create_pdecode_svp64(include_fp=True)
706 vl = rtlil.convert(pdecode, ports=pdecode.ports())
707 with open("decoder_svp64.il", "w") as f:
708 f.write(vl)