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
300 def _missing_(cls
, desc
):
302 In1Sel
, In2Sel
, In3Sel
, CRInSel
, CRIn2Sel
,
305 if isinstance(desc
, selectors
):
306 return cls
.__members
__.get(desc
.name
)
308 return cls
.__members
__.get(desc
)
320 if alias
is not None:
324 Reg
.RA_OR_ZERO
: Reg
.RA
,
325 Reg
.RT_OR_ZERO
: Reg
.RT
,
327 if alias
is not None:
352 class SVP64PredMode(Enum
):
360 class SVP64PredInt(Enum
):
371 def _missing_(cls
, desc
):
372 if isinstance(desc
, str):
383 if value
.startswith("~"):
384 value
= f
"~{value[1:].strip()}"
385 elif "<<" in value
: # 1 << r3
386 (lhs
, _
, rhs
) = value
.partition("<<")
387 lhs
= lhs
.strip().lower()
388 rhs
= rhs
.strip().lower()
389 if (lhs
== "1") and (rhs
in ("r3", "%r3")):
392 return values
.get(value
)
394 return super()._missing
_(desc
)
398 self
.__class
__.ALWAYS
: "",
399 self
.__class
__.R3_UNARY
: "^r3",
400 self
.__class
__.R3
: "r3",
401 self
.__class
__.R3_N
: "~r3",
402 self
.__class
__.R10
: "r10",
403 self
.__class
__.R10_N
: "~r10",
404 self
.__class
__.R30
: "r30",
405 self
.__class
__.R30_N
: "~r30",
409 return f
"{self.__class__.__name__}({str(self)})"
416 return SVP64PredMode
.INT
420 return (self
.value
& 0b1)
424 return (self
.value
>> 1)
427 class SVP64PredCR(Enum
):
442 def _missing_(cls
, desc
):
443 if isinstance(desc
, str):
445 return cls
.__members
__.get(name
)
447 return super()._missing
_(desc
)
454 return SVP64PredMode
.CR
458 return (self
.value
& 0b1)
462 return (self
.value
>> 1)
466 class SVP64PredRC1(Enum
):
471 def _missing_(cls
, desc
):
473 "RC1": SVP64PredRC1
.RC1
,
474 "~RC1": SVP64PredRC1
.RC1_N
,
482 return SVP64PredMode
.RC1
486 return (self
is SVP64PredRC1
.RC1_N
)
493 class SVP64Pred(Enum
):
494 ALWAYS
= SVP64PredInt
.ALWAYS
495 R3_UNARY
= SVP64PredInt
.R3_UNARY
497 R3_N
= SVP64PredInt
.R3_N
498 R10
= SVP64PredInt
.R10
499 R10_N
= SVP64PredInt
.R10_N
500 R30
= SVP64PredInt
.R30
501 R30_N
= SVP64PredInt
.R30_N
512 RC1
= SVP64PredRC1
.RC1
513 RC1_N
= SVP64PredRC1
.RC1_N
516 def _missing_(cls
, desc
):
517 if isinstance(desc
, str):
518 values
= {item
.value
:item
for item
in cls
}
519 for subcls
in (SVP64PredInt
, SVP64PredCR
, SVP64PredRC1
):
521 return values
.get(subcls(desc
))
526 return super()._missing
_(desc
)
529 return int(self
.value
)
533 return self
.value
.mode
537 return self
.value
.inv
541 return self
.value
.state
545 class SVP64RMMode(Enum
):
554 class SVP64BCPredMode(Enum
):
561 class SVP64BCVLSETMode(Enum
):
567 # note that these are chosen to be exactly the same as
568 # SVP64 RM bit 4. ALL=1 => bit4=1
570 class SVP64BCGate(Enum
):
575 class SVP64BCCTRMode(Enum
):
582 class SVP64Width(Enum
):
589 def _missing_(cls
, desc
):
590 if isinstance(desc
, str):
592 "32": SVP64Width
.EW_32
,
593 "16": SVP64Width
.EW_16
,
594 "8": SVP64Width
.EW_8
,
597 return super()._missing
_(desc
)
601 class SVP64SubVL(Enum
):
608 def _missing_(cls
, desc
):
609 if isinstance(desc
, str):
611 return cls
.__members
__.get(name
)
613 return super()._missing
_(desc
)
617 class SVP64Sat(Enum
):
624 class SVP64LDSTmode(Enum
):
652 CR_3BIT
= 2 # CR field; the CR register is 32-bit
656 CR_5BIT
= 3 # bit of the 32-bit CR register
663 XER_BIT
= 4 # XER bits, includes OV, OV32, SO, CA, CA32
671 def _missing_(cls
, value
):
672 if isinstance(value
, Reg
):
673 return cls
.__members
__.get(value
.name
)
675 return super()._missing
_(value
)
680 "fatan2pi", "fatan2pis",
689 "fexp2m1", "fexp2m1s",
690 "flog2p1", "flog2p1s",
697 "fexp10m1", "fexp10m1s",
698 "flog10p1", "flog10p1s",
710 "fasinpi", "fasinpis",
711 "facospi", "facospis",
712 "fatanpi", "fatanpis",
719 # fmin*/fmax* need to be replaced with fminmax
720 # https://bugs.libre-soc.org/show_bug.cgi?id=1057
721 # commented for now to make space for fmv/cvt
722 # "fminnum08", "fminnum08s",
723 # "fmaxnum08", "fmaxnum08s",
724 # "fmin19", "fmin19s",
725 # "fmax19", "fmax19s",
726 # "fminnum19", "fminnum19s",
727 # "fmaxnum19", "fmaxnum19s",
730 # "fminmagnum08", "fminmagnum08s",
731 # "fmaxmagnum08", "fmaxmagnum08s",
732 # "fminmag19", "fminmag19s",
733 # "fmaxmag19", "fmaxmag19s",
734 # "fminmagnum19", "fminmagnum19s",
735 # "fmaxmagnum19", "fmaxmagnum19s",
736 # "fminmagc", "fminmagcs",
737 # "fmaxmagc", "fmaxmagcs",
739 "fremainder", "fremainders",
743 # supported instructions: make sure to keep up-to-date with CSV files
744 # just like everything else
746 "NONE", "add", "addc", "addco", "adde", "addeo",
747 "addi", "addic", "addic.", "addis",
748 "addme", "addmeo", "addo", "addze", "addzeo",
751 "and", "andc", "andi.", "andis.",
753 "absdu", "absds", # AV bitmanip
754 "absdacs", "absdacu", # AV bitmanip
755 "avgadd", # AV bitmanip
756 "b", "bc", "bcctr", "bclr", "bctar",
757 "bmask", # AV bitmanip
761 "cmp", "cmpb", "cmpeqb", "cmpi", "cmpl", "cmpli", "cmprb",
762 "cntlzd", "cntlzw", "cnttzd", "cnttzw",
763 "cprop", # AV bitmanip
764 "crand", "crandc", "creqv",
765 "crnand", "crnor", "cror", "crorc", "crxor",
767 "dcbf", "dcbst", "dcbt", "dcbtst", "dcbz",
768 "divd", "divde", "divdeo", "divdeu",
769 "divdeuo", "divdo", "divdu", "divduo",
771 "divw", "divwe", "divweo",
772 "divweu", "divweuo", "divwo", "divwu", "divwuo",
773 "dsld", "dsld.", "dsrd", "dsrd.",
775 "extsb", "extsh", "extsw", "extswsli",
776 "fadd", "fadds", "fsub", "fsubs", # FP add / sub
777 "fcfids", "fcfidus", "fsqrts", "fres", "frsqrtes", # FP stuff
778 "fdmadds", # DCT FP 3-arg
779 "fmsubs", "fmadds", "fnmsubs", "fnmadds", # FP 3-arg
780 "ffadds", "ffsubs", "ffmuls", "ffdivs", # FFT FP 2-arg
781 "ffmsubs", "ffmadds", "ffnmsubs", "ffnmadds", # FFT FP 3-arg
782 "fmul", "fmuls", "fdiv", "fdivs", # FP mul / div
783 "fmr", "fabs", "fnabs", "fneg", "fcpsgn", # FP move/abs/neg
784 "fmvis", # FP load immediate
785 "fishmv", # Float Replace Lower-Half Single, Immediate
790 'grev', 'grev.', 'grevi', 'grevi.',
791 'grevw', 'grevw.', 'grevwi', 'grevwi.',
792 "hrfid", "icbi", "icbt", "isel", "isync",
793 "lbarx", "lbz", "lbzcix", "lbzu", "lbzux", "lbzx", # load byte
794 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
795 # "lbzbr", "lbzubr", # load byte SVP64 bit-reversed
796 # "ldbr", "ldubr", # load double SVP64 bit-reversed
797 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
798 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load double
799 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
800 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
801 # "lhabr", "lhaubr", # load half SVP64 bit-reversed
802 # "lhzbr", "lhzubr", # more load half SVP64 bit-reversed
803 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
804 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
805 # "lwabr", # load word SVP64 bit-reversed
806 # "lwzbr", "lwzubr", # more load word SVP64 bit-reversed
807 "maddedu", "maddedus",
808 "maddhd", "maddhdu", "maddld", # INT multiply-and-add
809 "maddsubrs", # Integer DCT Butterfly Add Sub and Round Shift
810 "maddrs", # Integer DCT Butterfly Add and Accumulate and Round Shift
811 "mcrf", "mcrxr", "mcrxrx", "mfcr/mfocrf", # CR mvs
813 "minmax", # AV bitmanip
814 "modsd", "modsw", "modud", "moduw",
815 "mtcrf/mtocrf", "mtmsr", "mtmsrd", "mtspr",
816 "mulhd", "mulhdu", "mulhw", "mulhwu", "mulld", "mulldo",
817 "mulli", "mullw", "mullwo",
818 "nand", "neg", "nego",
820 "nor", "or", "orc", "ori", "oris",
822 "popcntb", "popcntd", "popcntw",
825 "rldcl", "rldcr", "rldic", "rldicl", "rldicr", "rldimi",
826 "rlwimi", "rlwinm", "rlwnm",
828 "setvl", # https://libre-soc.org/openpower/sv/setvl
829 "svindex", # https://libre-soc.org/openpower/sv/remap
830 "svremap", # https://libre-soc.org/openpower/sv/remap - TEMPORARY
831 "svshape", # https://libre-soc.org/openpower/sv/remap/#svshape
832 "svshape2", # https://libre-soc.org/openpower/sv/remap/discussion TODO
833 "svstep", # https://libre-soc.org/openpower/sv/setvl
835 "sadd", "saddw", "sadduw",
836 "slbia", "sld", "slw", "srad", "sradi",
837 "sraw", "srawi", "srd", "srw",
838 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
839 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
840 "stfs", "stfsx", "stfsu", "stfux", "stfsux", # FP store single
841 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store double
842 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
843 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
844 "subf", "subfc", "subfco", "subfe", "subfeo", "subfic",
845 "subfme", "subfmeo", "subfo", "subfze", "subfzeo",
849 "tlbie", "tlbiel", "tlbsync",
852 "xor", "xori", "xoris",
856 # two-way lookup of instruction-to-index and vice-versa
859 for i
, insn
in enumerate(_insns
):
863 # must be long enough to cover all instructions
864 asmlen
= len(_insns
).bit_length()
866 # Internal Operation numbering. Add new opcodes here (FPADD, FPMUL etc.)
871 OP_ILLEGAL
= 0 # important that this is zero (see power_decoder.py)
945 OP_FPOP
= 77 # temporary: replace with actual ops
946 OP_FPOP_I
= 78 # temporary: replace with actual ops
983 SelType
.NONE
: "NONE",
994 RS
= 4 # for some ALU/Logical operations
1001 CIA
= 8 # for addpcis
1005 if self
is In1Sel
.RA_OR_ZERO
:
1011 if self
is In1Sel
.NONE
:
1030 RS
= 13 # for shiftrot (M-Form)
1034 CONST_SVD
= 15 # for SVD-Form
1035 CONST_SVDS
= 16 # for SVDS-Form
1037 CONST_DXHI4
= 18 # for addpcis
1038 CONST_DQ
= 19 # for ld/st-quad
1045 if self
is In2Sel
.NONE
:
1054 RB
= 2 # for shiftrot (M-Form)
1058 RC
= 5 # for SVP64 bit-reverse LD/ST
1059 RT
= 6 # for ternlog[i]
1068 if self
is In3Sel
.NONE
:
1089 if self
is OutSel
.RT_OR_ZERO
:
1095 if self
is OutSel
.NONE
:
1101 class LDSTLen(Enum
):
1108 # Backward compatibility
1113 class LDSTMode(Enum
):
1124 RC
= 2 # includes OE
1125 RC_ONLY
= 3 # does not include OE
1137 class CRInSel(Enum
):
1153 if self
is CRInSel
.NONE
:
1159 class CRIn2Sel(Enum
):
1168 if self
is CRIn2Sel
.NONE
:
1174 class CROutSel(Enum
):
1187 if self
is CROutSel
.NONE
:
1192 # SPRs - Special-Purpose Registers. See V3.0B Figure 18 p971 and
1193 # http://libre-riscv.org/openpower/isatables/sprs.csv
1194 # http://bugs.libre-riscv.org/show_bug.cgi?id=261
1195 # http://bugs.libre-riscv.org/show_bug.cgi?id=859 - KAIVB
1197 def get_spr_enum(full_file
):
1198 """get_spr_enum - creates an Enum of SPRs, dynamically
1199 has the option to reduce the enum to a much shorter list.
1200 this saves drastically on the size of the regfile
1202 short_list
= {'PIDR', 'DAR', 'PRTBL', 'DSISR', 'SVSRR0', 'SVSTATE',
1203 'SVSTATE0', 'SVSTATE1', 'SVSTATE2', 'SVSTATE3',
1204 'SPRG0_priv', 'SPRG1_priv', 'SPRG2_priv', 'SPRG3_priv',
1205 'SPRG0', 'SPRG1', 'SPRG2', 'SPRG3', 'KAIVB',
1206 # hmmm should not be including these, they are FAST regs
1207 'CTR', 'LR', 'TAR', 'SRR0', 'SRR1', 'XER', 'DEC', 'TB', 'TBU',
1208 'HSRR0', 'HSRR1', 'HSPRG0', 'HSPRG1',
1211 for row
in get_csv("sprs.csv"):
1212 if full_file
or row
['SPR'] in short_list
:
1215 spr_info
= namedtuple('spr_info', 'SPR priv_mtspr priv_mfspr length idx')
1219 info
= spr_info(SPR
=row
['SPR'], priv_mtspr
=row
['priv_mtspr'],
1220 priv_mfspr
=row
['priv_mfspr'], length
=int(row
['len']),
1221 idx
=int(row
['Idx']))
1222 spr_dict
[int(row
['Idx'])] = info
1223 spr_byname
[row
['SPR']] = info
1224 fields
= [(row
['SPR'], int(row
['Idx'])) for row
in spr_csv
]
1225 SPR
= Enum('SPR', fields
)
1226 return SPR
, spr_dict
, spr_byname
1229 SPRfull
, spr_dict
, spr_byname
= get_spr_enum(full_file
=True)
1230 SPRreduced
, _
, _
= get_spr_enum(full_file
=False)
1240 MSRSpec
= namedtuple("MSRSpec", ["dr", "pr", "sf"])
1242 # flags for bfp_* functions
1259 if __name__
== '__main__':
1260 # find out what the heck is in SPR enum :)
1261 print("sprs full", len(SPRfull
))
1263 print("sprs reduced", len(SPRreduced
))
1264 print(dir(SPRreduced
))
1266 print(SPRfull
.__members
__['TAR'])
1268 print("full", x
, x
.value
, str(x
), x
.name
)
1269 for x
in SPRreduced
:
1270 print("reduced", x
, x
.value
, str(x
), x
.name
)
1272 print("function", Function
.ALU
.name
)