kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }