rv64_decode_test.c (9191B)
1 /* RV64 structured decode test. 2 * 3 * Pins the ArchDecodeOps path used by the emu lifter bring-up: bytes decode 4 * into KitDecodedInsn records, and the formatter renders those same 5 * records for disassembly without parsing text back into operands. */ 6 7 #include <kit/compile.h> 8 #include <kit/core.h> 9 #include <stdarg.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include "arch/arch.h" 15 #include "arch/riscv/isa.h" 16 #include "lib/kit_unit.h" 17 18 /* Shared test context replaces the per-file heap/diag/counter globals; 19 * EXPECT aliases CU_EXPECT so the call sites are unchanged. */ 20 static KitUnit g_u; 21 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__) 22 23 static KitCompiler* new_compiler(void) { 24 KitTargetSpec t = kit_unit_target(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF); 25 KitCompiler* c = NULL; 26 if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) { 27 fprintf(stderr, "compiler_new failed\n"); 28 exit(2); 29 } 30 return c; 31 } 32 33 static void put32(unsigned char* b, size_t off, unsigned v) { 34 b[off + 0] = (unsigned char)v; 35 b[off + 1] = (unsigned char)(v >> 8); 36 b[off + 2] = (unsigned char)(v >> 16); 37 b[off + 3] = (unsigned char)(v >> 24); 38 } 39 40 static void put16(unsigned char* b, size_t off, unsigned v) { 41 b[off + 0] = (unsigned char)v; 42 b[off + 1] = (unsigned char)(v >> 8); 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 /* CSR pseudo-ops expand to the matching full-form csrr* instruction. Confirm 125 * the bytes the 2-operand pseudo forms build (via enc_i, supplying x0 for the 126 * dropped operand) are bit-identical to the full-form encodings and decode / 127 * format as those full forms. CSR numbers come from the shared name table 128 * (mstatus=0x300, mcause=0x342, mtvec=0x305, mscratch=0x340). */ 129 static void expect_csr_bytes(KitCompiler* pub, u32 word, const char* mnem, 130 const char* op_needle, u32 pc) { 131 Compiler* c = (Compiler*)pub; 132 unsigned char bytes[4]; 133 KitDecodedInsn insn; 134 ArchInsnFormatter* fmt; 135 KitInsn text; 136 KitStatus st; 137 138 put32(bytes, 0, word); 139 memset(&insn, 0, sizeof(insn)); 140 st = arch_decode_one(c, bytes, sizeof(bytes), pc, &insn); 141 EXPECT(st == KIT_OK, "decode_one(%s) status %d", mnem, (int)st); 142 EXPECT(insn.nbytes == 4, "%s nbytes = %u", mnem, (unsigned)insn.nbytes); 143 fmt = arch_insn_formatter_new(c); 144 if (!fmt) return; 145 memset(&text, 0, sizeof(text)); 146 st = arch_format_insn(fmt, &insn, &text); 147 EXPECT(st == KIT_OK, "format(%s) status %d", mnem, (int)st); 148 EXPECT(kit_slice_eq_cstr(text.mnemonic, mnem), "%s mnemonic = %.*s", mnem, 149 KIT_SLICE_ARG(text.mnemonic)); 150 EXPECT(text.operands.s && strstr(text.operands.s, op_needle), 151 "%s operands missing '%s': %.*s", mnem, op_needle, 152 KIT_SLICE_ARG(text.operands)); 153 arch_insn_formatter_free(fmt); 154 } 155 156 static void csr_pseudos_match_full_form(KitCompiler* pub) { 157 /* csrs mstatus, t0 == csrrs x0, 0x300, t0 */ 158 expect_csr_bytes(pub, rv_csrrs(RV_ZERO, 0x300, RV_T0), "csrrs", "t0", 0x6000); 159 /* csrr a0, mcause == csrrs a0, 0x342, x0 */ 160 expect_csr_bytes(pub, rv_csrrs(RV_A0, 0x342, RV_ZERO), "csrrs", "a0", 0x6004); 161 /* csrw mtvec, a1 == csrrw x0, 0x305, a1 */ 162 expect_csr_bytes(pub, rv_csrrw(RV_ZERO, 0x305, RV_A1), "csrrw", "a1", 0x6008); 163 /* csrwi mscratch, 5 == csrrwi x0, 0x340, 5 */ 164 expect_csr_bytes(pub, rv_csrrwi(RV_ZERO, 0x340, 5), "csrrwi", "5", 0x600c); 165 166 /* Round-trip the CSR-name table. */ 167 for (u32 i = 0; i < rv64_csr_names_n; ++i) { 168 u16 num = 0; 169 EXPECT( 170 rv64_csr_num_from_name(kit_slice_cstr(rv64_csr_names[i].name), &num) && 171 num == rv64_csr_names[i].num, 172 "csr name lookup '%s' -> 0x%x", rv64_csr_names[i].name, 173 (unsigned)rv64_csr_names[i].num); 174 EXPECT(rv64_csr_name_from_num(rv64_csr_names[i].num) != NULL, 175 "csr num 0x%x has no name", (unsigned)rv64_csr_names[i].num); 176 } 177 } 178 179 /* The CR compressed format packs c.jr/c.jalr (rs2==0, rd/rs1!=0) and 180 * c.mv/c.add (rs2!=0). rv64_decode_flags derives the control-flow flags from 181 * the encoding (bit[12] picks the linking c.jalr) rather than the mnemonic 182 * string; pin that decode here so the dispatch stays encoding-driven. */ 183 static unsigned cr_word(unsigned bit12, unsigned rd_rs1, unsigned rs2) { 184 return (4u << 13) | ((bit12 & 1u) << 12) | ((rd_rs1 & 0x1fu) << 7) | 185 ((rs2 & 0x1fu) << 2) | 2u; 186 } 187 188 static void expect_cr_flags(KitCompiler* pub, unsigned word, u16 want_set, 189 u16 want_clear, const char* what) { 190 Compiler* c = (Compiler*)pub; 191 unsigned char bytes[4]; 192 KitDecodedInsn insn; 193 KitStatus st; 194 memset(bytes, 0, sizeof(bytes)); 195 put16(bytes, 0, word); 196 memset(&insn, 0, sizeof(insn)); 197 st = arch_decode_one(c, bytes, sizeof(bytes), 0x7000, &insn); 198 EXPECT(st == KIT_OK, "decode_one(%s) status %d", what, (int)st); 199 EXPECT(insn.nbytes == 2, "%s nbytes = %u (want 2)", what, 200 (unsigned)insn.nbytes); 201 EXPECT((insn.flags & want_set) == want_set, "%s flags 0x%x missing 0x%x", 202 what, (unsigned)insn.flags, (unsigned)want_set); 203 EXPECT((insn.flags & want_clear) == 0, "%s flags 0x%x should clear 0x%x", 204 what, (unsigned)insn.flags, (unsigned)want_clear); 205 } 206 207 static void decode_compressed_cr_flags(KitCompiler* pub) { 208 u16 br = (u16)(KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH); 209 u16 ctrl = (u16)(KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH | KIT_DECODE_CALL); 210 /* c.jr ra: branch terminator, not a call. */ 211 expect_cr_flags(pub, cr_word(0, RV_RA, 0), br, (u16)KIT_DECODE_CALL, "c.jr"); 212 /* c.jalr ra: linking branch -> call. */ 213 expect_cr_flags(pub, cr_word(1, RV_RA, 0), ctrl, 0, "c.jalr"); 214 /* c.mv / c.add (rs2!=0): not control transfers. */ 215 expect_cr_flags(pub, cr_word(0, RV_A0, RV_A1), 0, ctrl, "c.mv"); 216 expect_cr_flags(pub, cr_word(1, RV_A0, RV_A1), 0, ctrl, "c.add"); 217 } 218 219 int main(void) { 220 KitCompiler* c; 221 kit_unit_init(&g_u); 222 c = new_compiler(); 223 decode_addi(c); 224 decode_block_stops_at_ecall(c); 225 format_decoded_record(c); 226 csr_pseudos_match_full_form(c); 227 decode_compressed_cr_flags(c); 228 kit_compiler_free(c); 229 kit_unit_summary(&g_u, "rv64_decode_test"); 230 return kit_unit_status(&g_u); 231 }