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
195 def _missing_(cls
, desc
):
196 return {"1P": SVPType
.P1
, "2P": SVPType
.P2
}.get(desc
)
200 SVPType
.NONE
: "NONE",
217 class SVMaskSrc(Enum
):
232 Idx_1_2
= 5 # due to weird BA/BB for crops
236 SVExtra
.NONE
: "NONE",
241 SVExtra
.Idx_1_2
: "[1:2]",
244 # Backward compatibility
248 class SVExtraRegType(Enum
):
254 class SVExtraReg(Enum
):
289 def _missing_(cls
, desc
):
291 In1Sel
, In2Sel
, In3Sel
, CRInSel
, CRIn2Sel
,
294 if isinstance(desc
, selectors
):
295 return cls
.__members
__.get(desc
.name
)
297 return cls
.__members
__.get(desc
)
301 class SVP64PredMode(Enum
):
309 class SVP64PredInt(Enum
):
320 def _missing_(cls
, desc
):
321 if isinstance(desc
, str):
332 if value
.startswith("~"):
333 value
= f
"~{value[1:].strip()}"
334 elif "<<" in value
: # 1 << r3
335 (lhs
, _
, rhs
) = value
.partition("<<")
336 lhs
= lhs
.strip().lower()
337 rhs
= rhs
.strip().lower()
338 if (lhs
== "1") and (rhs
in ("r3", "%r3")):
341 return values
.get(value
)
343 return super()._missing
_(desc
)
347 self
.__class
__.ALWAYS
: "",
348 self
.__class
__.R3_UNARY
: "^r3",
349 self
.__class
__.R3
: "r3",
350 self
.__class
__.R3_N
: "~r3",
351 self
.__class
__.R10
: "r10",
352 self
.__class
__.R10_N
: "~r10",
353 self
.__class
__.R30
: "r30",
354 self
.__class
__.R30_N
: "~r30",
358 return f
"{self.__class__.__name__}({str(self)})"
365 return SVP64PredMode
.INT
369 return (self
.value
& 0b1)
373 return (self
.value
>> 1)
376 class SVP64PredCR(Enum
):
391 def _missing_(cls
, desc
):
392 if isinstance(desc
, str):
394 return cls
.__members
__.get(name
)
396 return super()._missing
_(desc
)
403 return SVP64PredMode
.CR
407 return (self
.value
& 0b1)
411 return (self
.value
>> 1)
415 class SVP64PredRC1(Enum
):
420 def _missing_(cls
, desc
):
422 "RC1": SVP64PredRC1
.RC1
,
423 "~RC1": SVP64PredRC1
.RC1_N
,
431 return SVP64PredMode
.RC1
435 return (self
is SVP64PredRC1
.RC1_N
)
442 class SVP64Pred(Enum
):
443 ALWAYS
= SVP64PredInt
.ALWAYS
444 R3_UNARY
= SVP64PredInt
.R3_UNARY
446 R3_N
= SVP64PredInt
.R3_N
447 R10
= SVP64PredInt
.R10
448 R10_N
= SVP64PredInt
.R10_N
449 R30
= SVP64PredInt
.R30
450 R30_N
= SVP64PredInt
.R30_N
461 RC1
= SVP64PredRC1
.RC1
462 RC1_N
= SVP64PredRC1
.RC1_N
465 def _missing_(cls
, desc
):
466 if isinstance(desc
, str):
467 values
= {item
.value
:item
for item
in cls
}
468 for subcls
in (SVP64PredInt
, SVP64PredCR
, SVP64PredRC1
):
470 return values
.get(subcls(desc
))
475 return super()._missing
_(desc
)
478 return int(self
.value
)
482 return self
.value
.mode
486 return self
.value
.inv
490 return self
.value
.state
494 class SVP64RMMode(Enum
):
504 class SVP64BCPredMode(Enum
):
511 class SVP64BCVLSETMode(Enum
):
517 # note that these are chosen to be exactly the same as
518 # SVP64 RM bit 4. ALL=1 => bit4=1
520 class SVP64BCGate(Enum
):
525 class SVP64BCCTRMode(Enum
):
532 class SVP64Width(Enum
):
539 def _missing_(cls
, desc
):
540 if isinstance(desc
, str):
542 "32": SVP64Width
.EW_32
,
543 "16": SVP64Width
.EW_16
,
544 "8": SVP64Width
.EW_8
,
547 return super()._missing
_(desc
)
551 class SVP64SubVL(Enum
):
558 def _missing_(cls
, desc
):
559 if isinstance(desc
, str):
561 return cls
.__members
__.get(name
)
563 return super()._missing
_(desc
)
567 class SVP64Sat(Enum
):
574 class SVP64LDSTmode(Enum
):
602 CR_3BIT
= 2 # CR field; the CR register is 32-bit
606 CR_5BIT
= 3 # bit of the 32-bit CR register
613 XER_BIT
= 4 # XER bits, includes OV, OV32, SO, CA, CA32
621 def _missing_(cls
, value
):
622 if isinstance(value
, SVExtraReg
):
623 return cls
.__members
__.get(value
.name
)
625 return super()._missing
_(value
)
630 "fatan2pi", "fatan2pis",
639 "fexp2m1", "fexp2m1s",
640 "flog2p1", "flog2p1s",
647 "fexp10m1", "fexp10m1s",
648 "flog10p1", "flog10p1s",
660 "fasinpi", "fasinpis",
661 "facospi", "facospis",
662 "fatanpi", "fatanpis",
669 # fmin*/fmax* need to be replaced with fminmax
670 # https://bugs.libre-soc.org/show_bug.cgi?id=1057
671 # commented for now to make space for fmv/cvt
672 # "fminnum08", "fminnum08s",
673 # "fmaxnum08", "fmaxnum08s",
674 # "fmin19", "fmin19s",
675 # "fmax19", "fmax19s",
676 # "fminnum19", "fminnum19s",
677 # "fmaxnum19", "fmaxnum19s",
680 # "fminmagnum08", "fminmagnum08s",
681 # "fmaxmagnum08", "fmaxmagnum08s",
682 # "fminmag19", "fminmag19s",
683 # "fmaxmag19", "fmaxmag19s",
684 # "fminmagnum19", "fminmagnum19s",
685 # "fmaxmagnum19", "fmaxmagnum19s",
686 # "fminmagc", "fminmagcs",
687 # "fmaxmagc", "fmaxmagcs",
689 "fremainder", "fremainders",
693 # supported instructions: make sure to keep up-to-date with CSV files
694 # just like everything else
696 "NONE", "add", "addc", "addco", "adde", "addeo",
697 "addi", "addic", "addic.", "addis",
698 "addme", "addmeo", "addo", "addze", "addzeo",
701 "and", "andc", "andi.", "andis.",
703 "absdu", "absds", # AV bitmanip
704 "absdacs", "absdacu", # AV bitmanip
705 "avgadd", # AV bitmanip
706 "b", "bc", "bcctr", "bclr", "bctar",
707 "bmask", # AV bitmanip
711 "cmp", "cmpb", "cmpeqb", "cmpi", "cmpl", "cmpli", "cmprb",
712 "cntlzd", "cntlzw", "cnttzd", "cnttzw",
713 "cprop", # AV bitmanip
714 "crand", "crandc", "creqv",
715 "crnand", "crnor", "cror", "crorc", "crxor",
717 "dcbf", "dcbst", "dcbt", "dcbtst", "dcbz",
718 "divd", "divde", "divdeo", "divdeu",
719 "divdeuo", "divdo", "divdu", "divduo",
721 "divw", "divwe", "divweo",
722 "divweu", "divweuo", "divwo", "divwu", "divwuo",
723 "dsld", "dsld.", "dsrd", "dsrd.",
725 "extsb", "extsh", "extsw", "extswsli",
726 "fadd", "fadds", "fsub", "fsubs", # FP add / sub
727 "fcfids", "fcfidus", "fsqrts", "fres", "frsqrtes", # FP stuff
728 "fdmadds", # DCT FP 3-arg
729 "fmsubs", "fmadds", "fnmsubs", "fnmadds", # FP 3-arg
730 "ffadds", "ffsubs", "ffmuls", "ffdivs", # FFT FP 2-arg
731 "ffmsubs", "ffmadds", "ffnmsubs", "ffnmadds", # FFT FP 3-arg
732 "fmul", "fmuls", "fdiv", "fdivs", # FP mul / div
733 "fmr", "fabs", "fnabs", "fneg", "fcpsgn", # FP move/abs/neg
734 "fmvis", # FP load immediate
735 "fishmv", # Float Replace Lower-Half Single, Immediate
736 'grev', 'grev.', 'grevi', 'grevi.',
737 'grevw', 'grevw.', 'grevwi', 'grevwi.',
738 "hrfid", "icbi", "icbt", "isel", "isync",
739 "lbarx", "lbz", "lbzcix", "lbzu", "lbzux", "lbzx", # load byte
740 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
741 # "lbzbr", "lbzubr", # load byte SVP64 bit-reversed
742 # "ldbr", "ldubr", # load double SVP64 bit-reversed
743 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
744 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load double
745 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
746 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
747 # "lhabr", "lhaubr", # load half SVP64 bit-reversed
748 # "lhzbr", "lhzubr", # more load half SVP64 bit-reversed
749 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
750 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
751 # "lwabr", # load word SVP64 bit-reversed
752 # "lwzbr", "lwzubr", # more load word SVP64 bit-reversed
753 "maddedu", "maddedus",
754 "maddhd", "maddhdu", "maddld", # INT multiply-and-add
755 "mcrf", "mcrxr", "mcrxrx", "mfcr/mfocrf", # CR mvs
757 "minmax", # AV bitmanip
758 "modsd", "modsw", "modud", "moduw",
759 "mtcrf/mtocrf", "mtmsr", "mtmsrd", "mtspr",
760 "mulhd", "mulhdu", "mulhw", "mulhwu", "mulld", "mulldo",
761 "mulli", "mullw", "mullwo",
762 "nand", "neg", "nego",
764 "nor", "or", "orc", "ori", "oris",
766 "popcntb", "popcntd", "popcntw",
769 "rldcl", "rldcr", "rldic", "rldicl", "rldicr", "rldimi",
770 "rlwimi", "rlwinm", "rlwnm",
772 "setvl", # https://libre-soc.org/openpower/sv/setvl
773 "svindex", # https://libre-soc.org/openpower/sv/remap
774 "svremap", # https://libre-soc.org/openpower/sv/remap - TEMPORARY
775 "svshape", # https://libre-soc.org/openpower/sv/remap/#svshape
776 "svshape2", # https://libre-soc.org/openpower/sv/remap/discussion TODO
777 "svstep", # https://libre-soc.org/openpower/sv/setvl
779 "shadd", "shaddw", "shadduw",
780 "slbia", "sld", "slw", "srad", "sradi",
781 "sraw", "srawi", "srd", "srw",
782 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
783 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
784 "stfs", "stfsx", "stfsu", "stfux", "stfsux", # FP store single
785 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store double
786 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
787 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
788 "subf", "subfc", "subfco", "subfe", "subfeo", "subfic",
789 "subfme", "subfmeo", "subfo", "subfze", "subfzeo",
793 "tlbie", "tlbiel", "tlbsync",
796 "xor", "xori", "xoris",
800 # two-way lookup of instruction-to-index and vice-versa
803 for i
, insn
in enumerate(_insns
):
807 # must be long enough to cover all instructions
808 asmlen
= len(_insns
).bit_length()
810 # Internal Operation numbering. Add new opcodes here (FPADD, FPMUL etc.)
815 OP_ILLEGAL
= 0 # important that this is zero (see power_decoder.py)
889 OP_FPOP
= 77 # temporary: replace with actual ops
890 OP_FPOP_I
= 78 # temporary: replace with actual ops
923 RS
= 4 # for some ALU/Logical operations
930 CIA
= 8 # for addpcis
948 RS
= 13 # for shiftrot (M-Form)
952 CONST_SVD
= 15 # for SVD-Form
953 CONST_SVDS
= 16 # for SVDS-Form
955 CONST_DXHI4
= 18 # for addpcis
956 CONST_DQ
= 19 # for ld/st-quad
963 RB
= 2 # for shiftrot (M-Form)
967 RC
= 5 # for SVP64 bit-reverse LD/ST
968 RT
= 6 # for ternlog[i]
997 # Backward compatibility
1002 class LDSTMode(Enum
):
1013 RC
= 2 # includes OE
1014 RC_ONLY
= 3 # does not include OE
1026 class CRInSel(Enum
):
1039 class CRIn2Sel(Enum
):
1045 class CROutSel(Enum
):
1054 # SPRs - Special-Purpose Registers. See V3.0B Figure 18 p971 and
1055 # http://libre-riscv.org/openpower/isatables/sprs.csv
1056 # http://bugs.libre-riscv.org/show_bug.cgi?id=261
1057 # http://bugs.libre-riscv.org/show_bug.cgi?id=859 - KAIVB
1059 def get_spr_enum(full_file
):
1060 """get_spr_enum - creates an Enum of SPRs, dynamically
1061 has the option to reduce the enum to a much shorter list.
1062 this saves drastically on the size of the regfile
1064 short_list
= {'PIDR', 'DAR', 'PRTBL', 'DSISR', 'SVSRR0', 'SVSTATE',
1065 'SVSTATE0', 'SVSTATE1', 'SVSTATE2', 'SVSTATE3',
1066 'SPRG0_priv', 'SPRG1_priv', 'SPRG2_priv', 'SPRG3_priv',
1067 'SPRG0', 'SPRG1', 'SPRG2', 'SPRG3', 'KAIVB',
1068 # hmmm should not be including these, they are FAST regs
1069 'CTR', 'LR', 'TAR', 'SRR0', 'SRR1', 'XER', 'DEC', 'TB', 'TBU',
1070 'HSRR0', 'HSRR1', 'HSPRG0', 'HSPRG1',
1073 for row
in get_csv("sprs.csv"):
1074 if full_file
or row
['SPR'] in short_list
:
1077 spr_info
= namedtuple('spr_info', 'SPR priv_mtspr priv_mfspr length idx')
1081 info
= spr_info(SPR
=row
['SPR'], priv_mtspr
=row
['priv_mtspr'],
1082 priv_mfspr
=row
['priv_mfspr'], length
=int(row
['len']),
1083 idx
=int(row
['Idx']))
1084 spr_dict
[int(row
['Idx'])] = info
1085 spr_byname
[row
['SPR']] = info
1086 fields
= [(row
['SPR'], int(row
['Idx'])) for row
in spr_csv
]
1087 SPR
= Enum('SPR', fields
)
1088 return SPR
, spr_dict
, spr_byname
1091 SPRfull
, spr_dict
, spr_byname
= get_spr_enum(full_file
=True)
1092 SPRreduced
, _
, _
= get_spr_enum(full_file
=False)
1102 MSRSpec
= namedtuple("MSRSpec", ["dr", "pr", "sf"])
1104 if __name__
== '__main__':
1105 # find out what the heck is in SPR enum :)
1106 print("sprs full", len(SPRfull
))
1108 print("sprs reduced", len(SPRreduced
))
1109 print(dir(SPRreduced
))
1111 print(SPRfull
.__members
__['TAR'])
1113 print("full", x
, x
.value
, str(x
), x
.name
)
1114 for x
in SPRreduced
:
1115 print("reduced", x
, x
.value
, str(x
), x
.name
)
1117 print("function", Function
.ALU
.name
)