test_rvc.py
1 from parameterized import parameterized_class 2 3 from amaranth import * 4 from amaranth_types import ValueLike 5 6 from coreblocks.frontend.decoder.rvc import InstrDecompress 7 from coreblocks.arch import * 8 from coreblocks.params import * 9 from coreblocks.params.configurations import test_core_config 10 11 from transactron.testing import TestCaseWithSimulator, TestbenchContext 12 13 COMMON_TESTS = [ 14 # Illegal instruction 15 (0x0000, IllegalInstr()), 16 # c.addi4spn x15, 1020 17 (0x1FFC, ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X15, funct3=Funct3.ADD, rs1=Registers.SP, imm=1020)), 18 # c.lw x13, 28(x11) 19 (0x4DD4, ITypeInstr(opcode=Opcode.LOAD, rd=Registers.X13, funct3=Funct3.W, rs1=Registers.X11, imm=28)), 20 # c.sw x10, 20(x8) 21 (0xC848, STypeInstr(opcode=Opcode.STORE, imm=20, funct3=Funct3.W, rs1=Registers.X8, rs2=Registers.X10)), 22 # c.nop 23 (0x0001, ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X0, funct3=Funct3.ADD, rs1=Registers.X0, imm=0)), 24 # c.addi x2, -28 25 ( 26 0x1111, 27 ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X2, funct3=Funct3.ADD, rs1=Registers.X2, imm=-28), 28 ), 29 # c.li x31, -7 30 ( 31 0x5FE5, 32 ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X31, funct3=Funct3.ADD, rs1=Registers.ZERO, imm=-7), 33 ), 34 # c.addi16sp 496 35 (0x617D, ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.SP, funct3=Funct3.ADD, rs1=Registers.SP, imm=496)), 36 # c.lui x7, -3 37 (0x73F5, UTypeInstr(opcode=Opcode.LUI, rd=Registers.X7, imm=Cat(C(0, 12), C(-3, 20)))), 38 # c.srli x10, 3 39 ( 40 0x810D, 41 RTypeInstr( 42 opcode=Opcode.OP_IMM, 43 rd=Registers.X10, 44 funct3=Funct3.SR, 45 rs1=Registers.X10, 46 rs2=Registers.X3, 47 funct7=Funct7.SL, 48 ), 49 ), 50 # c.srai x12, 8 51 ( 52 0x8621, 53 RTypeInstr( 54 opcode=Opcode.OP_IMM, 55 rd=Registers.X12, 56 funct3=Funct3.SR, 57 rs1=Registers.X12, 58 rs2=Registers.X8, 59 funct7=Funct7.SA, 60 ), 61 ), 62 # c.andi x9, 17 63 (0x88C5, ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X9, funct3=Funct3.AND, rs1=Registers.X9, imm=17)), 64 # c.sub x10, x15 65 ( 66 0x8D1D, 67 RTypeInstr( 68 opcode=Opcode.OP, 69 rd=Registers.X10, 70 funct3=Funct3.SUB, 71 rs1=Registers.X10, 72 rs2=Registers.X15, 73 funct7=Funct7.SUB, 74 ), 75 ), 76 # c.xor x13, x8 77 ( 78 0x8EA1, 79 RTypeInstr( 80 opcode=Opcode.OP, 81 rd=Registers.X13, 82 funct3=Funct3.XOR, 83 rs1=Registers.X13, 84 rs2=Registers.X8, 85 funct7=Funct7.XOR, 86 ), 87 ), 88 # c.or x15, x14 89 ( 90 0x8FD9, 91 RTypeInstr( 92 opcode=Opcode.OP, 93 rd=Registers.X15, 94 funct3=Funct3.OR, 95 rs1=Registers.X15, 96 rs2=Registers.X14, 97 funct7=Funct7.OR, 98 ), 99 ), 100 # c.and x9, x9 101 ( 102 0x8CE5, 103 RTypeInstr( 104 opcode=Opcode.OP, 105 rd=Registers.X9, 106 funct3=Funct3.AND, 107 rs1=Registers.X9, 108 rs2=Registers.X9, 109 funct7=Funct7.AND, 110 ), 111 ), 112 # c.j 2012 113 (0xAFF1, JTypeInstr(opcode=Opcode.JAL, rd=Registers.ZERO, imm=2012)), 114 # c.beqz x8, -6 115 ( 116 0xDC6D, 117 BTypeInstr(opcode=Opcode.BRANCH, imm=-6, funct3=Funct3.BEQ, rs1=Registers.X8, rs2=Registers.ZERO), 118 ), 119 # c.bnez x15, 20 120 ( 121 0xEB91, 122 BTypeInstr(opcode=Opcode.BRANCH, imm=20, funct3=Funct3.BNE, rs1=Registers.X15, rs2=Registers.ZERO), 123 ), 124 # c.slli x13, 31 125 ( 126 0x06FE, 127 RTypeInstr( 128 opcode=Opcode.OP_IMM, 129 rd=Registers.X13, 130 funct3=Funct3.SLL, 131 rs1=Registers.X13, 132 rs2=Registers.X31, 133 funct7=Funct7.SL, 134 ), 135 ), 136 # c.lwsp x2, 4 137 (0x4112, ITypeInstr(opcode=Opcode.LOAD, rd=Registers.X2, funct3=Funct3.W, rs1=Registers.SP, imm=4)), 138 # c.jr x30 139 ( 140 0x8F02, 141 ITypeInstr(opcode=Opcode.JALR, rd=Registers.ZERO, funct3=Funct3.JALR, rs1=Registers.X30, imm=0), 142 ), 143 # c.mv x2, x26 144 ( 145 0x816A, 146 RTypeInstr( 147 opcode=Opcode.OP, 148 rd=Registers.X2, 149 funct3=Funct3.ADD, 150 rs1=Registers.ZERO, 151 rs2=Registers.X26, 152 funct7=Funct7.ADD, 153 ), 154 ), 155 # c.ebreak 156 (0x9002, EBreakInstr()), 157 # c.add x14, x8 158 ( 159 0x9722, 160 RTypeInstr( 161 opcode=Opcode.OP, 162 rd=Registers.X14, 163 funct3=Funct3.ADD, 164 rs1=Registers.X14, 165 rs2=Registers.X8, 166 funct7=Funct7.ADD, 167 ), 168 ), 169 # c.swsp x31, 20 170 (0xCA7E, STypeInstr(opcode=Opcode.STORE, imm=20, funct3=Funct3.W, rs1=Registers.SP, rs2=Registers.X31)), 171 ] 172 173 RV32_TESTS = [ 174 # c.ld x8, 8(x9) 175 (0x6480, IllegalInstr()), 176 # c.sd x14, 0(x13) 177 (0xE298, IllegalInstr()), 178 # c.jal 40 179 (0x2025, JTypeInstr(opcode=Opcode.JAL, rd=Registers.RA, imm=40)), 180 # c.jal -412 181 (0x3595, JTypeInstr(opcode=Opcode.JAL, rd=Registers.RA, imm=-412)), 182 # c.srli x10, 32 183 (0x9101, IllegalInstr()), 184 # c.srai x12, 40 185 (0x9621, IllegalInstr()), 186 # c.subw x10, x11 187 (0x9D0D, IllegalInstr()), 188 # c.addw x15, x8 189 (0x9FA1, IllegalInstr()), 190 # c.slli x13, 63 191 (0x16FE, IllegalInstr()), 192 ] 193 194 RV64_TESTS = [ 195 # c.ld x8, 8(x9) 196 (0x6480, ITypeInstr(opcode=Opcode.LOAD, rd=Registers.X8, funct3=Funct3.D, rs1=Registers.X9, imm=8)), 197 # c.sd x14, 0(x13) 198 (0xE298, STypeInstr(opcode=Opcode.STORE, imm=0, funct3=Funct3.D, rs1=Registers.X13, rs2=Registers.X14)), 199 # c.addiw x13, -12, 200 ( 201 0x36D1, 202 ITypeInstr(opcode=Opcode.OP_IMM_32, rd=Registers.X13, funct3=Funct3.ADD, rs1=Registers.X13, imm=-12), 203 ), 204 # c.srli x10, 32 205 ( 206 0x9101, 207 RTypeInstr( 208 opcode=Opcode.OP_IMM, 209 rd=Registers.X10, 210 funct3=Funct3.SR, 211 rs1=Registers.X10, 212 rs2=Registers.X0, 213 funct7=Funct7.SL | 1, 214 ), 215 ), 216 # c.srai x12, 40 217 ( 218 0x9621, 219 RTypeInstr( 220 opcode=Opcode.OP_IMM, 221 rd=Registers.X12, 222 funct3=Funct3.SR, 223 rs1=Registers.X12, 224 rs2=Registers.X8, 225 funct7=Funct7.SA | 1, 226 ), 227 ), 228 # c.subw x10, x11 229 ( 230 0x9D0D, 231 RTypeInstr( 232 opcode=Opcode.OP32, 233 rd=Registers.X10, 234 funct3=Funct3.SUB, 235 rs1=Registers.X10, 236 rs2=Registers.X11, 237 funct7=Funct3.SUB, 238 ), 239 ), 240 # c.addw x15, x8 241 ( 242 0x9FA1, 243 RTypeInstr( 244 opcode=Opcode.OP32, 245 rd=Registers.X15, 246 funct3=Funct3.ADD, 247 rs1=Registers.X15, 248 rs2=Registers.X8, 249 funct7=Funct3.ADD, 250 ), 251 ), 252 # c.slli x13, 63 253 ( 254 0x16FE, 255 RTypeInstr( 256 opcode=Opcode.OP_IMM, 257 rd=Registers.X13, 258 funct3=Funct3.SLL, 259 rs1=Registers.X13, 260 rs2=Registers.X31, 261 funct7=Funct7.SL | 1, 262 ), 263 ), 264 # c.ldsp x29, 40 265 (0x7EA2, ITypeInstr(opcode=Opcode.LOAD, rd=Registers.X29, funct3=Funct3.D, rs1=Registers.SP, imm=40)), 266 # c.sdsp x4, 8 267 (0xE412, STypeInstr(opcode=Opcode.STORE, imm=8, funct3=Funct3.D, rs1=Registers.SP, rs2=Registers.X4)), 268 ] 269 270 271 @parameterized_class( 272 ("name", "isa_xlen", "test_cases"), 273 [("rv32ic", 32, COMMON_TESTS + RV32_TESTS), ("rv64ic", 64, COMMON_TESTS + RV64_TESTS)], 274 ) 275 class TestInstrDecompress(TestCaseWithSimulator): 276 isa_xlen: int 277 test_cases: list[tuple[int, ValueLike]] 278 279 def test(self): 280 self.gen_params = GenParams( 281 test_core_config.replace(compressed=True, xlen=self.isa_xlen, fetch_block_bytes_log=3) 282 ) 283 self.m = InstrDecompress(self.gen_params) 284 285 async def process(sim: TestbenchContext): 286 illegal = Const.cast(IllegalInstr()).value 287 288 for instr_in, instr_out in self.test_cases: 289 sim.set(self.m.instr_in, instr_in) 290 expected = Const.cast(instr_out).value 291 292 if expected == illegal: 293 expected = instr_in # for exception handling 294 295 assert sim.get(self.m.instr_out) == expected 296 await sim.tick() 297 298 with self.run_simulation(self.m) as sim: 299 sim.add_testbench(process) 300 301 302 ZCB_COMMON_TESTS = [ 303 # c.lbu x13, 3(x11) 304 (0x81F4, ITypeInstr(opcode=Opcode.LOAD, rd=Registers.X13, funct3=Funct3.BU, rs1=Registers.X11, imm=3)), 305 # c.lhu x13, 2(x11) 306 (0x85B4, ITypeInstr(opcode=Opcode.LOAD, rd=Registers.X13, funct3=Funct3.HU, rs1=Registers.X11, imm=2)), 307 # c.lh x13, 2(x11) 308 (0x85F4, ITypeInstr(opcode=Opcode.LOAD, rd=Registers.X13, funct3=Funct3.H, rs1=Registers.X11, imm=2)), 309 # c.sb x13, 3(x11) 310 (0x89F4, STypeInstr(opcode=Opcode.STORE, imm=3, funct3=Funct3.B, rs1=Registers.X11, rs2=Registers.X13)), 311 # c.sh x13, 2(x11) 312 (0x8DB4, STypeInstr(opcode=Opcode.STORE, imm=2, funct3=Funct3.H, rs1=Registers.X11, rs2=Registers.X13)), 313 # c.zext.b x13 314 (0x9EE1, ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X13, funct3=Funct3.AND, rs1=Registers.X13, imm=0xFF)), 315 # c.not x13 316 (0x9EF5, ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X13, funct3=Funct3.XOR, rs1=Registers.X13, imm=-1)), 317 # c.sext.b x13 318 ( 319 0x9EE5, 320 ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X13, funct3=Funct3.SEXTB, rs1=Registers.X13, imm=Funct12.SEXTB), 321 ), 322 # c.zext.h x13 323 ( 324 0x9EE9, 325 RTypeInstr( 326 opcode=Opcode.OP, 327 rd=Registers.X13, 328 funct3=Funct3.ZEXTH, 329 rs1=Registers.X13, 330 rs2=Registers.ZERO, 331 funct7=Funct7.ZEXTH, 332 ), 333 ), 334 # c.sext.h x13 335 ( 336 0x9EED, 337 ITypeInstr(opcode=Opcode.OP_IMM, rd=Registers.X13, funct3=Funct3.SEXTH, rs1=Registers.X13, imm=Funct12.SEXTH), 338 ), 339 # c.mul x13, x11 340 ( 341 0x9ECD, 342 RTypeInstr( 343 opcode=Opcode.OP, 344 rd=Registers.X13, 345 funct3=Funct3.MUL, 346 rs1=Registers.X13, 347 rs2=Registers.X11, 348 funct7=Funct7.MULDIV, 349 ), 350 ), 351 ] 352 353 ZCB_RV64_ONLY_TESTS = [ 354 # c.zext.w x13 (left illegal until add.uw is supported) 355 (0x9EF1, IllegalInstr()), 356 ] 357 358 359 @parameterized_class( 360 ("name", "isa_xlen", "test_cases"), 361 [("rv32imc_zcb_zbb", 32, ZCB_COMMON_TESTS), ("rv64imc_zcb_zbb", 64, ZCB_COMMON_TESTS + ZCB_RV64_ONLY_TESTS)], 362 ) 363 class TestInstrDecompressZcb(TestCaseWithSimulator): 364 isa_xlen: int 365 test_cases: list[tuple[int, ValueLike]] 366 367 def test(self): 368 self.gen_params = GenParams( 369 test_core_config.replace( 370 xlen=self.isa_xlen, 371 fetch_block_bytes_log=3, 372 _implied_extensions=Extension.I | Extension.ZCA | Extension.ZCB | Extension.ZBB | Extension.M, 373 ) 374 ) 375 self.m = InstrDecompress(self.gen_params) 376 377 async def process(sim: TestbenchContext): 378 illegal = Const.cast(IllegalInstr()).value 379 380 for instr_in, instr_out in self.test_cases: 381 sim.set(self.m.instr_in, instr_in) 382 expected = Const.cast(instr_out).value 383 384 if expected == illegal: 385 expected = instr_in 386 387 assert sim.get(self.m.instr_out) == expected 388 await sim.tick() 389 390 with self.run_simulation(self.m) as sim: 391 sim.add_testbench(process)