/ coreblocks / arch / optypes.py
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