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
172 # Simple-V svp64 fields https://libre-soc.org/openpower/sv/svp64/
176 NONE
= 0 # for non-SV instructions only
191 def _missing_(cls
, desc
):
192 return {"1P": SVPType
.P1
, "2P": SVPType
.P2
}.get(desc
)
196 SVPType
.NONE
: "NONE",
213 class SVMaskSrc(Enum
):
228 Idx_1_2
= 5 # due to weird BA/BB for crops
232 SVExtra
.NONE
: "NONE",
237 SVExtra
.Idx_1_2
: "[1:2]",
240 # Backward compatibility
244 class SVExtraRegType(Enum
):
250 class SVExtraReg(Enum
):
285 def _missing_(cls
, desc
):
287 In1Sel
, In2Sel
, In3Sel
, CRInSel
, CRIn2Sel
,
290 if isinstance(desc
, selectors
):
291 return cls
.__members
__.get(desc
.name
)
293 return cls
.__members
__.get(desc
)
297 class SVP64PredMode(Enum
):
305 class SVP64PredInt(Enum
):
316 def _missing_(cls
, desc
):
317 if isinstance(desc
, str):
328 if value
.startswith("~"):
329 value
= f
"~{value[1:].strip()}"
330 elif "<<" in value
: # 1 << r3
331 (lhs
, _
, rhs
) = value
.partition("<<")
332 lhs
= lhs
.strip().lower()
333 rhs
= rhs
.strip().lower()
334 if (lhs
== "1") and (rhs
in ("r3", "%r3")):
337 return values
.get(value
)
339 return super()._missing
_(desc
)
343 self
.__class
__.ALWAYS
: "",
344 self
.__class
__.R3_UNARY
: "^r3",
345 self
.__class
__.R3
: "r3",
346 self
.__class
__.R3_N
: "~r3",
347 self
.__class
__.R10
: "r10",
348 self
.__class
__.R10_N
: "~r10",
349 self
.__class
__.R30
: "r30",
350 self
.__class
__.R30_N
: "~r30",
354 return f
"{self.__class__.__name__}({str(self)})"
361 return SVP64PredMode
.INT
365 return (self
.value
& 0b1)
369 return (self
.value
>> 1)
372 class SVP64PredCR(Enum
):
387 def _missing_(cls
, desc
):
388 if isinstance(desc
, str):
390 return cls
.__members
__.get(name
)
392 return super()._missing
_(desc
)
399 return SVP64PredMode
.CR
403 return (self
.value
& 0b1)
407 return (self
.value
>> 1)
411 class SVP64PredRC1(Enum
):
416 def _missing_(cls
, desc
):
418 "RC1": SVP64PredRC1
.RC1
,
419 "~RC1": SVP64PredRC1
.RC1_N
,
427 return SVP64PredMode
.RC1
431 return (self
is SVP64PredRC1
.RC1_N
)
438 class SVP64Pred(Enum
):
439 ALWAYS
= SVP64PredInt
.ALWAYS
440 R3_UNARY
= SVP64PredInt
.R3_UNARY
442 R3_N
= SVP64PredInt
.R3_N
443 R10
= SVP64PredInt
.R10
444 R10_N
= SVP64PredInt
.R10_N
445 R30
= SVP64PredInt
.R30
446 R30_N
= SVP64PredInt
.R30_N
457 RC1
= SVP64PredRC1
.RC1
458 RC1_N
= SVP64PredRC1
.RC1_N
461 def _missing_(cls
, desc
):
462 if isinstance(desc
, str):
463 values
= {item
.value
:item
for item
in cls
}
464 for subcls
in (SVP64PredInt
, SVP64PredCR
, SVP64PredRC1
):
466 return values
.get(subcls(desc
))
471 return super()._missing
_(desc
)
474 return int(self
.value
)
478 return self
.value
.mode
482 return self
.value
.inv
486 return self
.value
.state
490 class SVP64RMMode(Enum
):
500 class SVP64BCPredMode(Enum
):
507 class SVP64BCVLSETMode(Enum
):
513 # note that these are chosen to be exactly the same as
514 # SVP64 RM bit 4. ALL=1 => bit4=1
516 class SVP64BCGate(Enum
):
521 class SVP64BCCTRMode(Enum
):
528 class SVP64Width(Enum
):
535 def _missing_(cls
, desc
):
536 if isinstance(desc
, str):
538 "32": SVP64Width
.EW_32
,
539 "16": SVP64Width
.EW_16
,
540 "8": SVP64Width
.EW_8
,
543 return super()._missing
_(desc
)
547 class SVP64SubVL(Enum
):
554 def _missing_(cls
, desc
):
555 if isinstance(desc
, str):
557 return cls
.__members
__.get(name
)
559 return super()._missing
_(desc
)
563 class SVP64Sat(Enum
):
570 class SVP64LDSTmode(Enum
):
598 CR_3BIT
= 2 # CR field; the CR register is 32-bit
602 CR_5BIT
= 3 # bit of the 32-bit CR register
609 XER_BIT
= 4 # XER bits, includes OV, OV32, SO, CA, CA32
617 def _missing_(cls
, value
):
618 if isinstance(value
, SVExtraReg
):
619 return cls
.__members
__.get(value
.name
)
621 return super()._missing
_(value
)
626 "fatan2pi", "fatan2pis",
635 "fexp2m1", "fexp2m1s",
636 "flog2p1", "flog2p1s",
643 "fexp10m1", "fexp10m1s",
644 "flog10p1", "flog10p1s",
656 "fasinpi", "fasinpis",
657 "facospi", "facospis",
658 "fatanpi", "fatanpis",
665 "fminnum08", "fminnum08s",
666 "fmaxnum08", "fmaxnum08s",
669 "fminnum19", "fminnum19s",
670 "fmaxnum19", "fmaxnum19s",
673 "fminmagnum08", "fminmagnum08s",
674 "fmaxmagnum08", "fmaxmagnum08s",
675 "fminmag19", "fminmag19s",
676 "fmaxmag19", "fmaxmag19s",
677 "fminmagnum19", "fminmagnum19s",
678 "fmaxmagnum19", "fmaxmagnum19s",
679 "fminmagc", "fminmagcs",
680 "fmaxmagc", "fmaxmagcs",
682 "fremainder", "fremainders",
686 # supported instructions: make sure to keep up-to-date with CSV files
687 # just like everything else
689 "NONE", "add", "addc", "addco", "adde", "addeo",
690 "addi", "addic", "addic.", "addis",
691 "addme", "addmeo", "addo", "addze", "addzeo",
694 "and", "andc", "andi.", "andis.",
696 "absdu", "absds", # AV bitmanip
697 "absdacs", "absdacu", # AV bitmanip
698 "avgadd", # AV bitmanip
699 "b", "bc", "bcctr", "bclr", "bctar",
700 "bmask", # AV bitmanip
704 "cmp", "cmpb", "cmpeqb", "cmpi", "cmpl", "cmpli", "cmprb",
705 "cntlzd", "cntlzw", "cnttzd", "cnttzw",
706 "cprop", # AV bitmanip
707 "crand", "crandc", "creqv",
708 "crnand", "crnor", "cror", "crorc", "crxor",
710 "dcbf", "dcbst", "dcbt", "dcbtst", "dcbz",
711 "divd", "divde", "divdeo", "divdeu",
712 "divdeuo", "divdo", "divdu", "divduo",
714 "divw", "divwe", "divweo",
715 "divweu", "divweuo", "divwo", "divwu", "divwuo",
716 "dsld", "dsld.", "dsrd", "dsrd.",
718 "extsb", "extsh", "extsw", "extswsli",
719 "fadd", "fadds", "fsub", "fsubs", # FP add / sub
720 "fcfids", "fcfidus", "fsqrts", "fres", "frsqrtes", # FP stuff
721 "fdmadds", # DCT FP 3-arg
722 "fmsubs", "fmadds", "fnmsubs", "fnmadds", # FP 3-arg
723 "ffadds", "ffsubs", "ffmuls", "ffdivs", # FFT FP 2-arg
724 "ffmsubs", "ffmadds", "ffnmsubs", "ffnmadds", # FFT FP 3-arg
725 "fmul", "fmuls", "fdiv", "fdivs", # FP mul / div
726 "fmr", "fabs", "fnabs", "fneg", "fcpsgn", # FP move/abs/neg
727 "fmvis", # FP load immediate
728 "fishmv", # Float Replace Lower-Half Single, Immediate
729 'grev', 'grev.', 'grevi', 'grevi.',
730 'grevw', 'grevw.', 'grevwi', 'grevwi.',
731 "hrfid", "icbi", "icbt", "isel", "isync",
732 "lbarx", "lbz", "lbzcix", "lbzu", "lbzux", "lbzx", # load byte
733 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
734 # "lbzbr", "lbzubr", # load byte SVP64 bit-reversed
735 # "ldbr", "ldubr", # load double SVP64 bit-reversed
736 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
737 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load double
738 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
739 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
740 # "lhabr", "lhaubr", # load half SVP64 bit-reversed
741 # "lhzbr", "lhzubr", # more load half SVP64 bit-reversed
742 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
743 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
744 # "lwabr", # load word SVP64 bit-reversed
745 # "lwzbr", "lwzubr", # more load word SVP64 bit-reversed
746 "maddedu", "maddedus",
747 "maddhd", "maddhdu", "maddld", # INT multiply-and-add
748 "mcrf", "mcrxr", "mcrxrx", "mfcr/mfocrf", # CR mvs
750 "mins", "maxs", "minu", "maxu", # AV bitmanip
751 "modsd", "modsw", "modud", "moduw",
752 "mtcrf/mtocrf", "mtmsr", "mtmsrd", "mtspr",
753 "mulhd", "mulhdu", "mulhw", "mulhwu", "mulld", "mulldo",
754 "mulli", "mullw", "mullwo",
755 "nand", "neg", "nego",
757 "nor", "or", "orc", "ori", "oris",
759 "popcntb", "popcntd", "popcntw",
762 "rldcl", "rldcr", "rldic", "rldicl", "rldicr", "rldimi",
763 "rlwimi", "rlwinm", "rlwnm",
765 "setvl", # https://libre-soc.org/openpower/sv/setvl
766 "svindex", # https://libre-soc.org/openpower/sv/remap
767 "svremap", # https://libre-soc.org/openpower/sv/remap - TEMPORARY
768 "svshape", # https://libre-soc.org/openpower/sv/remap/#svshape
769 "svshape2", # https://libre-soc.org/openpower/sv/remap/discussion TODO
770 "svstep", # https://libre-soc.org/openpower/sv/setvl
772 "shadd", "shaddw", "shadduw",
773 "slbia", "sld", "slw", "srad", "sradi",
774 "sraw", "srawi", "srd", "srw",
775 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
776 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
777 "stfs", "stfsx", "stfsu", "stfux", "stfsux", # FP store single
778 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store double
779 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
780 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
781 "subf", "subfc", "subfco", "subfe", "subfeo", "subfic",
782 "subfme", "subfmeo", "subfo", "subfze", "subfzeo",
786 "tlbie", "tlbiel", "tlbsync",
789 "xor", "xori", "xoris",
793 # two-way lookup of instruction-to-index and vice-versa
796 for i
, insn
in enumerate(_insns
):
800 # must be long enough to cover all instructions
801 asmlen
= len(_insns
).bit_length()
803 # Internal Operation numbering. Add new opcodes here (FPADD, FPMUL etc.)
808 OP_ILLEGAL
= 0 # important that this is zero (see power_decoder.py)
882 OP_FPOP
= 77 # temporary: replace with actual ops
883 OP_FPOP_I
= 78 # temporary: replace with actual ops
916 RS
= 4 # for some ALU/Logical operations
922 CIA
= 7 # for addpcis
939 RS
= 13 # for shiftrot (M-Form)
943 CONST_SVD
= 15 # for SVD-Form
944 CONST_SVDS
= 16 # for SVDS-Form
946 CONST_DXHI4
= 18 # for addpcis
947 CONST_DQ
= 19 # for ld/st-quad
954 RB
= 2 # for shiftrot (M-Form)
958 RC
= 5 # for SVP64 bit-reverse LD/ST
959 RT
= 6 # for ternlog[i]
986 # Backward compatibility
991 class LDSTMode(Enum
):
1002 RC
= 2 # includes OE
1003 RC_ONLY
= 3 # does not include OE
1015 class CRInSel(Enum
):
1028 class CRIn2Sel(Enum
):
1034 class CROutSel(Enum
):
1043 # SPRs - Special-Purpose Registers. See V3.0B Figure 18 p971 and
1044 # http://libre-riscv.org/openpower/isatables/sprs.csv
1045 # http://bugs.libre-riscv.org/show_bug.cgi?id=261
1046 # http://bugs.libre-riscv.org/show_bug.cgi?id=859 - KAIVB
1048 def get_spr_enum(full_file
):
1049 """get_spr_enum - creates an Enum of SPRs, dynamically
1050 has the option to reduce the enum to a much shorter list.
1051 this saves drastically on the size of the regfile
1053 short_list
= {'PIDR', 'DAR', 'PRTBL', 'DSISR', 'SVSRR0', 'SVSTATE',
1054 'SVSTATE0', 'SVSTATE1', 'SVSTATE2', 'SVSTATE3',
1055 'SPRG0_priv', 'SPRG1_priv', 'SPRG2_priv', 'SPRG3_priv',
1056 'SPRG0', 'SPRG1', 'SPRG2', 'SPRG3', 'KAIVB',
1057 # hmmm should not be including these, they are FAST regs
1058 'CTR', 'LR', 'TAR', 'SRR0', 'SRR1', 'XER', 'DEC', 'TB', 'TBU',
1059 'HSRR0', 'HSRR1', 'HSPRG0', 'HSPRG1',
1062 for row
in get_csv("sprs.csv"):
1063 if full_file
or row
['SPR'] in short_list
:
1066 spr_info
= namedtuple('spr_info', 'SPR priv_mtspr priv_mfspr length idx')
1070 info
= spr_info(SPR
=row
['SPR'], priv_mtspr
=row
['priv_mtspr'],
1071 priv_mfspr
=row
['priv_mfspr'], length
=int(row
['len']),
1072 idx
=int(row
['Idx']))
1073 spr_dict
[int(row
['Idx'])] = info
1074 spr_byname
[row
['SPR']] = info
1075 fields
= [(row
['SPR'], int(row
['Idx'])) for row
in spr_csv
]
1076 SPR
= Enum('SPR', fields
)
1077 return SPR
, spr_dict
, spr_byname
1080 SPRfull
, spr_dict
, spr_byname
= get_spr_enum(full_file
=True)
1081 SPRreduced
, _
, _
= get_spr_enum(full_file
=False)
1091 MSRSpec
= namedtuple("MSRSpec", ["dr", "pr", "sf"])
1093 if __name__
== '__main__':
1094 # find out what the heck is in SPR enum :)
1095 print("sprs full", len(SPRfull
))
1097 print("sprs reduced", len(SPRreduced
))
1098 print(dir(SPRreduced
))
1100 print(SPRfull
.__members
__['TAR'])
1102 print("full", x
, x
.value
, str(x
), x
.name
)
1103 for x
in SPRreduced
:
1104 print("reduced", x
, x
.value
, str(x
), x
.name
)
1106 print("function", Function
.ALU
.name
)