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 retval
= _get_csv(name
)
44 return [i
.copy() for i
in retval
]
47 @functools.lru_cache()
49 """gets a not-entirely-csv-file-formatted database, which allows comments
51 file_path
= find_wiki_file(name
)
52 with
open(file_path
, 'r') as csvfile
:
53 csvfile
= filter(lambda row
: row
[0] !='#', csvfile
) # strip "#..."
54 reader
= csv
.DictReader(csvfile
)
58 # names of the fields in the tables that don't correspond to an enum
59 single_bit_flags
= ['inv A', 'inv out',
60 'cry out', 'BR', 'sgn ext', 'rsrv', '32b',
61 'sgn', 'lk', 'sgl pipe']
63 # default values for fields in the table
64 default_values
= {'unit': "NONE", 'internal op': "OP_ILLEGAL",
65 'in1': "RA", 'in2': 'NONE', 'in3': 'NONE', 'out': 'NONE',
69 'rc': 'NONE', 'cry in': 'ZERO', 'form': 'NONE'}
72 def get_signal_name(name
):
75 return name
.lower().replace(' ', '_')
80 def _missing_(cls
, desc
):
81 if isinstance(desc
, str):
89 keys
= {item
.name
:item
for item
in cls
}
90 descs
= {item
.value
:item
for item
in cls
}
91 return keys
.get(desc
, descs
.get(desc
))
94 # this corresponds to which Function Unit (pipeline-with-Reservation-Stations)
95 # is to process and guard the operation. they are roughly divided by having
96 # the same register input/output signature (X-Form, etc.)
100 class Function(Enum
):
113 SV
= 1 << 12 # Simple-V https://libre-soc.org/openpower/sv
117 @functools.lru_cache(maxsize
=None)
120 value
= int(self
.value
)
126 desc
= f
"(1 << {counter})"
129 return f
"<{self.__class__.__name__}.{self.name}: {desc}>"
163 SVL
= 29 # Simple-V for setvl instruction
164 SVD
= 30 # Simple-V for LD/ST bit-reverse, variant of D-Form
165 SVDS
= 31 # Simple-V for LD/ST bit-reverse, variant of DS-Form
166 SVM
= 32 # Simple-V SHAPE mode
167 SVM2
= 33 # Simple-V SHAPE2 mode - fits into SVM
168 SVRM
= 34 # Simple-V REMAP mode
172 SVI
= 38 # Simple-V Index Mode
176 CRB
= 42 # crternlogi / crbinlut
177 MM
= 43 # [f]minmax[s][.]
182 # Simple-V svp64 fields https://libre-soc.org/openpower/sv/svp64/
186 NONE
= 0 # for non-SV instructions only
199 P2M
= 3 # for mixed EXTRA3/3/2 where MASK_SRC is RM[6,7,18]
202 def _missing_(cls
, desc
):
203 return {"1P": SVPType
.P1
, "2P": SVPType
.P2
, "2PM": SVPType
.P2M
}.get(desc
)
207 SVPType
.NONE
: "NONE",
217 * EXTRA2 : 0: [10,11] 1: [12,13] 2: [14,15] 3: [16,17] unused: [18]
218 * EXTRA3 : 0: [10,11,12] 1: [13,14,15] mask: [16,17,18]
219 * EXTRA32: 0: [10,11,12] 1: [13,14,15] 2: [16,17] mask: [6,7,18]
224 EXTRA32
= 3 # mixed EXTRA3 and EXTRA2 using RM bits 6&7 for MASK_SRC
231 class SVMaskSrc(Enum
):
246 Idx_1_2
= 5 # due to weird BA/BB for crops
250 SVExtra
.NONE
: "NONE",
251 SVExtra
.Idx0
: "EXTRA0",
252 SVExtra
.Idx1
: "EXTRA1",
253 SVExtra
.Idx2
: "EXTRA2",
254 SVExtra
.Idx3
: "EXTRA3",
255 SVExtra
.Idx_1_2
: "EXTRA1/EXTRA2",
258 # Backward compatibility
301 def _missing_(cls
, desc
):
303 In1Sel
, In2Sel
, In3Sel
, CRInSel
, CRIn2Sel
,
306 if isinstance(desc
, selectors
):
307 return cls
.__members
__.get(desc
.name
)
309 return cls
.__members
__.get(desc
)
321 if alias
is not None:
325 Reg
.RA_OR_ZERO
: Reg
.RA
,
326 Reg
.RT_OR_ZERO
: Reg
.RT
,
328 if alias
is not None:
353 class SVP64PredMode(Enum
):
361 class SVP64PredInt(Enum
):
372 def _missing_(cls
, desc
):
373 if isinstance(desc
, str):
384 if value
.startswith("~"):
385 value
= f
"~{value[1:].strip()}"
386 elif "<<" in value
: # 1 << r3
387 (lhs
, _
, rhs
) = value
.partition("<<")
388 lhs
= lhs
.strip().lower()
389 rhs
= rhs
.strip().lower()
390 if (lhs
== "1") and (rhs
in ("r3", "%r3")):
393 return values
.get(value
)
395 return super()._missing
_(desc
)
399 self
.__class
__.ALWAYS
: "",
400 self
.__class
__.R3_UNARY
: "^r3",
401 self
.__class
__.R3
: "r3",
402 self
.__class
__.R3_N
: "~r3",
403 self
.__class
__.R10
: "r10",
404 self
.__class
__.R10_N
: "~r10",
405 self
.__class
__.R30
: "r30",
406 self
.__class
__.R30_N
: "~r30",
410 return f
"{self.__class__.__name__}({str(self)})"
417 return SVP64PredMode
.INT
421 return (self
.value
& 0b1)
425 return (self
.value
>> 1)
428 class SVP64PredCR(Enum
):
443 def _missing_(cls
, desc
):
444 if isinstance(desc
, str):
446 return cls
.__members
__.get(name
)
448 return super()._missing
_(desc
)
455 return SVP64PredMode
.CR
459 return (self
.value
& 0b1)
463 return (self
.value
>> 1)
467 class SVP64PredRC1(Enum
):
472 def _missing_(cls
, desc
):
474 "RC1": SVP64PredRC1
.RC1
,
475 "~RC1": SVP64PredRC1
.RC1_N
,
483 return SVP64PredMode
.RC1
487 return (self
is SVP64PredRC1
.RC1_N
)
494 class SVP64Pred(Enum
):
495 ALWAYS
= SVP64PredInt
.ALWAYS
496 R3_UNARY
= SVP64PredInt
.R3_UNARY
498 R3_N
= SVP64PredInt
.R3_N
499 R10
= SVP64PredInt
.R10
500 R10_N
= SVP64PredInt
.R10_N
501 R30
= SVP64PredInt
.R30
502 R30_N
= SVP64PredInt
.R30_N
513 RC1
= SVP64PredRC1
.RC1
514 RC1_N
= SVP64PredRC1
.RC1_N
517 def _missing_(cls
, desc
):
518 if isinstance(desc
, str):
519 values
= {item
.value
:item
for item
in cls
}
520 for subcls
in (SVP64PredInt
, SVP64PredCR
, SVP64PredRC1
):
522 return values
.get(subcls(desc
))
527 return super()._missing
_(desc
)
530 return int(self
.value
)
534 return self
.value
.mode
538 return self
.value
.inv
542 return self
.value
.state
546 class SVP64RMMode(Enum
):
555 class SVP64BCPredMode(Enum
):
562 class SVP64BCVLSETMode(Enum
):
568 # note that these are chosen to be exactly the same as
569 # SVP64 RM bit 4. ALL=1 => bit4=1
571 class SVP64BCGate(Enum
):
576 class SVP64BCCTRMode(Enum
):
583 class SVP64Width(Enum
):
590 def _missing_(cls
, desc
):
591 if isinstance(desc
, str):
593 "32": SVP64Width
.EW_32
,
594 "16": SVP64Width
.EW_16
,
595 "8": SVP64Width
.EW_8
,
598 return super()._missing
_(desc
)
602 class SVP64SubVL(Enum
):
609 def _missing_(cls
, desc
):
610 if isinstance(desc
, str):
612 return cls
.__members
__.get(name
)
614 return super()._missing
_(desc
)
618 class SVP64Sat(Enum
):
625 class SVP64LDSTmode(Enum
):
653 CR_3BIT
= 2 # CR field; the CR register is 32-bit
658 CR_5BIT
= 3 # bit of the 32-bit CR register
665 XER_BIT
= 4 # XER bits, includes OV, OV32, SO, CA, CA32
673 def _missing_(cls
, value
):
674 if isinstance(value
, Reg
):
675 return cls
.__members
__.get(value
.name
)
677 return super()._missing
_(value
)
682 "fatan2pi", "fatan2pis",
691 "fexp2m1", "fexp2m1s",
692 "flog2p1", "flog2p1s",
699 "fexp10m1", "fexp10m1s",
700 "flog10p1", "flog10p1s",
712 "fasinpi", "fasinpis",
713 "facospi", "facospis",
714 "fatanpi", "fatanpis",
723 "fremainder", "fremainders",
727 # supported instructions: make sure to keep up-to-date with CSV files
728 # just like everything else
730 "NONE", "add", "addc", "addco", "adde", "addeo",
731 "addi", "addic", "addic.", "addis",
732 "addme", "addmeo", "addo", "addze", "addzeo",
735 "and", "andc", "andi.", "andis.",
737 "absdu", "absds", # AV bitmanip
738 "absdacs", "absdacu", # AV bitmanip
739 "avgadd", # AV bitmanip
740 "b", "bc", "bcctr", "bclr", "bctar",
742 "bmask", # AV bitmanip
747 "cmp", "cmpb", "cmpeqb", "cmpi", "cmpl", "cmpli", "cmprb",
748 "cntlzd", "cntlzdm", "cntlzw", "cnttzd", "cnttzdm", "cnttzw",
749 "cprop", # AV bitmanip
750 "crand", "crandc", "creqv",
751 "crnand", "crnor", "cror", "crorc", "crxor",
752 "crternlogi", # ternary bitmanip
754 "dcbf", "dcbst", "dcbt", "dcbtst", "dcbz",
755 "divd", "divde", "divdeo", "divdeu",
756 "divdeuo", "divdo", "divdu", "divduo",
758 "divw", "divwe", "divweo",
759 "divweu", "divweuo", "divwo", "divwu", "divwuo",
760 "dsld", "dsld.", "dsrd", "dsrd.",
762 "extsb", "extsh", "extsw", "extswsli",
763 "fadd", "fadds", "fsub", "fsubs", # FP add / sub
764 "fcfids", "fcfidus", "fsqrts", "fres", "frsqrtes", # FP stuff
765 "fdmadds", # DCT FP 3-arg
766 "fmsubs", "fmadds", "fnmsubs", "fnmadds", # FP 3-arg
767 "ffadds", "ffsubs", "ffmuls", "ffdivs", # FFT FP 2-arg
768 "ffmsubs", "ffmadds", "ffnmsubs", "ffnmadds", # FFT FP 3-arg
769 "fmul", "fmuls", "fdiv", "fdivs", # FP mul / div
770 "fmr", "fabs", "fnabs", "fneg", "fcpsgn", # FP move/abs/neg
771 "fmvis", # FP load immediate
772 "fishmv", # Float Replace Lower-Half Single, Immediate
773 "gbbd", # bitmanip - (aka bmatflip)
778 "hrfid", "icbi", "icbt", "isel", "isync",
779 "lbarx", "lbz", "lbzcix", "lbzu", "lbzux", "lbzx", # load byte
780 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
781 # "lbzbr", "lbzubr", # load byte SVP64 bit-reversed
782 # "ldbr", "ldubr", # load double SVP64 bit-reversed
783 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
784 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load double
785 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
786 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
787 # "lhabr", "lhaubr", # load half SVP64 bit-reversed
788 # "lhzbr", "lhzubr", # more load half SVP64 bit-reversed
789 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
790 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
791 # "lwabr", # load word SVP64 bit-reversed
792 # "lwzbr", "lwzubr", # more load word SVP64 bit-reversed
793 "maddedu", "maddedus",
794 "maddhd", "maddhdu", "maddld", # INT multiply-and-add
795 "maddsubrs", # Int DCT Butterfly Add Sub and Round Shift
796 "maddrs", # Int DCT Butterfly Add and Accumulate and Round Shift
797 "msubrs", # Int DCT Butterfly Subtract from and Round Shift
798 "mcrf", "mcrxr", "mcrxrx", "mfcr/mfocrf", # CR mvs
800 "minmax", # AV bitmanip
801 "modsd", "modsw", "modud", "moduw",
802 "mtcrf/mtocrf", "mtmsr", "mtmsrd", "mtspr",
803 "mulhd", "mulhdu", "mulhw", "mulhwu", "mulld", "mulldo",
804 "mulli", "mullw", "mullwo",
805 "nand", "neg", "nego",
807 "nor", "or", "orc", "ori", "oris",
810 "popcntb", "popcntd", "popcntw",
813 "rldcl", "rldcr", "rldic", "rldicl", "rldicr", "rldimi",
814 "rlwimi", "rlwinm", "rlwnm",
816 "setbc", "setbcr", "setnbc", "setnbcr",
817 "setvl", # https://libre-soc.org/openpower/sv/setvl
819 "svindex", # https://libre-soc.org/openpower/sv/remap
820 "svremap", # https://libre-soc.org/openpower/sv/remap - TEMPORARY
821 "svshape", # https://libre-soc.org/openpower/sv/remap/#svshape
822 "svshape2", # https://libre-soc.org/openpower/sv/remap/discussion TODO
823 "svstep", # https://libre-soc.org/openpower/sv/setvl
825 "sadd", "saddw", "sadduw",
826 "slbia", "sld", "slw", "srad", "sradi",
827 "sraw", "srawi", "srd", "srw",
828 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
829 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
830 "stfs", "stfsx", "stfsu", "stfux", "stfsux", # FP store single
831 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store double
832 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
833 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
834 "subf", "subfc", "subfco", "subfe", "subfeo", "subfic",
835 "subfme", "subfmeo", "subfo", "subfze", "subfzeo",
839 "tlbie", "tlbiel", "tlbsync",
842 "xor", "xori", "xoris",
846 # two-way lookup of instruction-to-index and vice-versa
849 for i
, insn
in enumerate(_insns
):
853 # must be long enough to cover all instructions
854 asmlen
= len(_insns
).bit_length()
856 # Internal Operation numbering. Add new opcodes here (FPADD, FPMUL etc.)
861 OP_ILLEGAL
= 0 # important that this is zero (see power_decoder.py)
935 OP_FPOP
= 77 # temporary: replace with actual ops
936 OP_FPOP_I
= 78 # temporary: replace with actual ops
970 OP_BMAT
= 112 # bmatflip/xor/and - known by many names (vgbbd in Power)
981 SelType
.NONE
: "NONE",
992 RS
= 4 # for some ALU/Logical operations
999 CIA
= 8 # for addpcis
1003 if self
is In1Sel
.RA_OR_ZERO
:
1009 if self
is In1Sel
.NONE
:
1028 RS
= 13 # for shiftrot (M-Form)
1032 CONST_SVD
= 15 # for SVD-Form
1033 CONST_SVDS
= 16 # for SVDS-Form
1035 CONST_DXHI4
= 18 # for addpcis
1036 CONST_DQ
= 19 # for ld/st-quad
1043 if self
is In2Sel
.NONE
:
1052 RB
= 2 # for shiftrot (M-Form)
1056 RC
= 5 # for SVP64 bit-reverse LD/ST
1057 RT
= 6 # for ternlog[i]
1066 if self
is In3Sel
.NONE
:
1087 if self
is OutSel
.RT_OR_ZERO
:
1093 if self
is OutSel
.NONE
:
1099 class LDSTLen(Enum
):
1106 # Backward compatibility
1111 class LDSTMode(Enum
):
1122 RC
= 2 # includes OE
1123 RC_ONLY
= 3 # does not include OE
1135 class CRInSel(Enum
):
1152 if self
is CRInSel
.NONE
:
1158 class CRIn2Sel(Enum
):
1167 if self
is CRIn2Sel
.NONE
:
1173 class CROutSel(Enum
):
1186 if self
is CROutSel
.NONE
:
1191 # SPRs - Special-Purpose Registers. See V3.0B Figure 18 p971 and
1192 # http://libre-riscv.org/openpower/isatables/sprs.csv
1193 # http://bugs.libre-riscv.org/show_bug.cgi?id=261
1194 # http://bugs.libre-riscv.org/show_bug.cgi?id=859 - KAIVB
1196 def get_spr_enum(full_file
):
1197 """get_spr_enum - creates an Enum of SPRs, dynamically
1198 has the option to reduce the enum to a much shorter list.
1199 this saves drastically on the size of the regfile
1201 short_list
= {'PIDR', 'DAR', 'PRTBL', 'DSISR', 'SVSRR0', 'SVSTATE',
1202 'SVSTATE0', 'SVSTATE1', 'SVSTATE2', 'SVSTATE3',
1203 'SPRG0_priv', 'SPRG1_priv', 'SPRG2_priv', 'SPRG3_priv',
1204 'SPRG0', 'SPRG1', 'SPRG2', 'SPRG3', 'KAIVB',
1205 # hmmm should not be including these, they are FAST regs
1206 'CTR', 'LR', 'TAR', 'SRR0', 'SRR1', 'XER', 'DEC', 'TB', 'TBU',
1207 'HSRR0', 'HSRR1', 'HSPRG0', 'HSPRG1',
1210 for row
in get_csv("sprs.csv"):
1211 if full_file
or row
['SPR'] in short_list
:
1214 spr_info
= namedtuple('spr_info', 'SPR priv_mtspr priv_mfspr length idx')
1218 info
= spr_info(SPR
=row
['SPR'], priv_mtspr
=row
['priv_mtspr'],
1219 priv_mfspr
=row
['priv_mfspr'], length
=int(row
['len']),
1220 idx
=int(row
['Idx']))
1221 spr_dict
[int(row
['Idx'])] = info
1222 spr_byname
[row
['SPR']] = info
1223 fields
= [(row
['SPR'], int(row
['Idx'])) for row
in spr_csv
]
1224 SPR
= Enum('SPR', fields
)
1225 return SPR
, spr_dict
, spr_byname
1228 SPRfull
, spr_dict
, spr_byname
= get_spr_enum(full_file
=True)
1229 SPRreduced
, _
, _
= get_spr_enum(full_file
=False)
1239 MSRSpec
= namedtuple("MSRSpec", ["dr", "pr", "sf"])
1241 # flags for bfp_* functions
1260 class FMinMaxMode(Enum
):
1261 """ FMM field for fminmax instruction.
1262 enumerant names match assembly aliases.
1268 fminmagnum08
= 0b0100
1270 fminmagnum19
= 0b0110
1276 fmaxmagnum08
= 0b1100
1278 fmaxmagnum19
= 0b1110
1281 if __name__
== '__main__':
1282 # find out what the heck is in SPR enum :)
1283 print("sprs full", len(SPRfull
))
1285 print("sprs reduced", len(SPRreduced
))
1286 print(dir(SPRreduced
))
1288 print(SPRfull
.__members
__['TAR'])
1290 print("full", x
, x
.value
, str(x
), x
.name
)
1291 for x
in SPRreduced
:
1292 print("reduced", x
, x
.value
, str(x
), x
.name
)
1294 print("function", Function
.ALU
.name
)