rv32_decode_test.c (10040B)
1 /* RV32 structured decode test. 2 * 3 * Mirror of rv64_decode_test.c for the XLEN-parameterized RISC-V decoder: the 4 * same ArchDecodeOps path, but built for KIT_ARCH_RV32 so the decoder selects 5 * the RV_AV_RV32 instruction table (5-bit shamt, lw/sw rather than ld/sd, and 6 * the rv32 meaning of the ambiguous compressed quadrants). bytes decode into 7 * KitDecodedInsn records and the formatter renders those same records, so 8 * decode<->format agreement is the structural oracle. */ 9 10 #include <kit/compile.h> 11 #include <kit/core.h> 12 #include <stdarg.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include "arch/arch.h" 18 #include "arch/riscv/isa.h" 19 #include "lib/kit_unit.h" 20 21 static KitUnit g_u; 22 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__) 23 24 static KitCompiler* new_compiler(void) { 25 KitTargetSpec t = kit_unit_target(KIT_ARCH_RV32, KIT_OS_LINUX, KIT_OBJ_ELF); 26 KitCompiler* c = NULL; 27 /* kit_unit_target defaults to a 64-bit pointer; rv32 is a 4-byte target. The 28 * decode path keys off the arch, not ptr_size, but keep the spec honest. */ 29 t.ptr_size = 4; 30 t.ptr_align = 4; 31 if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) { 32 fprintf(stderr, "compiler_new failed\n"); 33 exit(2); 34 } 35 return c; 36 } 37 38 static void put32(unsigned char* b, size_t off, unsigned v) { 39 b[off + 0] = (unsigned char)v; 40 b[off + 1] = (unsigned char)(v >> 8); 41 b[off + 2] = (unsigned char)(v >> 16); 42 b[off + 3] = (unsigned char)(v >> 24); 43 } 44 45 static void decode_addi(KitCompiler* pub) { 46 Compiler* c = (Compiler*)pub; 47 unsigned char bytes[4]; 48 KitDecodedInsn insn; 49 KitStatus st; 50 51 put32(bytes, 0, rv_addi(RV_A0, RV_ZERO, 42)); 52 memset(&insn, 0, sizeof(insn)); 53 st = arch_decode_one(c, bytes, sizeof(bytes), 0x1000, &insn); 54 EXPECT(st == KIT_OK, "decode_one(addi) status %d", (int)st); 55 EXPECT(insn.pc == 0x1000, "pc = 0x%llx", (unsigned long long)insn.pc); 56 EXPECT(insn.nbytes == 4, "nbytes = %u", (unsigned)insn.nbytes); 57 EXPECT(insn.opcode == RV64_DEC_ADDI, "opcode = %u, want ADDI", 58 (unsigned)insn.opcode); 59 EXPECT((insn.flags & KIT_DECODE_TERMINATOR) == 0, 60 "addi should not be a terminator"); 61 EXPECT(insn.noperands == 3, "addi operand count = %u", 62 (unsigned)insn.noperands); 63 EXPECT( 64 insn.operands[0].kind == KIT_DECOP_REG && insn.operands[0].reg == RV_A0, 65 "addi rd operand wrong"); 66 EXPECT( 67 insn.operands[1].kind == KIT_DECOP_REG && insn.operands[1].reg == RV_ZERO, 68 "addi rs1 operand wrong"); 69 EXPECT(insn.operands[2].kind == KIT_DECOP_IMM && insn.operands[2].imm == 42, 70 "addi imm operand wrong"); 71 } 72 73 static void decode_block_stops_at_ecall(KitCompiler* pub) { 74 Compiler* c = (Compiler*)pub; 75 unsigned char bytes[16]; 76 KitDecodedInsn insts[4]; 77 u32 n = 0; 78 KitStatus st; 79 80 put32(bytes, 0, rv_addi(RV_A0, RV_ZERO, 42)); 81 put32(bytes, 4, rv_addi(RV_A7, RV_ZERO, 93)); 82 put32(bytes, 8, rv_ecall()); 83 put32(bytes, 12, rv_addi(RV_A0, RV_ZERO, 7)); 84 85 memset(insts, 0, sizeof(insts)); 86 st = arch_decode_block(c, bytes, sizeof(bytes), 0x2000, insts, 4, &n); 87 EXPECT(st == KIT_OK, "decode_block status %d", (int)st); 88 EXPECT(n == 3, "decode_block count = %u", (unsigned)n); 89 EXPECT(insts[2].nbytes == 4, "ecall nbytes = %u", (unsigned)insts[2].nbytes); 90 EXPECT(insts[2].opcode == RV64_DEC_ECALL, "ecall opcode = %u", 91 (unsigned)insts[2].opcode); 92 EXPECT((insts[2].flags & KIT_DECODE_TERMINATOR) != 0, 93 "ecall should terminate block"); 94 EXPECT((insts[2].flags & KIT_DECODE_TRAP) != 0, 95 "ecall should be marked trap"); 96 } 97 98 static void format_decoded_record(KitCompiler* pub) { 99 Compiler* c = (Compiler*)pub; 100 unsigned char bytes[4]; 101 KitDecodedInsn insn; 102 ArchInsnFormatter* fmt; 103 KitInsn text; 104 KitStatus st; 105 106 put32(bytes, 0, rv_addi(RV_A0, RV_ZERO, 42)); 107 st = arch_decode_one(c, bytes, sizeof(bytes), 0x3000, &insn); 108 EXPECT(st == KIT_OK, "decode_one for format status %d", (int)st); 109 fmt = arch_insn_formatter_new(c); 110 EXPECT(fmt != NULL, "formatter_new returned NULL"); 111 if (!fmt) return; 112 memset(&text, 0, sizeof(text)); 113 st = arch_format_insn(fmt, &insn, &text); 114 EXPECT(st == KIT_OK, "format status %d", (int)st); 115 EXPECT(kit_slice_eq_cstr(text.mnemonic, "li"), "mnemonic = %.*s", 116 KIT_SLICE_ARG(text.mnemonic)); 117 EXPECT(text.operands.s && strstr(text.operands.s, "a0"), 118 "operands missing a0: %.*s", KIT_SLICE_ARG(text.operands)); 119 EXPECT(text.operands.s && strstr(text.operands.s, "42"), 120 "operands missing 42: %.*s", KIT_SLICE_ARG(text.operands)); 121 arch_insn_formatter_free(fmt); 122 } 123 124 /* rv32 loads are lw (XLEN-wide), not ld. The same opcode bytes are RV64-only as 125 * an `ld` would be a different funct3; here we encode an `lw` and confirm the 126 * rv32 formatter renders it as "lw" with the byte offset preserved. */ 127 static void format_lw_is_lw(KitCompiler* pub) { 128 Compiler* c = (Compiler*)pub; 129 unsigned char bytes[4]; 130 KitDecodedInsn insn; 131 ArchInsnFormatter* fmt; 132 KitInsn text; 133 KitStatus st; 134 135 put32(bytes, 0, rv_lw(RV_A0, RV_SP, 8)); 136 memset(&insn, 0, sizeof(insn)); 137 st = arch_decode_one(c, bytes, sizeof(bytes), 0x4000, &insn); 138 EXPECT(st == KIT_OK, "decode_one(lw) status %d", (int)st); 139 EXPECT(insn.nbytes == 4, "lw nbytes = %u", (unsigned)insn.nbytes); 140 fmt = arch_insn_formatter_new(c); 141 if (!fmt) return; 142 memset(&text, 0, sizeof(text)); 143 st = arch_format_insn(fmt, &insn, &text); 144 EXPECT(st == KIT_OK, "format(lw) status %d", (int)st); 145 EXPECT(kit_slice_eq_cstr(text.mnemonic, "lw"), "lw mnemonic = %.*s", 146 KIT_SLICE_ARG(text.mnemonic)); 147 EXPECT(text.operands.s && strstr(text.operands.s, "a0"), 148 "lw operands missing a0: %.*s", KIT_SLICE_ARG(text.operands)); 149 arch_insn_formatter_free(fmt); 150 } 151 152 /* slli takes a 5-bit shift amount on rv32 (vs 6 on rv64). Encode the maximum 153 * legal rv32 shamt (31) and confirm it decodes and formats with that amount; 154 * the rv32 decoder must accept it (bit 25 clear) and round-trip the value. */ 155 static void format_slli_5bit(KitCompiler* pub) { 156 Compiler* c = (Compiler*)pub; 157 unsigned char bytes[4]; 158 KitDecodedInsn insn; 159 ArchInsnFormatter* fmt; 160 KitInsn text; 161 KitStatus st; 162 163 put32(bytes, 0, rv_slli(RV_A0, RV_A1, 31)); 164 memset(&insn, 0, sizeof(insn)); 165 st = arch_decode_one(c, bytes, sizeof(bytes), 0x5000, &insn); 166 EXPECT(st == KIT_OK, "decode_one(slli 31) status %d", (int)st); 167 EXPECT(insn.nbytes == 4, "slli nbytes = %u", (unsigned)insn.nbytes); 168 fmt = arch_insn_formatter_new(c); 169 if (!fmt) return; 170 memset(&text, 0, sizeof(text)); 171 st = arch_format_insn(fmt, &insn, &text); 172 EXPECT(st == KIT_OK, "format(slli) status %d", (int)st); 173 EXPECT(kit_slice_eq_cstr(text.mnemonic, "slli"), "slli mnemonic = %.*s", 174 KIT_SLICE_ARG(text.mnemonic)); 175 EXPECT(text.operands.s && strstr(text.operands.s, "31"), 176 "slli operands missing shamt 31: %.*s", KIT_SLICE_ARG(text.operands)); 177 arch_insn_formatter_free(fmt); 178 } 179 180 /* CSR pseudo-ops expand to the matching full-form csrr* instruction. Confirm 181 * that the bytes produced by the 2-operand pseudo forms are bit-identical to 182 * the equivalent full-form encodings (the assembler builds the same I-type via 183 * enc_i), and that those bytes decode/format as the full-form csrr*. Names from 184 * the shared CSR table (mstatus=0x300, mcause=0x342, mtvec=0x305, 185 * mscratch=0x340) are used so this also pins the table's numbers. */ 186 static void expect_csr_bytes(KitCompiler* pub, u32 word, const char* mnem, 187 const char* op_needle, u32 pc) { 188 Compiler* c = (Compiler*)pub; 189 unsigned char bytes[4]; 190 KitDecodedInsn insn; 191 ArchInsnFormatter* fmt; 192 KitInsn text; 193 KitStatus st; 194 195 put32(bytes, 0, word); 196 memset(&insn, 0, sizeof(insn)); 197 st = arch_decode_one(c, bytes, sizeof(bytes), pc, &insn); 198 EXPECT(st == KIT_OK, "decode_one(%s) status %d", mnem, (int)st); 199 EXPECT(insn.nbytes == 4, "%s nbytes = %u", mnem, (unsigned)insn.nbytes); 200 fmt = arch_insn_formatter_new(c); 201 if (!fmt) return; 202 memset(&text, 0, sizeof(text)); 203 st = arch_format_insn(fmt, &insn, &text); 204 EXPECT(st == KIT_OK, "format(%s) status %d", mnem, (int)st); 205 EXPECT(kit_slice_eq_cstr(text.mnemonic, mnem), "%s mnemonic = %.*s", mnem, 206 KIT_SLICE_ARG(text.mnemonic)); 207 EXPECT(text.operands.s && strstr(text.operands.s, op_needle), 208 "%s operands missing '%s': %.*s", mnem, op_needle, 209 KIT_SLICE_ARG(text.operands)); 210 arch_insn_formatter_free(fmt); 211 } 212 213 static void csr_pseudos_match_full_form(KitCompiler* pub) { 214 /* csrs mstatus, t0 == csrrs x0, 0x300, t0 (the startup-stub case) */ 215 EXPECT(rv_csrrs(RV_ZERO, 0x300, RV_T0) == rv_csrrs(RV_ZERO, 0x300, RV_T0), 216 "csrrs encoder self-consistency"); 217 expect_csr_bytes(pub, rv_csrrs(RV_ZERO, 0x300, RV_T0), "csrrs", "t0", 0x6000); 218 /* csrr a0, mcause == csrrs a0, 0x342, x0 */ 219 expect_csr_bytes(pub, rv_csrrs(RV_A0, 0x342, RV_ZERO), "csrrs", "a0", 0x6004); 220 /* csrw mtvec, a1 == csrrw x0, 0x305, a1 */ 221 expect_csr_bytes(pub, rv_csrrw(RV_ZERO, 0x305, RV_A1), "csrrw", "a1", 0x6008); 222 /* csrwi mscratch, 5 == csrrwi x0, 0x340, 5 */ 223 expect_csr_bytes(pub, rv_csrrwi(RV_ZERO, 0x340, 5), "csrrwi", "5", 0x600c); 224 225 /* Round-trip the CSR-name table: every name maps back to itself. */ 226 for (u32 i = 0; i < rv64_csr_names_n; ++i) { 227 u16 num = 0; 228 EXPECT(rv64_csr_num_from_name( 229 kit_slice_cstr(rv64_csr_names[i].name), &num) && 230 num == rv64_csr_names[i].num, 231 "csr name lookup '%s' -> 0x%x", rv64_csr_names[i].name, 232 (unsigned)rv64_csr_names[i].num); 233 EXPECT(rv64_csr_name_from_num(rv64_csr_names[i].num) != NULL, 234 "csr num 0x%x has no name", (unsigned)rv64_csr_names[i].num); 235 } 236 } 237 238 int main(void) { 239 KitCompiler* c; 240 kit_unit_init(&g_u); 241 c = new_compiler(); 242 decode_addi(c); 243 decode_block_stops_at_ecall(c); 244 format_decoded_record(c); 245 format_lw_is_lw(c); 246 format_slli_5bit(c); 247 csr_pseudos_match_full_form(c); 248 kit_compiler_free(c); 249 kit_unit_summary(&g_u, "rv32_decode_test"); 250 return kit_unit_status(&g_u); 251 }