kit

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

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 }