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
291 def _missing_(cls
, desc
):
293 In1Sel
, In2Sel
, In3Sel
, CRInSel
, CRIn2Sel
,
296 if isinstance(desc
, selectors
):
297 return cls
.__members
__.get(desc
.name
)
299 return cls
.__members
__.get(desc
)
311 if alias
is not None:
315 Reg
.RA_OR_ZERO
: Reg
.RA
,
316 Reg
.RT_OR_ZERO
: Reg
.RT
,
318 if alias
is not None:
343 class SVP64PredMode(Enum
):
351 class SVP64PredInt(Enum
):
362 def _missing_(cls
, desc
):
363 if isinstance(desc
, str):
374 if value
.startswith("~"):
375 value
= f
"~{value[1:].strip()}"
376 elif "<<" in value
: # 1 << r3
377 (lhs
, _
, rhs
) = value
.partition("<<")
378 lhs
= lhs
.strip().lower()
379 rhs
= rhs
.strip().lower()
380 if (lhs
== "1") and (rhs
in ("r3", "%r3")):
383 return values
.get(value
)
385 return super()._missing
_(desc
)
389 self
.__class
__.ALWAYS
: "",
390 self
.__class
__.R3_UNARY
: "^r3",
391 self
.__class
__.R3
: "r3",
392 self
.__class
__.R3_N
: "~r3",
393 self
.__class
__.R10
: "r10",
394 self
.__class
__.R10_N
: "~r10",
395 self
.__class
__.R30
: "r30",
396 self
.__class
__.R30_N
: "~r30",
400 return f
"{self.__class__.__name__}({str(self)})"
407 return SVP64PredMode
.INT
411 return (self
.value
& 0b1)
415 return (self
.value
>> 1)
418 class SVP64PredCR(Enum
):
433 def _missing_(cls
, desc
):
434 if isinstance(desc
, str):
436 return cls
.__members
__.get(name
)
438 return super()._missing
_(desc
)
445 return SVP64PredMode
.CR
449 return (self
.value
& 0b1)
453 return (self
.value
>> 1)
457 class SVP64PredRC1(Enum
):
462 def _missing_(cls
, desc
):
464 "RC1": SVP64PredRC1
.RC1
,
465 "~RC1": SVP64PredRC1
.RC1_N
,
473 return SVP64PredMode
.RC1
477 return (self
is SVP64PredRC1
.RC1_N
)
484 class SVP64Pred(Enum
):
485 ALWAYS
= SVP64PredInt
.ALWAYS
486 R3_UNARY
= SVP64PredInt
.R3_UNARY
488 R3_N
= SVP64PredInt
.R3_N
489 R10
= SVP64PredInt
.R10
490 R10_N
= SVP64PredInt
.R10_N
491 R30
= SVP64PredInt
.R30
492 R30_N
= SVP64PredInt
.R30_N
503 RC1
= SVP64PredRC1
.RC1
504 RC1_N
= SVP64PredRC1
.RC1_N
507 def _missing_(cls
, desc
):
508 if isinstance(desc
, str):
509 values
= {item
.value
:item
for item
in cls
}
510 for subcls
in (SVP64PredInt
, SVP64PredCR
, SVP64PredRC1
):
512 return values
.get(subcls(desc
))
517 return super()._missing
_(desc
)
520 return int(self
.value
)
524 return self
.value
.mode
528 return self
.value
.inv
532 return self
.value
.state
536 class SVP64RMMode(Enum
):
545 class SVP64BCPredMode(Enum
):
552 class SVP64BCVLSETMode(Enum
):
558 # note that these are chosen to be exactly the same as
559 # SVP64 RM bit 4. ALL=1 => bit4=1
561 class SVP64BCGate(Enum
):
566 class SVP64BCCTRMode(Enum
):
573 class SVP64Width(Enum
):
580 def _missing_(cls
, desc
):
581 if isinstance(desc
, str):
583 "32": SVP64Width
.EW_32
,
584 "16": SVP64Width
.EW_16
,
585 "8": SVP64Width
.EW_8
,
588 return super()._missing
_(desc
)
592 class SVP64SubVL(Enum
):
599 def _missing_(cls
, desc
):
600 if isinstance(desc
, str):
602 return cls
.__members
__.get(name
)
604 return super()._missing
_(desc
)
608 class SVP64Sat(Enum
):
615 class SVP64LDSTmode(Enum
):
643 CR_3BIT
= 2 # CR field; the CR register is 32-bit
647 CR_5BIT
= 3 # bit of the 32-bit CR register
654 XER_BIT
= 4 # XER bits, includes OV, OV32, SO, CA, CA32
662 def _missing_(cls
, value
):
663 if isinstance(value
, Reg
):
664 return cls
.__members
__.get(value
.name
)
666 return super()._missing
_(value
)
671 "fatan2pi", "fatan2pis",
680 "fexp2m1", "fexp2m1s",
681 "flog2p1", "flog2p1s",
688 "fexp10m1", "fexp10m1s",
689 "flog10p1", "flog10p1s",
701 "fasinpi", "fasinpis",
702 "facospi", "facospis",
703 "fatanpi", "fatanpis",
710 # fmin*/fmax* need to be replaced with fminmax
711 # https://bugs.libre-soc.org/show_bug.cgi?id=1057
712 # commented for now to make space for fmv/cvt
713 # "fminnum08", "fminnum08s",
714 # "fmaxnum08", "fmaxnum08s",
715 # "fmin19", "fmin19s",
716 # "fmax19", "fmax19s",
717 # "fminnum19", "fminnum19s",
718 # "fmaxnum19", "fmaxnum19s",
721 # "fminmagnum08", "fminmagnum08s",
722 # "fmaxmagnum08", "fmaxmagnum08s",
723 # "fminmag19", "fminmag19s",
724 # "fmaxmag19", "fmaxmag19s",
725 # "fminmagnum19", "fminmagnum19s",
726 # "fmaxmagnum19", "fmaxmagnum19s",
727 # "fminmagc", "fminmagcs",
728 # "fmaxmagc", "fmaxmagcs",
730 "fremainder", "fremainders",
734 # supported instructions: make sure to keep up-to-date with CSV files
735 # just like everything else
737 "NONE", "add", "addc", "addco", "adde", "addeo",
738 "addi", "addic", "addic.", "addis",
739 "addme", "addmeo", "addo", "addze", "addzeo",
742 "and", "andc", "andi.", "andis.",
744 "absdu", "absds", # AV bitmanip
745 "absdacs", "absdacu", # AV bitmanip
746 "avgadd", # AV bitmanip
747 "b", "bc", "bcctr", "bclr", "bctar",
748 "bmask", # AV bitmanip
752 "cmp", "cmpb", "cmpeqb", "cmpi", "cmpl", "cmpli", "cmprb",
753 "cntlzd", "cntlzw", "cnttzd", "cnttzw",
754 "cprop", # AV bitmanip
755 "crand", "crandc", "creqv",
756 "crnand", "crnor", "cror", "crorc", "crxor",
758 "dcbf", "dcbst", "dcbt", "dcbtst", "dcbz",
759 "divd", "divde", "divdeo", "divdeu",
760 "divdeuo", "divdo", "divdu", "divduo",
762 "divw", "divwe", "divweo",
763 "divweu", "divweuo", "divwo", "divwu", "divwuo",
764 "dsld", "dsld.", "dsrd", "dsrd.",
766 "extsb", "extsh", "extsw", "extswsli",
767 "fadd", "fadds", "fsub", "fsubs", # FP add / sub
768 "fcfids", "fcfidus", "fsqrts", "fres", "frsqrtes", # FP stuff
769 "fdmadds", # DCT FP 3-arg
770 "fmsubs", "fmadds", "fnmsubs", "fnmadds", # FP 3-arg
771 "ffadds", "ffsubs", "ffmuls", "ffdivs", # FFT FP 2-arg
772 "ffmsubs", "ffmadds", "ffnmsubs", "ffnmadds", # FFT FP 3-arg
773 "fmul", "fmuls", "fdiv", "fdivs", # FP mul / div
774 "fmr", "fabs", "fnabs", "fneg", "fcpsgn", # FP move/abs/neg
775 "fmvis", # FP load immediate
776 "fishmv", # Float Replace Lower-Half Single, Immediate
777 "fcvttg", "fcvttgo", "fcvttgs", "fcvttgso",
781 'grev', 'grev.', 'grevi', 'grevi.',
782 'grevw', 'grevw.', 'grevwi', 'grevwi.',
783 "hrfid", "icbi", "icbt", "isel", "isync",
784 "lbarx", "lbz", "lbzcix", "lbzu", "lbzux", "lbzx", # load byte
785 "ld", "ldarx", "ldbrx", "ldu", "ldux", "ldx", # load double
786 # "lbzbr", "lbzubr", # load byte SVP64 bit-reversed
787 # "ldbr", "ldubr", # load double SVP64 bit-reversed
788 "lfs", "lfsx", "lfsu", "lfsux", # FP load single
789 "lfd", "lfdx", "lfdu", "lfdux", "lfiwzx", "lfiwax", # FP load double
790 "lha", "lharx", "lhau", "lhaux", "lhax", # load half
791 "lhbrx", "lhz", "lhzu", "lhzux", "lhzx", # more load half
792 # "lhabr", "lhaubr", # load half SVP64 bit-reversed
793 # "lhzbr", "lhzubr", # more load half SVP64 bit-reversed
794 "lwa", "lwarx", "lwaux", "lwax", "lwbrx", # load word
795 "lwz", "lwzcix", "lwzu", "lwzux", "lwzx", # more load word
796 # "lwabr", # load word SVP64 bit-reversed
797 # "lwzbr", "lwzubr", # more load word SVP64 bit-reversed
798 "maddedu", "maddedus",
799 "maddhd", "maddhdu", "maddld", # INT multiply-and-add
800 "maddsubrs", # Integer DCT Butterfly Add Sub and Round Shift
801 "maddrs", # Integer DCT Butterfly Add and Accumulate and Round Shift
802 "mcrf", "mcrxr", "mcrxrx", "mfcr/mfocrf", # CR mvs
804 "minmax", # AV bitmanip
805 "modsd", "modsw", "modud", "moduw",
806 "mtcrf/mtocrf", "mtmsr", "mtmsrd", "mtspr",
807 "mulhd", "mulhdu", "mulhw", "mulhwu", "mulld", "mulldo",
808 "mulli", "mullw", "mullwo",
809 "nand", "neg", "nego",
811 "nor", "or", "orc", "ori", "oris",
813 "popcntb", "popcntd", "popcntw",
816 "rldcl", "rldcr", "rldic", "rldicl", "rldicr", "rldimi",
817 "rlwimi", "rlwinm", "rlwnm",
819 "setvl", # https://libre-soc.org/openpower/sv/setvl
820 "svindex", # https://libre-soc.org/openpower/sv/remap
821 "svremap", # https://libre-soc.org/openpower/sv/remap - TEMPORARY
822 "svshape", # https://libre-soc.org/openpower/sv/remap/#svshape
823 "svshape2", # https://libre-soc.org/openpower/sv/remap/discussion TODO
824 "svstep", # https://libre-soc.org/openpower/sv/setvl
826 "sadd", "saddw", "sadduw",
827 "slbia", "sld", "slw", "srad", "sradi",
828 "sraw", "srawi", "srd", "srw",
829 "stb", "stbcix", "stbcx", "stbu", "stbux", "stbx",
830 "std", "stdbrx", "stdcx", "stdu", "stdux", "stdx",
831 "stfs", "stfsx", "stfsu", "stfux", "stfsux", # FP store single
832 "stfd", "stfdx", "stfdu", "stfdux", "stfiwx", # FP store double
833 "sth", "sthbrx", "sthcx", "sthu", "sthux", "sthx",
834 "stw", "stwbrx", "stwcx", "stwu", "stwux", "stwx",
835 "subf", "subfc", "subfco", "subfe", "subfeo", "subfic",
836 "subfme", "subfmeo", "subfo", "subfze", "subfzeo",
840 "tlbie", "tlbiel", "tlbsync",
843 "xor", "xori", "xoris",
847 # two-way lookup of instruction-to-index and vice-versa
850 for i
, insn
in enumerate(_insns
):
854 # must be long enough to cover all instructions
855 asmlen
= len(_insns
).bit_length()
857 # Internal Operation numbering. Add new opcodes here (FPADD, FPMUL etc.)
862 OP_ILLEGAL
= 0 # important that this is zero (see power_decoder.py)
936 OP_FPOP
= 77 # temporary: replace with actual ops
937 OP_FPOP_I
= 78 # temporary: replace with actual ops
974 SelType
.NONE
: "NONE",
985 RS
= 4 # for some ALU/Logical operations
992 CIA
= 8 # for addpcis
997 if self
is In1Sel
.NONE
:
1016 RS
= 13 # for shiftrot (M-Form)
1020 CONST_SVD
= 15 # for SVD-Form
1021 CONST_SVDS
= 16 # for SVDS-Form
1023 CONST_DXHI4
= 18 # for addpcis
1024 CONST_DQ
= 19 # for ld/st-quad
1028 if self
is In2Sel
.NONE
:
1037 RB
= 2 # for shiftrot (M-Form)
1041 RC
= 5 # for SVP64 bit-reverse LD/ST
1042 RT
= 6 # for ternlog[i]
1048 if self
is In3Sel
.NONE
:
1070 if self
is OutSel
.NONE
:
1076 class LDSTLen(Enum
):
1083 # Backward compatibility
1088 class LDSTMode(Enum
):
1099 RC
= 2 # includes OE
1100 RC_ONLY
= 3 # does not include OE
1112 class CRInSel(Enum
):
1125 if self
is CRInSel
.NONE
:
1131 class CRIn2Sel(Enum
):
1137 if self
is CRIn2Sel
.NONE
:
1143 class CROutSel(Enum
):
1153 if self
is CROutSel
.NONE
:
1158 # SPRs - Special-Purpose Registers. See V3.0B Figure 18 p971 and
1159 # http://libre-riscv.org/openpower/isatables/sprs.csv
1160 # http://bugs.libre-riscv.org/show_bug.cgi?id=261
1161 # http://bugs.libre-riscv.org/show_bug.cgi?id=859 - KAIVB
1163 def get_spr_enum(full_file
):
1164 """get_spr_enum - creates an Enum of SPRs, dynamically
1165 has the option to reduce the enum to a much shorter list.
1166 this saves drastically on the size of the regfile
1168 short_list
= {'PIDR', 'DAR', 'PRTBL', 'DSISR', 'SVSRR0', 'SVSTATE',
1169 'SVSTATE0', 'SVSTATE1', 'SVSTATE2', 'SVSTATE3',
1170 'SPRG0_priv', 'SPRG1_priv', 'SPRG2_priv', 'SPRG3_priv',
1171 'SPRG0', 'SPRG1', 'SPRG2', 'SPRG3', 'KAIVB',
1172 # hmmm should not be including these, they are FAST regs
1173 'CTR', 'LR', 'TAR', 'SRR0', 'SRR1', 'XER', 'DEC', 'TB', 'TBU',
1174 'HSRR0', 'HSRR1', 'HSPRG0', 'HSPRG1',
1177 for row
in get_csv("sprs.csv"):
1178 if full_file
or row
['SPR'] in short_list
:
1181 spr_info
= namedtuple('spr_info', 'SPR priv_mtspr priv_mfspr length idx')
1185 info
= spr_info(SPR
=row
['SPR'], priv_mtspr
=row
['priv_mtspr'],
1186 priv_mfspr
=row
['priv_mfspr'], length
=int(row
['len']),
1187 idx
=int(row
['Idx']))
1188 spr_dict
[int(row
['Idx'])] = info
1189 spr_byname
[row
['SPR']] = info
1190 fields
= [(row
['SPR'], int(row
['Idx'])) for row
in spr_csv
]
1191 SPR
= Enum('SPR', fields
)
1192 return SPR
, spr_dict
, spr_byname
1195 SPRfull
, spr_dict
, spr_byname
= get_spr_enum(full_file
=True)
1196 SPRreduced
, _
, _
= get_spr_enum(full_file
=False)
1206 MSRSpec
= namedtuple("MSRSpec", ["dr", "pr", "sf"])
1208 # flags for bfp_* functions
1225 if __name__
== '__main__':
1226 # find out what the heck is in SPR enum :)
1227 print("sprs full", len(SPRfull
))
1229 print("sprs reduced", len(SPRreduced
))
1230 print(dir(SPRreduced
))
1232 print(SPRfull
.__members
__['TAR'])
1234 print("full", x
, x
.value
, str(x
), x
.name
)
1235 for x
in SPRreduced
:
1236 print("reduced", x
, x
.value
, str(x
), x
.name
)
1238 print("function", Function
.ALU
.name
)