1 # SPDX-License-Identifier: LGPL-3-or-later
2 # Copyright (C) 2020, 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Copyright (C) 2020, Michael Nolan
5 """Enums used in OpenPOWER ISA decoding
7 Note: for SV, from v3.1B p12:
9 The designated SPR sandbox consists of non-privileged SPRs 704-719 and
10 privileged SPRs 720-735.
12 Note: the option exists to select a much shorter list of SPRs, to reduce
13 regfile size in HDL. this is SPRreduced and the supported list is in
24 from os
.path
import dirname
, join
25 from collections
import namedtuple
30 filedir
= os
.path
.dirname(os
.path
.abspath(__file__
))
31 basedir
= dirname(dirname(dirname(filedir
)))
32 tabledir
= join(basedir
, 'openpower')
33 isatables
= join(tabledir
, 'isatables')
34 #print ("find_wiki_dir", isatables)
38 def find_wiki_file(name
):
39 return join(find_wiki_dir(), name
)
43 """gets a not-entirely-csv-file-formatted database, which allows comments
45 file_path
= find_wiki_file(name
)
46 with
open(file_path
, 'r') as csvfile
:
47 csvfile
= filter(lambda row
: row
[0] !='#', csvfile
) # strip "#..."
48 reader
= csv
.DictReader(csvfile
)
52 # names of the fields in the tables that don't correspond to an enum
53 single_bit_flags
= ['inv A', 'inv out',
54 'cry out', 'BR', 'sgn ext', 'rsrv', '32b',
55 'sgn', 'lk', 'sgl pipe']
57 # default values for fields in the table
58 default_values
= {'unit': "NONE", 'internal op': "OP_ILLEGAL",
59 'in1': "RA", 'in2': 'NONE', 'in3': 'NONE', 'out': 'NONE',
63 'rc': 'NONE', 'cry in': 'ZERO', 'form': 'NONE'}
66 def get_signal_name(name
):
69 return name
.lower().replace(' ', '_')
74 def _missing_(cls
, desc
):
75 if isinstance(desc
, str):
83 keys
= {item
.name
:item
for item
in cls
}
84 descs
= {item
.value
:item
for item
in cls
}
85 return keys
.get(desc
, descs
.get(desc
))
88 # this corresponds to which Function Unit (pipeline-with-Reservation-Stations)
89 # is to process and guard the operation. they are roughly divided by having
90 # the same register input/output signature (X-Form, etc.)
107 SV
= 1 << 12 # Simple-V https://libre-soc.org/openpower/sv
111 @functools.lru_cache(maxsize
=None)
114 value
= int(self
.value
)
120 desc
= f
"(1 << {counter})"
123 return f
"<{self.__class__.__name__}.{self.name}: {desc}>"
157 SVL
= 29 # Simple-V for setvl instruction
158 SVD
= 30 # Simple-V for LD/ST bit-reverse, variant of D-Form
159 SVDS
= 31 # Simple-V for LD/ST bit-reverse, variant of DS-Form
160 SVM
= 32 # Simple-V SHAPE mode
161 SVM2
= 33 # Simple-V SHAPE2 mode - fits into SVM
162 SVRM
= 34 # Simple-V REMAP mode
166 SVI
= 38 # Simple-V Index Mode
170 CRB
= 42 # crternlogi / crbinlut
171 MM
= 43 # [f]minmax[s][.]
176 # Simple-V svp64 fields https://libre-soc.org/openpower/sv/svp64/
180 NONE
= 0 # for non-SV instructions only
193 P2M
= 3 # for mixed EXTRA3/3/2 where MASK_SRC is RM[6,7,18]
196 def _missing_(cls
, desc
):
197 return {"1P": SVPType
.P1
, "2P": SVPType
.P2
, "2PM": SVPType
.P2M
}.get(desc
)
201 SVPType
.NONE
: "NONE",
211 * EXTRA2 : 0: [10,11] 1: [12,13] 2: [14,15] 3: [16,17] unused: [18]
212 * EXTRA3 : 0: [10,11,12] 1: [13,14,15] mask: [16,17,18]
213 * EXTRA32: 0: [10,11,12] 1: [13,14,15] 2: [16,17] mask: [6,7,18]
218 EXTRA32
= 3 # mixed EXTRA3 and EXTRA2 using RM bits 6&7 for MASK_SRC
225 class SVMaskSrc(Enum
):
240 Idx_1_2
= 5 # due to weird BA/BB for crops
244 SVExtra
.NONE
: "NONE",
245 SVExtra
.Idx0
: "EXTRA0",
246 SVExtra
.Idx1
: "EXTRA1",
247 SVExtra
.Idx2
: "EXTRA2",
248 SVExtra
.Idx3
: "EXTRA3",
249 SVExtra
.Idx_1_2
: "EXTRA1/EXTRA2",
252 # Backward compatibility
294 def _missing_(cls
, desc
):
296 In1Sel
, In2Sel
, In3Sel
, CRInSel
, CRIn2Sel
,
299 if isinstance(desc
, selectors
):
300 return cls
.__members
__.get(desc
.name
)
302 return cls
.__members
__.get(desc
)
314 if alias
is not None:
318 Reg
.RA_OR_ZERO
: Reg
.RA
,
319 Reg
.RT_OR_ZERO
: Reg
.RT
,
321 if alias
is not None:
346 class SVP64PredMode(Enum
):
354 class SVP64PredInt(Enum
):
365 def _missing_(cls
, desc
):
366 if isinstance(desc
, str):
377 if value
.startswith("~"):
378 value
= f
"~{value[1:].strip()}"
379 elif "<<" in value
: # 1 << r3
380 (lhs
, _
, rhs
) = value
.partition("<<")
381 lhs
= lhs
.strip().lower()
382 rhs
= rhs
.strip().lower()
383 if (lhs
== "1") and (rhs
in ("r3", "%r3")):
386 return values
.get(value
)
388 return super()._missing
_(desc
)
392 self
.__class
__.ALWAYS
: "",
393 self
.__class
__.R3_UNARY
: "^r3",
394 self
.__class
__.R3
: "r3",
395 self
.__class
__.R3_N
: "~r3",
396 self
.__class
__.R10
: "r10",
397 self
.__class
__.R10_N
: "~r10",
398 self
.__class
__.R30
: "r30",
399 self
.__class
__.R30_N
: "~r30",
403 return f
"{self.__class__.__name__}({str(self)})"
410 return SVP64PredMode
.INT
414 return (self
.value
& 0b1)
418 return (self
.value
>> 1)
421 class SVP64PredCR(Enum
):
436 def _missing_(cls
, desc
):
437 if isinstance(desc
, str):
439 return cls
.__members
__.get(name
)
441 return super()._missing
_(desc
)
448 return SVP64PredMode
.CR
452 return (self
.value
& 0b1)
456 return (self
.value
>> 1)
460 class SVP64PredRC1(Enum
):
465 def _missing_(cls
, desc
):
467 "RC1": SVP64PredRC1
.RC1
,
468 "~RC1": SVP64PredRC1
.RC1_N
,
476 return SVP64PredMode
.RC1
480 return (self
is SVP64PredRC1
.RC1_N
)
487 class SVP64Pred(Enum
):
488 ALWAYS
= SVP64PredInt
.ALWAYS
489 R3_UNARY
= SVP64PredInt
.R3_UNARY
491 R3_N
= SVP64PredInt
.R3_N
492 R10
= SVP64PredInt
.R10
493 R10_N
= SVP64PredInt
.R10_N
494 R30
= SVP64PredInt
.R30
495 R30_N
= SVP64PredInt
.R30_N
506 RC1
= SVP64PredRC1
.RC1
507 RC1_N
= SVP64PredRC1
.RC1_N
510 def _missing_(cls
, desc
):
511 if isinstance(desc
, str):
512 values
= {item
.value
:item
for item
in cls
}
513 for subcls
in (SVP64PredInt
, SVP64PredCR
, SVP64PredRC1
):
515 return values
.get(subcls(desc
))
520 return super()._missing
_(desc
)
523 return int(self
.value
)
527 return self
.value
.mode
531 return self
.value
.inv
535 return self
.value
.state
539 class SVP64RMMode(Enum
):
548 class SVP64BCPredMode(Enum
):
555 class SVP64BCVLSETMode(Enum
):
561 # note that these are chosen to be exactly the same as
562 # SVP64 RM bit 4. ALL=1 => bit4=1
564 class SVP64BCGate(Enum
):
569 class SVP64BCCTRMode(Enum
):
576 class SVP64Width(Enum
):
583 def _missing_(cls
, desc
):
584 if isinstance(desc
, str):
586 "32": SVP64Width
.EW_32
,
587 "16": SVP64Width
.EW_16
,
588 "8": SVP64Width
.EW_8
,
591 return super()._missing
_(desc
)
595 class SVP64SubVL(Enum
):
602 def _missing_(cls
, desc
):
603 if isinstance(desc
, str):
605 return cls
.__members
__.get(name
)
607 return super()._missing
_(desc
)
611 class SVP64Sat(Enum
):
618 class SVP64LDSTmode(Enum
):
646 CR_3BIT
= 2 # CR field; the CR register is 32-bit
650 CR_5BIT
= 3 # bit of the 32-bit CR register
657 XER_BIT
= 4 # XER bits, includes OV, OV32, SO, CA, CA32
665 def _missing_(cls
, value
):
666 if isinstance(value
, Reg
):
667 return cls
.__members
__.get(value
.name
)
669 return super()._missing
_(value
)
674 "fatan2pi", "fatan2pis",
683 "fexp2m1", "fexp2m1s",
684 "flog2p1", "flog2p1s",
691 "fexp10m1", "fexp10m1s",
692 "flog10p1", "flog10p1s",
704 "fasinpi", "fasinpis",
705 "facospi", "facospis",
706 "fatanpi", "fatanpis",
713 # fmin*/fmax* need to be replaced with fminmax
714 # https://bugs.libre-soc.org/show_bug.cgi?id=1057
715 # commented for now to make space for fmv/cvt
716 # "fminnum08", "fminnum08s",
717 # "fmaxnum08", "fmaxnum08s",
718 # "fmin19", "fmin19s",
719 # "fmax19", "fmax19s",
720 # "fminnum19", "fminnum19s",
721 # "fmaxnum19", "fmaxnum19s",
724 # "fminmagnum08", "fminmagnum08s",
725 # "fmaxmagnum08", "fmaxmagnum08s",
726 # "fminmag19", "fminmag19s",
727 # "fmaxmag19", "fmaxmag19s",
728 # "fminmagnum19", "fminmagnum19s",
729 # "fmaxmagnum19", "fmaxmagnum19s",
730 # "fminmagc", "fminmagcs",
731 # "fmaxmagc", "fmaxmagcs",
733 "fremainder", "fremainders",
737 # supported instructions: make sure to keep up-to-date with CSV files
738 # just like everything else
740 "NONE", "add", "addc", "addco", "adde", "addeo",
741 "addi", "addic", "addic.", "addis",
742 "addme", "addmeo", "addo", "addze", "addzeo",
745 "and", "andc", "andi.", "andis.",
747 "absdu", "absds", # AV bitmanip
748 "absdacs", "absdacu", # AV bitmanip
749 "avgadd", # AV bitmanip
750 "b", "bc", "bcctr", "bclr", "bctar",
751 "bmask", # AV bitmanip
755 "cmp", "cmpb", "cmpeqb", "cmpi", "cmpl", "cmpli", "cmprb",
756 "cntlzd", "cntlzw", "cnttzd", "cnttzw",
757 "cprop", # AV bitmanip
758 "crand", "crandc", "creqv",
759 "crnand", "crnor", "cror", "crorc", "crxor",
761 "dcbf", "dcbst", "dcbt", "dcbtst", "dcbz",
762 "divd", "divde", "divdeo", "divdeu",
763 "divdeuo", "divdo", "divdu", "divduo",
765 "divw", "divwe", "divweo",
766 "divweu", "divweuo", "divwo", "divwu", "divwuo",
767 "dsld", "dsld.", "dsrd", "dsrd.",
769 "extsb", "extsh", "extsw", "extswsli",
770 "fadd", "fadds", "fsub", "fsubs", # FP add / sub
771 "fcfids", "fcfidus", "fsqrts", "fres", "frsqrtes", # FP stuff
772 "fdmadds", # DCT FP 3-arg
773 "fmsubs", "fmadds", "fnmsubs", "fnmadds", # FP 3-arg
774 "ffadds", "ffsubs", "ffmuls", "ffdivs", # FFT FP 2-arg
775 "ffmsubs", "ffmadds", "ffnmsubs", "ffnmadds", # FFT FP 3-arg
776 "fmul", "fmuls", "fdiv", "fdivs", # FP mul / div
777 "fmr", "fabs", "fnabs", "fneg", "fcpsgn", # FP move/abs/neg
778 "fmvis", # FP load immediate
779 "fishmv", # Float Replace Lower-Half Single, Immediate
784 'grev', 'grev.', 'grevi', 'grevi.',
785 'grevw', 'grevw.', 'grevwi', 'grevwi.',
786 "hrfid", "icbi", "icbt", "isel", "isync",
787 "lbarx", "lbz", "lbzcix", "lbzu", "lbzux", "lbzx", # load byte
788 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
789 # "lbzbr", "lbzubr", # load byte SVP64 bit-reversed
790 # "ldbr", "ldubr", # load double SVP64 bit-reversed
791 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
792 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load double
793 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
794 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
795 # "lhabr", "lhaubr", # load half SVP64 bit-reversed
796 # "lhzbr", "lhzubr", # more load half SVP64 bit-reversed
797 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
798 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
799 # "lwabr", # load word SVP64 bit-reversed
800 # "lwzbr", "lwzubr", # more load word SVP64 bit-reversed
801 "maddedu", "maddedus",
802 "maddhd", "maddhdu", "maddld", # INT multiply-and-add
803 "maddsubrs", # Integer DCT Butterfly Add Sub and Round Shift
804 "maddrs", # Integer DCT Butterfly Add and Accumulate and Round Shift
805 "mcrf", "mcrxr", "mcrxrx", "mfcr/mfocrf", # CR mvs
807 "minmax", # AV bitmanip
808 "modsd", "modsw", "modud", "moduw",
809 "mtcrf/mtocrf", "mtmsr", "mtmsrd", "mtspr",
810 "mulhd", "mulhdu", "mulhw", "mulhwu", "mulld", "mulldo",
811 "mulli", "mullw", "mullwo",
812 "nand", "neg", "nego",
814 "nor", "or", "orc", "ori", "oris",
816 "popcntb", "popcntd", "popcntw",
819 "rldcl", "rldcr", "rldic", "rldicl", "rldicr", "rldimi",
820 "rlwimi", "rlwinm", "rlwnm",
822 "setvl", # https://libre-soc.org/openpower/sv/setvl
823 "svindex", # https://libre-soc.org/openpower/sv/remap
824 "svremap", # https://libre-soc.org/openpower/sv/remap - TEMPORARY
825 "svshape", # https://libre-soc.org/openpower/sv/remap/#svshape
826 "svshape2", # https://libre-soc.org/openpower/sv/remap/discussion TODO
827 "svstep", # https://libre-soc.org/openpower/sv/setvl
829 "sadd", "saddw", "sadduw",
830 "slbia", "sld", "slw", "srad", "sradi",
831 "sraw", "srawi", "srd", "srw",
832 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
833 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
834 "stfs", "stfsx", "stfsu", "stfux", "stfsux", # FP store single
835 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store double
836 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
837 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
838 "subf", "subfc", "subfco", "subfe", "subfeo", "subfic",
839 "subfme", "subfmeo", "subfo", "subfze", "subfzeo",
843 "tlbie", "tlbiel", "tlbsync",
846 "xor", "xori", "xoris",
850 # two-way lookup of instruction-to-index and vice-versa
853 for i
, insn
in enumerate(_insns
):
857 # must be long enough to cover all instructions
858 asmlen
= len(_insns
).bit_length()
860 # Internal Operation numbering. Add new opcodes here (FPADD, FPMUL etc.)
865 OP_ILLEGAL
= 0 # important that this is zero (see power_decoder.py)
939 OP_FPOP
= 77 # temporary: replace with actual ops
940 OP_FPOP_I
= 78 # temporary: replace with actual ops
977 SelType
.NONE
: "NONE",
988 RS
= 4 # for some ALU/Logical operations
995 CIA
= 8 # for addpcis
999 if self
is In1Sel
.RA_OR_ZERO
:
1005 if self
is In1Sel
.NONE
:
1024 RS
= 13 # for shiftrot (M-Form)
1028 CONST_SVD
= 15 # for SVD-Form
1029 CONST_SVDS
= 16 # for SVDS-Form
1031 CONST_DXHI4
= 18 # for addpcis
1032 CONST_DQ
= 19 # for ld/st-quad
1039 if self
is In2Sel
.NONE
:
1048 RB
= 2 # for shiftrot (M-Form)
1052 RC
= 5 # for SVP64 bit-reverse LD/ST
1053 RT
= 6 # for ternlog[i]
1062 if self
is In3Sel
.NONE
:
1083 if self
is OutSel
.RT_OR_ZERO
:
1089 if self
is OutSel
.NONE
:
1095 class LDSTLen(Enum
):
1102 # Backward compatibility
1107 class LDSTMode(Enum
):
1118 RC
= 2 # includes OE
1119 RC_ONLY
= 3 # does not include OE
1131 class CRInSel(Enum
):
1147 if self
is CRInSel
.NONE
:
1153 class CRIn2Sel(Enum
):
1162 if self
is CRIn2Sel
.NONE
:
1168 class CROutSel(Enum
):
1181 if self
is CROutSel
.NONE
:
1186 # SPRs - Special-Purpose Registers. See V3.0B Figure 18 p971 and
1187 # http://libre-riscv.org/openpower/isatables/sprs.csv
1188 # http://bugs.libre-riscv.org/show_bug.cgi?id=261
1189 # http://bugs.libre-riscv.org/show_bug.cgi?id=859 - KAIVB
1191 def get_spr_enum(full_file
):
1192 """get_spr_enum - creates an Enum of SPRs, dynamically
1193 has the option to reduce the enum to a much shorter list.
1194 this saves drastically on the size of the regfile
1196 short_list
= {'PIDR', 'DAR', 'PRTBL', 'DSISR', 'SVSRR0', 'SVSTATE',
1197 'SVSTATE0', 'SVSTATE1', 'SVSTATE2', 'SVSTATE3',
1198 'SPRG0_priv', 'SPRG1_priv', 'SPRG2_priv', 'SPRG3_priv',
1199 'SPRG0', 'SPRG1', 'SPRG2', 'SPRG3', 'KAIVB',
1200 # hmmm should not be including these, they are FAST regs
1201 'CTR', 'LR', 'TAR', 'SRR0', 'SRR1', 'XER', 'DEC', 'TB', 'TBU',
1202 'HSRR0', 'HSRR1', 'HSPRG0', 'HSPRG1',
1205 for row
in get_csv("sprs.csv"):
1206 if full_file
or row
['SPR'] in short_list
:
1209 spr_info
= namedtuple('spr_info', 'SPR priv_mtspr priv_mfspr length idx')
1213 info
= spr_info(SPR
=row
['SPR'], priv_mtspr
=row
['priv_mtspr'],
1214 priv_mfspr
=row
['priv_mfspr'], length
=int(row
['len']),
1215 idx
=int(row
['Idx']))
1216 spr_dict
[int(row
['Idx'])] = info
1217 spr_byname
[row
['SPR']] = info
1218 fields
= [(row
['SPR'], int(row
['Idx'])) for row
in spr_csv
]
1219 SPR
= Enum('SPR', fields
)
1220 return SPR
, spr_dict
, spr_byname
1223 SPRfull
, spr_dict
, spr_byname
= get_spr_enum(full_file
=True)
1224 SPRreduced
, _
, _
= get_spr_enum(full_file
=False)
1234 MSRSpec
= namedtuple("MSRSpec", ["dr", "pr", "sf"])
1236 # flags for bfp_* functions
1253 if __name__
== '__main__':
1254 # find out what the heck is in SPR enum :)
1255 print("sprs full", len(SPRfull
))
1257 print("sprs reduced", len(SPRreduced
))
1258 print(dir(SPRreduced
))
1260 print(SPRfull
.__members
__['TAR'])
1262 print("full", x
, x
.value
, str(x
), x
.name
)
1263 for x
in SPRreduced
:
1264 print("reduced", x
, x
.value
, str(x
), x
.name
)
1266 print("function", Function
.ALU
.name
)