optypes.py
1 from amaranth import * 2 from amaranth.lib.enum import unique, IntEnum, auto 3 4 from amaranth_types import ValueLike 5 6 from .isa import Extension, extension_implications, extension_only_implies 7 8 __all__ = [ 9 "OpType", 10 "CfiType", 11 ] 12 13 14 @unique 15 class OpType(IntEnum): 16 """ 17 Enum of operation types. Do not confuse with Opcode. 18 """ 19 20 UNKNOWN = auto() # needs to be first 21 ARITHMETIC = auto() 22 COMPARE = auto() 23 LOGIC = auto() 24 SHIFT = auto() 25 AUIPC = auto() 26 JAL = auto() 27 JALR = auto() 28 BRANCH = auto() 29 LOAD = auto() 30 STORE = auto() 31 FENCE = auto() 32 ECALL = auto() 33 EBREAK = auto() 34 MRET = auto() 35 WFI = auto() 36 FENCEI = auto() 37 CSR_REG = auto() 38 CSR_IMM = auto() 39 MUL = auto() 40 DIV_REM = auto() 41 SINGLE_BIT_MANIPULATION = auto() 42 ADDRESS_GENERATION = auto() 43 BIT_MANIPULATION = auto() 44 BIT_ROTATION = auto() 45 UNARY_BIT_MANIPULATION_1 = auto() 46 UNARY_BIT_MANIPULATION_2 = auto() 47 UNARY_BIT_MANIPULATION_3 = auto() 48 UNARY_BIT_MANIPULATION_4 = auto() 49 UNARY_BIT_MANIPULATION_5 = auto() 50 CROSSBAR_PERMUTATION = auto() 51 CLMUL = auto() 52 SRET = auto() 53 SFENCEVMA = auto() 54 CZERO = auto() 55 ATOMIC_MEMORY_OP = auto() 56 ATOMIC_LR_SC = auto() 57 #: Internal Coreblocks OpType, specifying that instruction caused Exception before FU execution 58 EXCEPTION = auto() 59 60 61 @unique 62 class CfiType(IntEnum): 63 """ 64 Types of control flow instructions. 65 66 There are 4 main types: invalid, branch, JAL, and JALR. CALL and RET are 67 just special cases of respectively JAL and JALR and thus the encoding 68 was chosen in the way that it is sufficient to check the lowest two bits to 69 get the main type and the third bit is just a hint about the specialized type. 70 71 Because of these encoding tweaks, helper functions should be preferred to use 72 to get the CFI type. 73 """ 74 75 INVALID = 0b000 # Not a CFI 76 BRANCH = 0b001 77 78 JALR = 0b010 # Jump and Link Register 79 RET = 0b110 # Return from a function (JALR with rs1 equal to x1 or x5) 80 81 JAL = 0b011 # Jump and Link 82 CALL = 0b111 # Call a function (JAL with rd equal to x1 or x5)) 83 84 @staticmethod 85 def valid(val: ValueLike) -> Value: 86 return Value.cast(val)[0:2] != CfiType.INVALID 87 88 @staticmethod 89 def is_branch(val: ValueLike) -> Value: 90 return Value.cast(val)[0:2] == CfiType.BRANCH 91 92 @staticmethod 93 def is_jal(val: ValueLike) -> Value: 94 return Value.cast(val)[0:2] == CfiType.JAL 95 96 @staticmethod 97 def is_jalr(val: ValueLike) -> Value: 98 return Value.cast(val)[0:2] == CfiType.JALR 99 100 101 # 102 # Operation types grouped by extensions 103 # Note that this list provides 1:1 mappings and extension implications (like M->Zmmul) need to be resolved externally. 104 # 105 106 optypes_by_extensions = { 107 Extension.I: [ 108 OpType.ARITHMETIC, 109 OpType.COMPARE, 110 OpType.LOGIC, 111 OpType.SHIFT, 112 OpType.AUIPC, 113 OpType.JAL, 114 OpType.JALR, 115 OpType.BRANCH, 116 OpType.LOAD, 117 OpType.STORE, 118 OpType.FENCE, 119 OpType.ECALL, 120 OpType.EBREAK, 121 ], 122 Extension.ZIFENCEI: [ 123 OpType.FENCEI, 124 ], 125 Extension.ZICSR: [ 126 OpType.CSR_REG, 127 OpType.CSR_IMM, 128 ], 129 Extension.ZMMUL: [ 130 OpType.MUL, 131 ], 132 Extension.M: [ 133 OpType.DIV_REM, 134 ], 135 Extension.ZAAMO: [ 136 OpType.ATOMIC_MEMORY_OP, 137 ], 138 Extension.ZALRSC: [ 139 OpType.ATOMIC_LR_SC, 140 ], 141 Extension.ZBS: [ 142 OpType.SINGLE_BIT_MANIPULATION, 143 ], 144 Extension.ZBA: [ 145 OpType.ADDRESS_GENERATION, 146 ], 147 Extension.ZBB: [ 148 OpType.BIT_MANIPULATION, 149 OpType.BIT_ROTATION, 150 OpType.UNARY_BIT_MANIPULATION_1, 151 OpType.UNARY_BIT_MANIPULATION_2, 152 OpType.UNARY_BIT_MANIPULATION_3, 153 OpType.UNARY_BIT_MANIPULATION_4, 154 OpType.UNARY_BIT_MANIPULATION_5, 155 ], 156 Extension.ZBC: [ 157 OpType.CLMUL, 158 ], 159 Extension.ZBKX: [ 160 OpType.CROSSBAR_PERMUTATION, 161 ], 162 Extension.ZICOND: [ 163 OpType.CZERO, 164 ], 165 Extension.XINTMACHINEMODE: [ 166 OpType.MRET, 167 OpType.WFI, 168 ], 169 Extension.XINTSUPERVISOR: [ 170 OpType.SRET, 171 OpType.SFENCEVMA, 172 ], 173 } 174 175 176 def optypes_required_by_extensions( 177 extensions: Extension, resolve_implications=True, ignore_unsupported=False 178 ) -> set[OpType]: 179 optypes = set() 180 181 if resolve_implications: 182 implied_extensions = Extension(0) 183 for ext in Extension: 184 if ext in extensions: 185 # check if extensions has implications, but skip if we don't have defined any optypes for it yet 186 if ext in extension_implications and (ext in optypes_by_extensions or ext in extension_only_implies): 187 implied_extensions |= extension_implications[ext] 188 extensions |= implied_extensions 189 190 for ext in Extension: 191 if ext in extensions: 192 if ext in optypes_by_extensions: 193 optypes = optypes.union(optypes_by_extensions[ext]) 194 elif not ignore_unsupported: 195 raise Exception(f"Core does not support {ext!r} extension") 196 197 return optypes