/ test / frontend / test_instr_decoder.py
test_instr_decoder.py
  1  from amaranth.sim import *
  2  
  3  from transactron.testing import TestCaseWithSimulator, TestbenchContext
  4  
  5  from coreblocks.params import *
  6  from coreblocks.params.configurations import test_core_config
  7  from coreblocks.frontend.decoder.instr_decoder import InstrDecoder, Encoding, instructions_by_optype
  8  from coreblocks.arch import *
  9  from unittest import TestCase
 10  from typing import Optional, TypeAlias
 11  
 12  
 13  class TestDecoder(TestCaseWithSimulator):
 14      class InstrTest:
 15          def __init__(
 16              self,
 17              encoding,
 18              opcode,
 19              funct3=None,
 20              funct7=None,
 21              funct12=None,
 22              rd=None,
 23              rs1=None,
 24              rs2=None,
 25              imm=None,
 26              succ=None,
 27              pred=None,
 28              fm=None,
 29              csr=None,
 30              op=None,
 31              illegal=0,
 32          ):
 33              self.encoding = encoding
 34              self.opcode = opcode
 35              self.funct3 = funct3
 36              self.funct7 = funct7
 37              self.funct12 = funct12
 38              self.rd = rd
 39              self.rs1 = rs1
 40              self.rs2 = rs2
 41              self.imm = imm
 42              self.succ = succ
 43              self.pred = pred
 44              self.fm = fm
 45              self.csr = csr
 46              self.op = op
 47              self.illegal = illegal
 48  
 49      DECODER_TESTS_I = [
 50          # Arithmetic
 51          InstrTest(0x02A28213, Opcode.OP_IMM, Funct3.ADD, rd=4, rs1=5, imm=42, op=OpType.ARITHMETIC),
 52          InstrTest(0x003100B3, Opcode.OP, Funct3.ADD, Funct7.ADD, rd=1, rs1=2, rs2=3, op=OpType.ARITHMETIC),
 53          InstrTest(0x40418133, Opcode.OP, Funct3.ADD, Funct7.SUB, rd=2, rs1=3, rs2=4, op=OpType.ARITHMETIC),
 54          InstrTest(0x001230B7, Opcode.OP_IMM, Funct3.ADD, rd=1, rs1=0, imm=0x123 << 12, op=OpType.ARITHMETIC),
 55          # Compare
 56          InstrTest(0x07BF2A13, Opcode.OP_IMM, Funct3.SLT, rd=20, rs1=30, imm=123, op=OpType.COMPARE),
 57          InstrTest(0x0FFFBA93, Opcode.OP_IMM, Funct3.SLTU, rd=21, rs1=31, imm=0xFF, op=OpType.COMPARE),
 58          InstrTest(0x00C5A533, Opcode.OP, Funct3.SLT, Funct7.SLT, rd=10, rs1=11, rs2=12, op=OpType.COMPARE),
 59          InstrTest(0x00C5B533, Opcode.OP, Funct3.SLTU, Funct7.SLT, rd=10, rs1=11, rs2=12, op=OpType.COMPARE),
 60          # Logic
 61          InstrTest(0xFFF04013, Opcode.OP_IMM, Funct3.XOR, rd=0, rs1=0, imm=-1, op=OpType.LOGIC),
 62          InstrTest(0x3FF0E093, Opcode.OP_IMM, Funct3.OR, rd=1, rs1=1, imm=0x3FF, op=OpType.LOGIC),
 63          InstrTest(0x000FFF13, Opcode.OP_IMM, Funct3.AND, rd=30, rs1=31, imm=0, op=OpType.LOGIC),
 64          InstrTest(0x003140B3, Opcode.OP, Funct3.XOR, Funct7.XOR, rd=1, rs1=2, rs2=3, op=OpType.LOGIC),
 65          InstrTest(0x003160B3, Opcode.OP, Funct3.OR, Funct7.OR, rd=1, rs1=2, rs2=3, op=OpType.LOGIC),
 66          InstrTest(0x003170B3, Opcode.OP, Funct3.AND, Funct7.AND, rd=1, rs1=2, rs2=3, op=OpType.LOGIC),
 67          # Shift
 68          InstrTest(0x00029793, Opcode.OP_IMM, Funct3.SLL, Funct7.SL, rd=15, rs1=5, imm=0, op=OpType.SHIFT),
 69          InstrTest(0x00F2D793, Opcode.OP_IMM, Funct3.SR, Funct7.SL, rd=15, rs1=5, imm=15, op=OpType.SHIFT),
 70          InstrTest(0x41F2D793, Opcode.OP_IMM, Funct3.SR, Funct7.SA, rd=15, rs1=5, imm=31, op=OpType.SHIFT),
 71          InstrTest(0x019297B3, Opcode.OP, Funct3.SLL, Funct7.SL, rd=15, rs1=5, rs2=25, op=OpType.SHIFT),
 72          InstrTest(0x0192D7B3, Opcode.OP, Funct3.SR, Funct7.SL, rd=15, rs1=5, rs2=25, op=OpType.SHIFT),
 73          InstrTest(0x4192D7B3, Opcode.OP, Funct3.SR, Funct7.SA, rd=15, rs1=5, rs2=25, op=OpType.SHIFT),
 74          # AUIPC
 75          InstrTest(0x00777F17, Opcode.AUIPC, rd=30, imm=0x777 << 12, op=OpType.AUIPC),
 76          # Jumps
 77          InstrTest(0x000000EF, Opcode.JAL, rd=1, imm=0, op=OpType.JAL),
 78          InstrTest(0xFFE100E7, Opcode.JALR, Funct3.JALR, rd=1, rs1=2, imm=-2, op=OpType.JALR),
 79          # Branch
 80          InstrTest(0x00209463, Opcode.BRANCH, Funct3.BNE, rs1=1, rs2=2, imm=4 << 1, op=OpType.BRANCH),
 81          InstrTest(0x00310463, Opcode.BRANCH, Funct3.BEQ, rs1=2, rs2=3, imm=4 << 1, op=OpType.BRANCH),
 82          InstrTest(0x0041D463, Opcode.BRANCH, Funct3.BGE, rs1=3, rs2=4, imm=4 << 1, op=OpType.BRANCH),
 83          InstrTest(0x00524463, Opcode.BRANCH, Funct3.BLT, rs1=4, rs2=5, imm=4 << 1, op=OpType.BRANCH),
 84          InstrTest(0x0062F463, Opcode.BRANCH, Funct3.BGEU, rs1=5, rs2=6, imm=4 << 1, op=OpType.BRANCH),
 85          InstrTest(0x00736463, Opcode.BRANCH, Funct3.BLTU, rs1=6, rs2=7, imm=4 << 1, op=OpType.BRANCH),
 86          # Load
 87          InstrTest(0x00B48403, Opcode.LOAD, Funct3.B, rd=8, rs1=9, imm=11, op=OpType.LOAD),
 88          InstrTest(0x00C54483, Opcode.LOAD, Funct3.BU, rd=9, rs1=10, imm=12, op=OpType.LOAD),
 89          InstrTest(0x00D59503, Opcode.LOAD, Funct3.H, rd=10, rs1=11, imm=13, op=OpType.LOAD),
 90          InstrTest(0x00E65583, Opcode.LOAD, Funct3.HU, rd=11, rs1=12, imm=14, op=OpType.LOAD),
 91          InstrTest(0x00F6A603, Opcode.LOAD, Funct3.W, rd=12, rs1=13, imm=15, op=OpType.LOAD),
 92          InstrTest(0xFFA09703, Opcode.LOAD, Funct3.H, rd=14, rs1=1, imm=-6, op=OpType.LOAD),
 93          # Store
 94          InstrTest(0x00D70823, Opcode.STORE, Funct3.B, rs1=14, rs2=13, imm=16, op=OpType.STORE),
 95          InstrTest(0x00E798A3, Opcode.STORE, Funct3.H, rs1=15, rs2=14, imm=17, op=OpType.STORE),
 96          InstrTest(0x00F82923, Opcode.STORE, Funct3.W, rs1=16, rs2=15, imm=18, op=OpType.STORE),
 97          # Fence
 98          InstrTest(
 99              0x0320000F,
100              Opcode.MISC_MEM,
101              Funct3.FENCE,
102              rd=0,
103              rs1=0,
104              succ=FenceTarget.MEM_R,
105              pred=(FenceTarget.MEM_R | FenceTarget.MEM_W),
106              fm=FenceFm.NONE,
107              op=OpType.FENCE,
108          ),
109          # ECALL
110          InstrTest(0x00000073, Opcode.SYSTEM, Funct3.PRIV, funct12=Funct12.ECALL, op=OpType.ECALL),
111          # EBREAK
112          InstrTest(0x00100073, Opcode.SYSTEM, Funct3.PRIV, funct12=Funct12.EBREAK, op=OpType.EBREAK),
113      ]
114      DECODER_TESTS_ZIFENCEI = [
115          InstrTest(0x0000100F, Opcode.MISC_MEM, Funct3.FENCEI, rd=0, rs1=0, imm=0, op=OpType.FENCEI),
116      ]
117      DECODER_TESTS_ZICSR = [
118          InstrTest(0x001A9A73, Opcode.SYSTEM, Funct3.CSRRW, rd=20, rs1=21, csr=0x01, op=OpType.CSR_REG),
119          InstrTest(0x002B2AF3, Opcode.SYSTEM, Funct3.CSRRS, rd=21, rs1=22, csr=0x02, op=OpType.CSR_REG),
120          InstrTest(0x004BBB73, Opcode.SYSTEM, Funct3.CSRRC, rd=22, rs1=23, csr=0x04, op=OpType.CSR_REG),
121          InstrTest(0x001FDA73, Opcode.SYSTEM, Funct3.CSRRWI, rd=20, imm=0x1F, csr=0x01, op=OpType.CSR_IMM),
122          InstrTest(0x0027EAF3, Opcode.SYSTEM, Funct3.CSRRSI, rd=21, imm=0xF, csr=0x02, op=OpType.CSR_IMM),
123          InstrTest(0x00407B73, Opcode.SYSTEM, Funct3.CSRRCI, rd=22, imm=0x0, csr=0x04, op=OpType.CSR_IMM),
124      ]
125      DECODER_TESTS_ILLEGAL = [
126          InstrTest(0xFFFFFFFF, Opcode.OP_IMM, illegal=1),
127          InstrTest(0x003160FF, Opcode.OP, Funct3.OR, Funct7.OR, rd=1, rs1=2, rs2=3, op=OpType.LOGIC, illegal=1),
128          InstrTest(0x000000F3, Opcode.SYSTEM, Funct3.PRIV, funct12=Funct12.ECALL, op=OpType.ECALL, illegal=1),
129      ]
130      DECODER_TESTS_M = [
131          InstrTest(0x02310133, Opcode.OP, Funct3.MUL, Funct7.MULDIV, rd=2, rs1=2, rs2=3, op=OpType.MUL),
132          InstrTest(0x02341133, Opcode.OP, Funct3.MULH, Funct7.MULDIV, rd=2, rs1=8, rs2=3, op=OpType.MUL),
133          InstrTest(0x02A12233, Opcode.OP, Funct3.MULHSU, Funct7.MULDIV, rd=4, rs1=2, rs2=10, op=OpType.MUL),
134          InstrTest(0x02A43233, Opcode.OP, Funct3.MULHU, Funct7.MULDIV, rd=4, rs1=8, rs2=10, op=OpType.MUL),
135          InstrTest(0x02314133, Opcode.OP, Funct3.DIV, Funct7.MULDIV, rd=2, rs1=2, rs2=3, op=OpType.DIV_REM),
136          InstrTest(0x02745133, Opcode.OP, Funct3.DIVU, Funct7.MULDIV, rd=2, rs1=8, rs2=7, op=OpType.DIV_REM),
137          InstrTest(0x02716233, Opcode.OP, Funct3.REM, Funct7.MULDIV, rd=4, rs1=2, rs2=7, op=OpType.DIV_REM),
138          InstrTest(0x02A47233, Opcode.OP, Funct3.REMU, Funct7.MULDIV, rd=4, rs1=8, rs2=10, op=OpType.DIV_REM),
139      ]
140      DECODER_TESTS_XINTMACHINEMODE = [
141          # MRET
142          InstrTest(0x30200073, Opcode.SYSTEM, Funct3.PRIV, funct12=Funct12.MRET, op=OpType.MRET),
143          # WFI
144          # InstrTest(0x10500073, Opcode.SYSTEM, Funct3.PRIV, funct12=Funct12.WFI, op=OpType.WFI),
145      ]
146      DECODER_TESTS_XINTSUPERVISOR = [
147          # SRET
148          InstrTest(0x10200073, Opcode.SYSTEM, Funct3.PRIV, funct12=Funct12.SRET, op=OpType.SRET),
149          # SFENCE.VMA
150          InstrTest(0x12208073, Opcode.SYSTEM, Funct3.PRIV, Funct7.SFENCEVMA, rs1=1, rs2=2, op=OpType.SFENCEVMA),
151      ]
152      DECODER_TESTS_ZBB = [
153          InstrTest(
154              0x60201013,
155              Opcode.OP_IMM,
156              Funct3.CPOP,
157              funct12=Funct12.CPOP,
158              rd=0,
159              rs1=0,
160              op=OpType.UNARY_BIT_MANIPULATION_5,
161          ),
162          InstrTest(0x40007033, Opcode.OP, Funct3.ANDN, Funct7.ANDN, rd=0, rs1=0, rs2=0, op=OpType.BIT_MANIPULATION),
163          InstrTest(
164              0x60411093,
165              Opcode.OP_IMM,
166              Funct3.SEXTB,
167              funct12=Funct12.SEXTB,
168              rd=1,
169              rs1=2,
170              op=OpType.UNARY_BIT_MANIPULATION_1,
171          ),
172      ]
173      DECODER_TESTS_ZICOND = [
174          #      CZERO    RS2   RS1   EQZ   RD     OP
175          # nez 0b0000111 00000 00000 111 00000 0110011
176          # eqz 0b0000111 00000 00000 101 00000 0110011
177          # CZERO.NEZ
178          InstrTest(0x0E007033, Opcode.OP, Funct3.CZERONEZ, Funct7.CZERO, rd=0, rs1=0, rs2=0, op=OpType.CZERO),
179          # CZERO.EQZ
180          InstrTest(0x0E005033, Opcode.OP, Funct3.CZEROEQZ, Funct7.CZERO, rd=0, rs1=0, rs2=0, op=OpType.CZERO),
181      ]
182  
183      DECODER_TESTS_ZBKX = [
184          # XPERM4
185          InstrTest(
186              0x28002033, Opcode.OP, Funct3.XPERM4, Funct7.XPERM, rd=0, rs1=0, rs2=0, op=OpType.CROSSBAR_PERMUTATION
187          ),
188          # XPERM8
189          InstrTest(
190              0x28004033, Opcode.OP, Funct3.XPERM8, Funct7.XPERM, rd=0, rs1=0, rs2=0, op=OpType.CROSSBAR_PERMUTATION
191          ),
192      ]
193  
194      DECODER_TESTS_A = [
195          InstrTest(0x0821A22F, Opcode.AMO, Funct3.W, Funct7.AMOSWAP, rd=4, rs2=2, rs1=3, op=OpType.ATOMIC_MEMORY_OP),
196          InstrTest(
197              0x0C21A22F, Opcode.AMO, Funct3.W, Funct7.AMOSWAP | 0x2, rd=4, rs2=2, rs1=3, op=OpType.ATOMIC_MEMORY_OP
198          ),
199          InstrTest(0x1812A1AF, Opcode.AMO, Funct3.W, Funct7.SC, rd=3, rs2=1, rs1=5, op=OpType.ATOMIC_LR_SC),
200      ]
201  
202      def setup_method(self):
203          self.gen_params = GenParams(
204              test_core_config.replace(
205                  _implied_extensions=Extension.G
206                  | Extension.XINTMACHINEMODE
207                  | Extension.XINTSUPERVISOR
208                  | Extension.ZBB
209                  | Extension.ZBKX
210                  | Extension.ZICOND
211              )
212          )
213          self.decoder = InstrDecoder(self.gen_params)
214          self.cnt = 1
215  
216      def do_test(self, tests: list[InstrTest]):
217          async def process(sim: TestbenchContext):
218              for test in tests:
219                  sim.set(self.decoder.instr, test.encoding)
220  
221                  assert sim.get(self.decoder.illegal) == test.illegal
222                  if test.illegal:
223                      return
224  
225                  assert sim.get(self.decoder.opcode) == test.opcode
226  
227                  if test.funct3 is not None:
228                      assert sim.get(self.decoder.funct3) == test.funct3
229                  assert sim.get(self.decoder.funct3_v) == (test.funct3 is not None)
230  
231                  if test.funct7 is not None:
232                      assert sim.get(self.decoder.funct7) == test.funct7
233                  assert sim.get(self.decoder.funct7_v) == (test.funct7 is not None)
234  
235                  if test.funct12 is not None:
236                      assert sim.get(self.decoder.funct12) == test.funct12
237                  assert sim.get(self.decoder.funct12_v) == (test.funct12 is not None)
238  
239                  if test.rd is not None:
240                      assert sim.get(self.decoder.rd) == test.rd
241                  assert sim.get(self.decoder.rd_v) == (test.rd is not None)
242  
243                  if test.rs1 is not None:
244                      assert sim.get(self.decoder.rs1) == test.rs1
245                  assert sim.get(self.decoder.rs1_v) == (test.rs1 is not None)
246  
247                  if test.rs2 is not None:
248                      assert sim.get(self.decoder.rs2) == test.rs2
249                  assert sim.get(self.decoder.rs2_v) == (test.rs2 is not None)
250  
251                  if test.imm is not None:
252                      if test.csr is not None:
253                          # in CSR instruction additional fields are passed in unused bits of imm field
254                          assert sim.get(self.decoder.imm.as_signed() & ((2**5) - 1)) == test.imm
255                      else:
256                          assert sim.get(self.decoder.imm.as_signed()) == test.imm
257  
258                  if test.succ is not None:
259                      assert sim.get(self.decoder.succ) == test.succ
260  
261                  if test.pred is not None:
262                      assert sim.get(self.decoder.pred) == test.pred
263  
264                  if test.fm is not None:
265                      assert sim.get(self.decoder.fm) == test.fm
266  
267                  if test.csr is not None:
268                      assert sim.get(self.decoder.csr) == test.csr
269  
270                  assert sim.get(self.decoder.optype) == test.op
271  
272          with self.run_simulation(self.decoder) as sim:
273              sim.add_testbench(process)
274  
275      def test_i(self):
276          self.do_test(self.DECODER_TESTS_I)
277  
278      def test_zifencei(self):
279          self.do_test(self.DECODER_TESTS_ZIFENCEI)
280  
281      def test_zicsr(self):
282          self.do_test(self.DECODER_TESTS_ZICSR)
283  
284      def test_m(self):
285          self.do_test(self.DECODER_TESTS_M)
286  
287      def test_illegal(self):
288          self.do_test(self.DECODER_TESTS_ILLEGAL)
289  
290      def test_xintmachinemode(self):
291          self.do_test(self.DECODER_TESTS_XINTMACHINEMODE)
292  
293      def test_xintsupervisor(self):
294          self.do_test(self.DECODER_TESTS_XINTSUPERVISOR)
295  
296      def test_zbb(self):
297          self.do_test(self.DECODER_TESTS_ZBB)
298  
299      def test_zicond(self):
300          self.do_test(self.DECODER_TESTS_ZICOND)
301  
302      def test_zbkx(self):
303          self.do_test(self.DECODER_TESTS_ZBKX)
304  
305      def test_a(self):
306          self.do_test(self.DECODER_TESTS_A)
307  
308  
309  class TestDecoderEExtLegal(TestCaseWithSimulator):
310      E_TEST = [
311          (0x00000033, False),  # add x0, x0, x0
312          (0x00F787B3, False),  # add x15, x15, x15
313          (0x00F807B3, True),  # add x15, x16, x15
314          (0xFFF78793, False),  # addi x15, x15, -1
315          (0xFFF78813, True),  # addi x16, x15, -1
316          (0xFFFFF06F, False),  # jal x0, -2
317          (0xFFFFFF6F, True),  # jal x30, -2
318      ]
319  
320      def test_e(self):
321          self.gen_params = GenParams(test_core_config.replace(embedded=True, _implied_extensions=Extension.E))
322          self.decoder = InstrDecoder(self.gen_params)
323  
324          async def process(sim: TestbenchContext):
325              for encoding, illegal in self.E_TEST:
326                  sim.set(self.decoder.instr, encoding)
327                  assert sim.get(self.decoder.illegal) == illegal
328  
329          with self.run_simulation(self.decoder) as sim:
330              sim.add_testbench(process)
331  
332  
333  code_type: TypeAlias = tuple[Optional[int], Optional[int], Optional[int], Optional[int]]
334  funct_code_type: TypeAlias = tuple[Optional[int], Optional[int]]
335  
336  
337  class TestEncodingUniqueness(TestCase):
338      def test_encoding_uniqueness(self):
339          def instruction_code(instr: Encoding) -> code_type:
340              op_code = int(instr.opcode)
341              funct3 = int(instr.funct3) if instr.funct3 is not None else None
342              funct7 = int(instr.funct7) if instr.funct7 is not None else None
343              funct12_5bits = None
344  
345              if instr.funct12 is not None:
346                  funct7 = (int(instr.funct12) & 0xFE0) >> 5
347                  funct12_5bits = int(instr.funct12) & 0x1F
348  
349              return (op_code, funct3, funct7, funct12_5bits)
350  
351          # prefixes of encoding
352          def code_prefixes(code: code_type) -> list[code_type]:
353              prefixes = []
354  
355              for i in range(3, -1, -1):
356                  if code[i] is not None:
357                      nt = tuple(list(code[:i]) + [None] * (4 - i))
358  
359                      prefixes.append(nt)
360  
361              return prefixes
362  
363          # known_codes store insformation about already read encodings
364          # if value is Encoding -> there is instruction with given code
365          # if value is None -> there is an instruction with prefix equal to this code
366          known_codes: dict[code_type, Optional[Encoding]] = dict()
367  
368          for instructions in instructions_by_optype.values():
369              for instruction in instructions:
370                  code = instruction_code(instruction)
371                  prefixes = code_prefixes(code)
372  
373                  for prefix in prefixes:
374                      if prefix in known_codes:
375                          encoding = known_codes[prefix]
376  
377                          # prefix of instruction can not be equal to code of any other instruction
378                          assert encoding is None, f"Instruction is not unique: I1 = {encoding} I2 = {instruction}"
379  
380                      known_codes[prefix] = None
381  
382                  # current instruction can not be prefix of other instruction
383                  self.assertNotIn(code, known_codes, f"Instruction is not unique: I = {instruction}")
384  
385                  known_codes[code] = instruction
386  
387      def test_decoded_distinguishable(self):
388          collisions: dict[OpType, set[Encoding]] = {
389              OpType.ARITHMETIC: {
390                  Encoding(Opcode.OP_IMM, Funct3.ADD),
391                  Encoding(Opcode.LUI),
392              },
393              OpType.SHIFT: {
394                  Encoding(Opcode.OP_IMM, Funct3.SLL, Funct7.SL),
395                  Encoding(Opcode.OP_IMM, Funct3.SR, Funct7.SL),
396                  Encoding(Opcode.OP_IMM, Funct3.SR, Funct7.SA),
397              },
398              OpType.LOGIC: {
399                  Encoding(Opcode.OP_IMM, Funct3.XOR),
400                  Encoding(Opcode.OP_IMM, Funct3.OR),
401                  Encoding(Opcode.OP_IMM, Funct3.AND),
402              },
403              OpType.COMPARE: {
404                  Encoding(Opcode.OP_IMM, Funct3.SLT),
405                  Encoding(Opcode.OP_IMM, Funct3.SLTU),
406              },
407              OpType.SINGLE_BIT_MANIPULATION: {
408                  Encoding(Opcode.OP_IMM, Funct3.BCLR, Funct7.BCLR),
409                  Encoding(Opcode.OP_IMM, Funct3.BEXT, Funct7.BEXT),
410                  Encoding(Opcode.OP_IMM, Funct3.BSET, Funct7.BSET),
411                  Encoding(Opcode.OP_IMM, Funct3.BINV, Funct7.BINV),
412              },
413              OpType.BIT_ROTATION: {
414                  Encoding(Opcode.OP_IMM, Funct3.ROR, Funct7.ROR),
415              },
416          }
417  
418          def instruction_code(instr: Encoding) -> funct_code_type:
419              funct3 = int(instr.funct3) if instr.funct3 is not None else 0
420              funct7 = int(instr.funct7) if instr.funct7 is not None else 0
421  
422              if instr.funct12 is not None:
423                  funct7 = (int(instr.funct12) & 0xFE0) >> 5
424  
425              return (funct3, funct7)
426  
427          for ext, instructions in instructions_by_optype.items():
428              known_codes: set[funct_code_type] = set()
429              ext_collisions = collisions[ext] if ext in collisions else set()
430  
431              for instruction in instructions:
432                  if instruction in ext_collisions:
433                      continue
434  
435                  code = instruction_code(instruction)
436  
437                  self.assertNotIn(
438                      code, known_codes, f"Instruction is not unique within OpType: OpType={ext} I={instruction}"
439                  )
440  
441                  known_codes.add(code)
442  
443              for instruction in ext_collisions:
444                  code = instruction_code(instruction)
445                  assert code in known_codes, f"Instruction is not colliding: OpType={ext} I={instruction}"