9389dd3a
1 # SPDX-License-Identifier: LGPL-3-or-later
2 """Cascading Power ISA Decoder
6 # Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
7 # Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
9 This module uses CSV tables in a hierarchical/peer cascading fashion,
10 to create a multi-level instruction decoder by recognising appropriate
11 patterns. The output is a wide, flattened (1-level) series of bitfields,
12 suitable for a simple RISC engine.
14 This is based on Anton Blanchard's excellent microwatt work:
15 https://github.com/antonblanchard/microwatt/blob/master/decode1.vhdl
17 The basic principle is that the python code does the heavy lifting
18 (reading the CSV files, constructing the hierarchy), creating the HDL
19 AST with for-loops generating switch-case statements.
21 Where "normal" HDL would do this, in laborious excruciating detail:
23 switch (opcode & major_mask_bits):
24 case opcode_2: decode_opcode_2()
26 switch (opcode & minor_19_mask_bits)
27 case minor_opcode_19_operation_X:
28 case minor_opcode_19_operation_y:
30 we take *full* advantage of the decoupling between python and the
31 nmigen AST data structure, to do this:
33 with m.Switch(opcode & self.mask):
34 for case_bitmask in subcases:
35 with m.If(opcode & case_bitmask): {do_something}
37 this includes specifying the information sufficient to perform subdecoding.
41 the full hierarchical tree for decoding POWER9 is specified here
42 subsetting is possible by specifying col_subset (row_subset TODO)
46 takes a *list* of CSV files with an associated bit-range that it
47 is requested to match against the "opcode" row of the CSV file.
48 This pattern can be either an integer, a binary number, *or* a
49 wildcard nmigen Case pattern of the form "001--1-100".
53 these are *additional* cases with further decoding. The "pattern"
54 argument is specified as one of the Case statements (a peer of the
55 opcode row in the CSV file), and thus further fields of the opcode
56 may be decoded giving increasing levels of detail.
60 [ (extra.csv: bit-fields entire 32-bit range
62 000000---------------01000000000 -> ILLEGAL instruction
63 01100000000000000000000000000000 -> SIM_CONFIG instruction
64 ................................ ->
66 (major.csv: first 6 bits ONLY
68 001100 -> ALU,OP_ADD (add)
69 001101 -> ALU,OP_ADD (another type of add)
73 001011 this must match *MAJOR*.CSV
74 [ (minor_19.csv: bits 21 through 30 inclusive:
76 0b0000000000 -> ALU,OP_MCRF
79 (minor_19_00000.csv: bits 21 through 25 inclusive:
81 0b00010 -> ALU,add_pcis
91 from collections
import namedtuple
, OrderedDict
92 from nmigen
import Module
, Elaboratable
, Signal
, Cat
, Mux
, Const
93 from nmigen
.cli
import rtlil
, verilog
94 from openpower
.decoder
.power_enums
import (Function
, Form
, MicrOp
,
95 In1Sel
, In2Sel
, In3Sel
, OutSel
,
96 SVEXTRA
, SVMode
, # Simple-V
97 SVEType
, SVPType
, # Simple-V
98 RCOE
, LdstLen
, LDSTMode
, CryIn
,
99 single_bit_flags
, CRInSel
,
100 CROutSel
, get_signal_name
,
101 default_values
, insns
, asmidx
,
103 from openpower
.decoder
.power_fields
import DecodeFields
104 from openpower
.decoder
.power_fieldsn
import SigDecode
, SignalBitRange
105 from openpower
.decoder
.power_svp64
import SVP64RM
107 from openpower
.util
import log
109 # key data structure in which the POWER decoder is specified,
110 # in a hierarchical fashion
111 Subdecoder
= namedtuple( # fix autoformatter
113 ["pattern", # the major pattern to search for (e.g. major opcode)
114 "opcodes", # a dictionary of minor patterns to find
115 "opint", # true => the pattern must not be in "10----11" format
116 # the bits (as a range) against which "pattern" matches
117 "bitsel", # should be in MSB0 order but isn't! it's LSB0. um.
118 "suffix", # shift the opcode down before decoding
119 "subdecoders" # list of further subdecoders for *additional* matches,
120 # *ONLY* after "pattern" has *ALSO* been matched against.
123 power_op_types
= {'function_unit': Function
,
124 'internal_op': MicrOp
,
142 'sv_cr_out': SVEXTRA
,
149 power_op_csvmap
= {'function_unit': 'unit',
151 'internal_op': 'internal op',
160 'sv_out2': 'sv_out2',
161 'sv_cr_in': 'sv_cr_in',
162 'sv_cr_out': 'sv_cr_out',
163 'SV_Etype': 'SV_Etype',
164 'SV_Ptype': 'SV_Ptype',
165 'SV_mode': 'SV_mode',
168 'ldst_len': 'ldst len',
170 'rsrv': 'rsrv', # atomic operation
176 def get_pname(field
, pname
):
179 return "%s_%s" % (pname
, field
)
183 """PowerOp - a dynamic class that stores (subsets of) CSV rows of data
184 about a PowerISA instruction. this is a "micro-code" expanded format
185 which generates an awful lot of wires, hence the subsetting
188 def __init__(self
, incl_asm
=True, name
=None, subset
=None, fields
=None):
191 if fields
is not None:
192 for k
, v
in fields
.items():
197 for field
, ptype
in power_op_types
.items():
199 if subset
and field
not in subset
:
201 fname
= get_pname(field
, name
)
202 setattr(self
, field
, Signal(ptype
, reset_less
=True, name
=fname
))
203 debug_report
.add(field
)
204 for bit
in single_bit_flags
:
205 field
= get_signal_name(bit
)
207 if subset
and field
not in subset
:
209 debug_report
.add(field
)
210 fname
= get_pname(field
, name
)
211 setattr(self
, field
, Signal(reset_less
=True, name
=fname
))
212 self
._fields
= fields
213 # comment out, bit too high debug level
214 #print("PowerOp debug", name, debug_report)
215 #print(" fields", fields)
219 """PowerOp.like: creates a duplicate of a given PowerOp instance
222 for fname
in other
._fields
:
223 sig
= getattr(other
, fname
, None)
225 fields
[fname
] = sig
.__class
__.like(sig
)
226 return PowerOp(subset
=other
.subset
, fields
=fields
)
228 def _eq(self
, row
=None):
231 # TODO: this conversion process from a dict to an object
232 # should really be done using e.g. namedtuple and then
234 if False: # debugging
235 if row
['CR in'] == '1':
239 if row
['CR out'] == '0':
244 ldst_mode
= row
['upd']
245 if ldst_mode
.isdigit():
246 row
['upd'] = int(ldst_mode
)
248 for field
, ptype
in power_op_types
.items():
249 if not hasattr(self
, field
):
251 if field
not in power_op_csvmap
:
253 csvname
= power_op_csvmap
[field
]
254 log("_eq", field
, ptype
, csvname
, row
)
256 if csvname
== 'upd' and isinstance(val
, int): # LDSTMode different
260 res
.append(getattr(self
, field
).eq(val
))
263 asmcode
= row
['comment']
264 # process the comment field, strip out "equals" for FP
266 asmcode
= asmcode
.split("=")[-1]
267 log("asmcode stripping =", asmcode
,
268 asmcode
in asmidx
, hasattr(self
, "asmcode"))
269 if hasattr(self
, "asmcode") and asmcode
in asmidx
:
270 res
.append(self
.asmcode
.eq(asmidx
[asmcode
]))
271 for bit
in single_bit_flags
:
272 field
= get_signal_name(bit
)
273 if not hasattr(self
, field
):
275 sig
= getattr(self
, field
)
276 res
.append(sig
.eq(int(row
.get(bit
, 0))))
279 def _get_eq(self
, res
, field
, otherop
):
280 copyfrom
= getattr(otherop
, field
, None)
281 copyto
= getattr(self
, field
, None)
282 if copyfrom
is not None and copyto
is not None:
283 res
.append(copyto
.eq(copyfrom
))
285 def eq(self
, otherop
):
287 for field
in power_op_types
.keys():
288 self
._get
_eq
(res
, field
, otherop
)
289 for bit
in single_bit_flags
:
290 self
._get
_eq
(res
, get_signal_name(bit
), otherop
)
295 for field
in power_op_types
.keys():
296 if hasattr(self
, field
):
297 res
.append(getattr(self
, field
))
298 if hasattr(self
, "asmcode"):
299 res
.append(self
.asmcode
)
300 for field
in single_bit_flags
:
301 field
= get_signal_name(field
)
302 if hasattr(self
, field
):
303 res
.append(getattr(self
, field
))
307 class PowerDecoder(Elaboratable
):
308 """PowerDecoder - decodes an incoming opcode into the type of operation
310 this is a recursive algorithm, creating Switch statements that can
311 have further match-and-decode on other parts of the opcode field before
312 finally landing at a "this CSV entry details gets returned" thing.
314 the complicating factor is the row and col subsetting. column subsetting
315 dynamically chooses only the CSV columns requested, whilst row subsetting
316 allows a function to be called on the row to determine if the Case
317 statement is to be generated for that row. this not only generates
318 completely different Decoders, it also means that some sub-decoders
319 will turn up blank (empty switch statements). if that happens we do
320 not want the parent to include a Mux for an entirely blank switch statement
321 so we have to store the switch/case statements in a tree, and
324 the reason for the tree is because elaborate can only be called *after*
325 the constructor is called. all quite messy.
328 def __init__(self
, width
, dec
, name
=None, col_subset
=None,
329 row_subset
=None, conditions
=None):
330 if conditions
is None:
331 # XXX conditions = {}
333 'SVP64FFT': Const(0, 1),
335 self
.actually_does_something
= False
337 self
.conditions
= conditions
338 self
.col_subset
= col_subset
339 self
.row_subsetfn
= row_subset
340 if not isinstance(dec
, list):
343 self
.opcode_in
= Signal(width
, reset_less
=True)
345 self
.op
= PowerOp(name
=name
, subset
=col_subset
)
347 if d
.suffix
is not None and d
.suffix
>= width
:
352 # create some case statement condition patterns for matching
353 # a single condition. "1----" for the first condition,
354 # "-1----" for the 2nd etc.
355 # also create a matching ordered list of conditions, for the switch,
356 # which will Cat() them together
358 self
.ckeys
= list(conditions
.keys())
361 def find_conditions(self
, opcodes
):
362 # look for conditions, create dictionary entries for them
364 rows
= OrderedDict() # start as a dictionary, get as list (after)
366 condition
= row
['CONDITIONS']
367 opcode
= row
['opcode']
369 # check it's expected
370 assert (condition
in self
.conditions
or
371 (condition
[0] == '~' and
372 condition
[1:] in self
.conditions
)), \
373 "condition %s not in %s" % (condition
, str(conditions
))
374 if opcode
not in rows
:
376 rows
[opcode
][condition
] = row
379 assert opcode
not in rows
, \
380 "opcode %s already in rows for %s" % \
383 # after checking for conditions, get just the values (ordered)
384 return list(rows
.values())
386 def suffix_mask(self
, d
):
387 return ((1 << d
.suffix
) - 1)
389 def divide_opcodes(self
, d
):
391 mask
= self
.suffix_mask(d
)
392 #print("mask", hex(mask))
393 for row
in d
.opcodes
:
394 opcode
= row
['opcode']
395 if d
.opint
and '-' not in opcode
:
396 opcode
= int(opcode
, 0)
398 opcode
= opcode
>> d
.suffix
399 if key
not in divided
:
403 divided
[key
].append(r
)
406 def tree_analyse(self
):
407 self
.decs
= decs
= []
408 self
.submodules
= submodules
= {}
411 # go through the list of CSV decoders first
414 opcode_switch
= Signal(d
.bitsel
[1] - d
.bitsel
[0],
417 case_does_something
= False
418 look_for
= self
.opcode_in
[d
.bitsel
[0]:d
.bitsel
[1]]
419 eq
.append(opcode_switch
.eq(look_for
))
421 opcodes
= self
.divide_opcodes(d
)
422 # TODO opcodes = self.find_conditions(opcodes)
423 opc_in
= Signal(d
.suffix
, reset_less
=True)
424 eq
.append(opc_in
.eq(opcode_switch
[:d
.suffix
]))
425 # begin the dynamic Switch statement here
427 cases
.append([opc_in
, switch_case
])
429 for key
, row
in opcodes
.items():
430 bitsel
= (d
.suffix
+d
.bitsel
[0], d
.bitsel
[1])
431 sd
= Subdecoder(pattern
=None, opcodes
=row
,
432 bitsel
=bitsel
, suffix
=None,
433 opint
=False, subdecoders
=[])
434 mname
= get_pname("dec_sub%d" % key
, self
.pname
)
435 subdecoder
= PowerDecoder(width
=32, dec
=sd
,
437 col_subset
=self
.col_subset
,
438 row_subset
=self
.row_subsetfn
,
439 conditions
=self
.conditions
)
440 if not subdecoder
.tree_analyse():
443 submodules
[mname
] = subdecoder
444 sub_eqs
.append(subdecoder
.opcode_in
.eq(self
.opcode_in
))
445 # add in the dynamic Case statement here
446 switch_case
[key
] = self
.op
.eq(subdecoder
.op
)
447 self
.actually_does_something
= True
448 case_does_something
= True
449 if case_does_something
:
452 # TODO: arguments, here (all of them) need to be a list.
453 # a for-loop around the *list* of decoder args.
455 cases
.append([opcode_switch
, switch_case
])
456 seqs
= self
.handle_subdecoders(switch_case
, submodules
, d
)
458 case_does_something
= True
460 opcodes
= self
.find_conditions(d
.opcodes
)
462 # urrr this is an awful hack. if "conditions" are active
463 # get the FIRST item (will be the same opcode), and it
464 # had BETTER have the same unit and also pass other
465 # row subset conditions.
466 if 'opcode' not in row
: # must be a "CONDITIONS" dict...
468 _row
= row
[list(row
.keys())[0]]
470 is_conditions
= False
472 opcode
= _row
['opcode']
473 if d
.opint
and '-' not in opcode
:
474 opcode
= int(opcode
, 0)
477 if self
.row_subsetfn
:
478 if not self
.row_subsetfn(opcode
, _row
):
480 # add in the dynamic Case statement here
482 switch_case
[opcode
] = {}
483 for k
, crow
in row
.items():
484 # log("ordered", k, crow)
485 switch_case
[opcode
][k
] = self
.op
._eq
(crow
)
487 switch_case
[opcode
] = self
.op
._eq
(row
)
488 self
.actually_does_something
= True
489 case_does_something
= True
493 if case_does_something
:
495 #print("submodule eqs", self.pname, eq)
497 #print("submodules", self.pname, submodules)
500 return self
.actually_does_something
502 def handle_subdecoders(self
, switch_case
, submodules
, d
):
504 for dlist
in d
.subdecoders
:
505 if not isinstance(dlist
, list): # XXX HACK: take first pattern
508 #print("subdec", dec.pattern, self.pname)
509 mname
= get_pname("dec%d" % dec
.pattern
, self
.pname
)
510 if mname
in submodules
:
513 assert mname
not in submodules
514 subdecoder
= PowerDecoder(self
.width
, dec
,
516 col_subset
=self
.col_subset
,
517 row_subset
=self
.row_subsetfn
,
518 conditions
=self
.conditions
)
519 log("subdecoder", mname
, subdecoder
)
520 if not subdecoder
.tree_analyse(): # doesn't do anything
521 log("analysed, DELETING", mname
)
524 submodules
[mname
] = subdecoder
525 eqs
.append(subdecoder
.opcode_in
.eq(self
.opcode_in
))
526 switch_case
[dec
.pattern
] = self
.op
.eq(subdecoder
.op
)
527 self
.actually_does_something
= True
531 def elaborate(self
, platform
):
532 #print("decoder elaborate", self.pname, self.submodules)
538 for mname
, subdecoder
in self
.submodules
.items():
539 setattr(m
.submodules
, mname
, subdecoder
)
541 for switch_case
in self
.decs
:
542 for (switch
, cases
) in switch_case
:
543 with m
.Switch(switch
):
544 for key
, eqs
in cases
.items():
546 # "conditions" are a further switch statement
547 if isinstance(eqs
, dict):
548 self
.condition_switch(m
, eqs
)
553 def condition_switch(self
, m
, cases
):
554 """against the global list of "conditions", having matched against
555 bits of the opcode, we FINALLY now have to match against some
556 additional "conditions". this is because there can be **MULTIPLE**
557 entries for a given opcode match. here we discern them.
562 for casekey
, eqs
in cases
.items():
563 if casekey
.startswith('~'):
564 with m
.If(~self
.conditions
[casekey
[1:]]):
567 with m
.If(self
.conditions
[casekey
]):
571 return [self
.opcode_in
] + self
.op
.ports()
574 class TopPowerDecoder(PowerDecoder
):
577 top-level hierarchical decoder for POWER ISA
578 bigendian dynamically switches between big and little endian decoding
579 (reverses byte order). See V3.0B p44 1.11.2
582 def __init__(self
, width
, dec
, name
=None, col_subset
=None,
583 row_subset
=None, conditions
=None):
584 PowerDecoder
.__init
__(self
, width
, dec
, name
,
585 col_subset
, row_subset
, conditions
)
586 self
.fields
= df
= DecodeFields(SignalBitRange
, [self
.opcode_in
])
587 self
.fields
.create_specs()
588 self
.raw_opcode_in
= Signal
.like(self
.opcode_in
, reset_less
=True)
589 self
.bigendian
= Signal(reset_less
=True)
591 for fname
, value
in self
.fields
.common_fields
.items():
592 signame
= get_pname(fname
, name
)
593 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=signame
)
594 setattr(self
, fname
, sig
)
596 # create signals for all field forms
597 forms
= self
.form_names
600 fields
= self
.fields
.instrs
[form
]
602 Fields
= namedtuple("Fields", fk
)
604 for k
, value
in fields
.items():
605 fname
= "%s_%s" % (form
, k
)
606 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=fname
)
609 setattr(self
, "Form%s" % form
, instr
)
610 self
.sigforms
[form
] = instr
615 def form_names(self
):
616 return self
.fields
.instrs
.keys()
618 def elaborate(self
, platform
):
619 m
= PowerDecoder
.elaborate(self
, platform
)
621 # sigh duplicated in SVP64PowerDecoder
622 # raw opcode in assumed to be in LE order: byte-reverse it to get BE
623 raw_le
= self
.raw_opcode_in
625 for i
in range(0, self
.width
, 8):
626 l
.append(raw_le
[i
:i
+8])
629 comb
+= self
.opcode_in
.eq(Mux(self
.bigendian
, raw_be
, raw_le
))
631 # add all signal from commonly-used fields
632 for fname
, value
in self
.fields
.common_fields
.items():
633 sig
= getattr(self
, fname
)
634 comb
+= sig
.eq(value
[0:-1])
636 # link signals for all field forms
637 forms
= self
.form_names
639 sf
= self
.sigforms
[form
]
640 fields
= self
.fields
.instrs
[form
]
641 for k
, value
in fields
.items():
643 comb
+= sig
.eq(value
[0:-1])
648 res
= [self
.raw_opcode_in
, self
.bigendian
] + PowerDecoder
.ports(self
)
649 for condition
in self
.conditions
.values():
650 res
.append(condition
)
654 #############################################################
655 # PRIMARY FUNCTION SPECIFYING ALTERNATIVE SVP64 POWER DECODER
657 def create_pdecode_svp64_ldst(name
=None, col_subset
=None, row_subset
=None,
659 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
661 subsetting of the PowerOp decoding is possible by setting col_subset
663 log("create_pdecode_svp64_ldst", name
, col_subset
, row_subset
, include_fp
)
665 # some alteration to the CSV files is required for SV so we use
668 get_csv
= isa
.get_svp64_csv
672 Subdecoder(pattern
=58, opcodes
=get_csv("svldst_minor_58.csv"),
673 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
674 # nope - needs 4-in regs
675 # Subdecoder(pattern=62, opcodes=get_csv("svldst_minor_62.csv"),
676 # opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
679 # FP 63L/H decoders. TODO: move mffsfamily to separate subdecoder
680 if False and include_fp
:
682 Subdecoder(pattern
=63, opcodes
=get_csv("minor_63.csv"),
683 opint
=False, bitsel
=(1, 11), suffix
=None,
687 Subdecoder(pattern
=59, opcodes
=get_csv("minor_59.csv"),
688 opint
=False, bitsel
=(1, 11), suffix
=None,
692 # top level: extra merged with major
694 opcodes
= get_csv("svldst_major.csv")
695 dec
.append(Subdecoder(pattern
=None, opint
=True, opcodes
=opcodes
,
696 bitsel
=(26, 32), suffix
=None, subdecoders
=pminor
))
698 return TopPowerDecoder(32, dec
, name
=name
, col_subset
=col_subset
,
699 row_subset
=row_subset
)
702 ####################################################
703 # PRIMARY FUNCTION SPECIFYING THE FULL POWER DECODER
705 def create_pdecode(name
=None, col_subset
=None, row_subset
=None,
706 include_fp
=False, conditions
=None):
707 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
709 subsetting of the PowerOp decoding is possible by setting col_subset
711 NOTE (sigh) the bitsel patterns are in LSB0 order, they should be MSB0
713 log("create_pdecode", name
, col_subset
, row_subset
, include_fp
)
715 # some alteration to the CSV files is required for SV so we use
718 get_csv
= isa
.get_svp64_csv
720 # minor 19 has extra patterns
722 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19.csv"),
723 opint
=False, bitsel
=(1, 11), suffix
=None,
725 # XXX problem with sub-decoders (can only handle one),
726 # sort this another time
727 # m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
728 # opint=True, bitsel=(1, 6), suffix=None,
734 Subdecoder(pattern
=30, opcodes
=get_csv("minor_30.csv"),
735 opint
=False, bitsel
=(1, 5), suffix
=None, subdecoders
=[]),
736 Subdecoder(pattern
=31, opcodes
=get_csv("minor_31.csv"),
737 opint
=True, bitsel
=(1, 11), suffix
=0b00101, subdecoders
=[]),
738 Subdecoder(pattern
=58, opcodes
=get_csv("minor_58.csv"),
739 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
740 Subdecoder(pattern
=62, opcodes
=get_csv("minor_62.csv"),
741 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
742 Subdecoder(pattern
=22, opcodes
=get_csv("minor_22.csv"),
743 opint
=False, bitsel
=(0, 11), suffix
=None, subdecoders
=[]),
744 Subdecoder(pattern
=5, opcodes
=get_csv("minor_5.csv"),
745 opint
=True, bitsel
=(0, 11), suffix
=None, subdecoders
=[]),
746 Subdecoder(pattern
=4, opcodes
=get_csv("minor_4.csv"),
747 opint
=True, bitsel
=(0, 6), suffix
=None, subdecoders
=[]),
750 # FP 63L/H decoders. TODO: move mffsfamily to separate subdecoder
753 Subdecoder(pattern
=63, opcodes
=get_csv("minor_63.csv"),
754 opint
=False, bitsel
=(1, 11), suffix
=None,
758 Subdecoder(pattern
=59, opcodes
=get_csv("minor_59.csv"),
759 opint
=False, bitsel
=(1, 11), suffix
=None,
763 # top level: extra merged with major
765 opcodes
= get_csv("major.csv")
766 dec
.append(Subdecoder(pattern
=None, opint
=True, opcodes
=opcodes
,
767 bitsel
=(26, 32), suffix
=None, subdecoders
=pminor
))
768 opcodes
= get_csv("extra.csv")
769 dec
.append(Subdecoder(pattern
=None, opint
=False, opcodes
=opcodes
,
770 bitsel
=(0, 32), suffix
=None, subdecoders
=[]))
772 return TopPowerDecoder(32, dec
, name
=name
, col_subset
=col_subset
,
773 row_subset
=row_subset
,
774 conditions
=conditions
)
777 # https://github.com/apertus-open-source-cinema/naps/blob/9ebbc0/naps/soc/cli.py#L17
780 def fragment_repr(original
):
781 from textwrap
import indent
783 for attr
in ['ports', 'drivers', 'statements', 'attrs',
784 'generated', 'flatten']:
785 attrs_str
+= f
"{attr}={repr(getattr(original, attr))},\n"
788 for name
, domain
in original
.domains
.items():
789 # TODO: this is not really sound because domains could be non local
790 domains_str
+= f
"{name}: {domain.name}\n"
791 attrs_str
+= f
"domains={{{indent(domains_str, ' ')}}},\n"
794 for child
, name
in original
.subfragments
:
795 children_str
+= f
"[{name}, {fragment_repr(child)}]\n"
796 attrs_str
+= f
"children=[{indent(children_str, ' ')}],\n"
798 return f
"Fragment({indent(attrs_str, ' ')})"
801 if __name__
== '__main__':
806 def rowsubsetfn(opcode
, row
):
807 log("row_subset", opcode
, row
)
808 return row
['unit'] in ['LDST', 'FPU']
811 'SVP64FFT': Signal(name
="svp64fft", reset_less
=True),
813 pdecode
= create_pdecode(name
="rowsub",
814 col_subset
={'opcode', 'function_unit',
816 'in2_sel', 'in3_sel'},
817 row_subset
=rowsubsetfn
,
819 conditions
=conditions
)
820 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
821 with
open("row_subset_decoder.il", "w") as f
:
824 vl
= verilog
.convert(pdecode
, ports
=pdecode
.ports())
825 with
open("row_subset_decoder.v", "w") as f
:
830 pdecode
= create_pdecode(name
="fusubset", col_subset
={'function_unit'},
831 conditions
=conditions
)
832 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
833 with
open("col_subset_decoder.il", "w") as f
:
836 from nmigen
.hdl
.ir
import Fragment
837 elaborated
= Fragment
.get(pdecode
, platform
=None)
838 elaborated_repr
= fragment_repr(elaborated
)
839 print(elaborated_repr
)
846 pdecode
= create_pdecode(include_fp
=True)
847 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
848 with
open("decoder.il", "w") as f
:
852 pdecode
= create_pdecode_svp64_ldst(include_fp
=True)
853 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
854 with
open("decoder_svp64.il", "w") as f
: