Visualizing the RISC-V Instruction Set

4 min read Original article ↗
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <immintrin.h> #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" #include "encoding.out.h" /* * This "encoding.out.h" was auto-generated by running * 'PYTHONPATH=src python -m riscv_opcodes -c "rv*"' in * https://github.com/riscv/riscv-opcodes (a2766fd) * with the following patch applied: * diff --git a/src/riscv_opcodes/c_utils.py b/src/riscv_opcodes/c_utils.py * index 198a37f..236fe6f 100644 * --- a/src/riscv_opcodes/c_utils.py * +++ b/src/riscv_opcodes/c_utils.py * @@ -15,2 +15,3 @@ def make_c(instr_dict: InstrDict): * declare_insn_str = "" * + myexts = set() * for i in instr_dict: * @@ -22,3 +23,10 @@ def make_c(instr_dict: InstrDict): * ) * - declare_insn_str += f'DECLARE_INSN({i.replace(".","_")}, MATCH_{i.upper().replace(".","_")}, MASK_{i.upper().replace(".","_")})\n' * + myexts.add(instr_dict[i]["extension"][0]) * + declare_insn_str += f'DECLARE_INSN(EXT_{instr_dict[i]["extension"][0]}, {i.replace(".","_")}, MATCH_{i.upper().replace(".","_")}, MASK_{i.upper().replace(".","_")})\n' * + ext_enum = "" * + ext_str = "" * + for e in myexts: * + ext_enum += ( f'EXT_{e},\n' ) * + ext_str += ( f'"{e}",') * + * * @@ -65,2 +73,7 @@ def make_c(instr_dict: InstrDict): * {mask_match_str} * +typedef enum Ext {{ * +EXT_NONE, * +{ext_enum}EXT_COUNT * +}} Ext; * +const char *ext2str[EXT_COUNT] = {{ {ext_str} }}; * {csr_names_str} */ #define ARR_LEN(a) (sizeof (a) / sizeof *(a)) typedef struct ExtGroup { const char *name; Ext *exts; } ExtGroup; #define EXT_custom EXT_COUNT #define EXT_gt32b (EXT_COUNT+1) typedef struct Insn { uint32_t ext, match, mask; } Insn; Insn insns[] = { {EXT_custom, 0b1011011, 0b1011111 }, {EXT_custom, 0b0101011, 0b0111111 }, {EXT_gt32b, 0b0011111, 0b0011111 }, #define DECLARE_INSN(ext,name,match,mask) {ext, match, mask}, #include "encoding.out.h" #undef DECLARE_INSN }; #define SEL 1 // select between first and second image #if SEL == 1 static const uint32_t BG = 0xFF100408; static uint32_t colors[] = { 0x5F8E02, 0x002ECB, 0x1A95FF, }; static ExtGroup groups[] = { { "16-bit", (Ext[]){ EXT_rv_c, EXT_rv64_c, EXT_rv_c_d, EXT_rv_zcb, EXT_rv64_zcb, 0 } }, { "custom", (Ext[]){ EXT_custom, 0 } }, { "32-bit", (Ext[]){ EXT_rv_i, EXT_rv64_i, EXT_rv_m, EXT_rv64_m, EXT_rv_zicond, EXT_rv_zicsr, EXT_rv_zifencei, EXT_rv_zknh, EXT_rv64_zknd, EXT_rv_zksed, EXT_rv_zksh, EXT_rv64_zkne, EXT_rv64_zknh, EXT_rv_zba, EXT_rv64_zba, EXT_rv_zbb, EXT_rv64_zbb, EXT_rv_zbs, EXT_rv64_zbs, EXT_rv_zbc, EXT_rv_zbkb, EXT_rv_zbkx, EXT_rv64_zbkb, EXT_rv_a, EXT_rv64_a, EXT_rv_zabha, EXT_rv_zabha_zacas, EXT_rv_zacas, EXT_rv64_zacas, EXT_rv_zawrs, EXT_rv_s, EXT_rv_sdext, EXT_rv_smrnmi, EXT_rv_ssctr, EXT_rv_svinval, EXT_rv_system, EXT_rv_h, EXT_rv64_h, EXT_rv_svinval_h, EXT_rv_zfbfmin, EXT_rv_zicbo, EXT_rv_zimop, EXT_rv_zfh_zfa, EXT_rv_zfh, EXT_rv64_zfh, EXT_rv_zfhmin, EXT_rv_d_zfhmin, EXT_rv_f, EXT_rv64_f, EXT_rv_f_zfa, EXT_rv_d, EXT_rv64_d, EXT_rv_d_zfa, EXT_rv_q, EXT_rv64_q, EXT_rv_q_zfa, EXT_rv64_q_zfa, EXT_rv_q_zfhmin, EXT_rv_v, EXT_rv_zvbb, EXT_rv_zvbc, EXT_rv_zvkg, EXT_rv_zvkned, EXT_rv_zvknha, EXT_rv_zvksed, EXT_rv_zvksh, EXT_rv_zvfbfmin, EXT_rv_zvfbfwma, 0 } }, }; #elif SEL == 2 static const uint32_t BG = 0xFF332827; static uint32_t colors[] = { 0xF8F8F2, 0xEFD966, 0x5ACFDC, 0x1F97FD, 0xFF81AE, 0x7226F9, }; static ExtGroup groups[] = { { "custom", (Ext[]){ EXT_custom, 0 } }, //{ "C", (Ext[]){ EXT_rv_c, EXT_rv64_c, EXT_rv_c_d, EXT_rv_zcb, EXT_rv64_zcb, 0 } }, { "general", (Ext[]){ EXT_rv_i, EXT_rv64_i, EXT_rv_m, EXT_rv64_m, EXT_rv_zicond, EXT_rv_zicsr, EXT_rv_zifencei, EXT_rv_zknh, EXT_rv64_zknd, EXT_rv_zksed, EXT_rv_zksh, EXT_rv64_zkne, EXT_rv64_zknh, EXT_rv_zba, EXT_rv64_zba, EXT_rv_zbb, EXT_rv64_zbb, EXT_rv_zbs, EXT_rv64_zbs, EXT_rv_zbc, EXT_rv_zbkb, EXT_rv_zbkx, EXT_rv64_zbkb, EXT_rv_a, EXT_rv64_a, EXT_rv_zabha, EXT_rv_zabha_zacas, EXT_rv_zacas, EXT_rv64_zacas, EXT_rv_zawrs, 0 } }, { "system", (Ext[]){ EXT_rv_zicsr, EXT_rv_zifencei, EXT_rv_s, EXT_rv_sdext, EXT_rv_smrnmi, EXT_rv_ssctr, EXT_rv_svinval, EXT_rv_system, EXT_rv_h, EXT_rv64_h, EXT_rv_svinval_h, EXT_rv_zicbo, EXT_rv_zimop, 0 } }, { "FP", (Ext[]){ EXT_rv_zfh_zfa, EXT_rv_zfh, EXT_rv64_zfh, EXT_rv_zfhmin, EXT_rv_d_zfhmin, EXT_rv_f, EXT_rv64_f, EXT_rv_f_zfa, EXT_rv_d, EXT_rv64_d, EXT_rv_d_zfa, EXT_rv_q, EXT_rv64_q, EXT_rv_q_zfa, EXT_rv64_q_zfa, EXT_rv_q_zfhmin, EXT_rv_zfbfmin, 0 } }, { "V", (Ext[]){ EXT_rv_v, EXT_rv_zvbb, EXT_rv_zvbc, EXT_rv_zvfbfmin, EXT_rv_zvfbfwma, 0 } }, { "Zvk", (Ext[]){ EXT_rv_zvkg, EXT_rv_zvkned, EXT_rv_zvknha, EXT_rv_zvksed, EXT_rv_zvksh, 0 } }, }; #endif _Static_assert(ARR_LEN(colors) >= ARR_LEN(groups), "insufficient colors defined"); #if SEL == 1 #define WIDTH (1ull<<13) #elif SEL == 2 #define WIDTH (1ull<<11) #endif #include <immintrin.h> static uint32_t perm(uint32_t u) { // u = _pext_u32(u,0b11111111111100001111111001111111); u = (u & 0b1111111) | ((u>>2) & (0b1111111<<7)) | ((u>>6) & (0b111111111111<<14)); // reverse bits u = ((u >> 1) & 0x55555555) | ((u & 0x55555555) << 1); u = ((u >> 2) & 0x33333333) | ((u & 0x33333333) << 2); u = ((u >> 4) & 0x0F0F0F0F) | ((u & 0x0F0F0F0F) << 4); #if SEL == 1 u = __builtin_bswap32(u) >> 6; #elif SEL == 2 u = __builtin_bswap32(u)<<2 >> 10; #endif // interleave for morton code uint32_t x = _pext_u32(u, 0b01010101010101010101010101010101); uint32_t y = _pext_u32(u, 0b10101010101010101010101010101010); return (x+y*WIDTH) & (WIDTH*WIDTH-1); } int main(void) { size_t total = 0; uint32_t *img = malloc(WIDTH*WIDTH * sizeof *img); for (size_t i = 0; i < WIDTH*WIDTH; ++i) img[i] = BG; for (size_t g = 0; g < ARR_LEN(groups); ++g) { uint32_t color = colors[g]; printf("%s:\t0x%08X\n", groups[g].name, color | 0xFF000000); for (Ext *e = groups[g].exts; *e; ++e) { for (size_t i = 0; i < ARR_LEN(insns); ++i) { if (insns[i].ext != *e) continue; uint32_t match = insns[i].match, mask = ~insns[i].mask; match = perm(match); mask = perm(mask); uint32_t cnt = 1ull << __builtin_popcount(mask); uint32_t opcode = 0; for (uint32_t c = 0; c < cnt; ++c) { ++total; size_t idx = opcode & mask | match; uint32_t col = img[idx]; img[idx] = col != BG ? col : (color | 0xFF000000); opcode = (opcode | ~mask) + 1; } } } } printf("%zu\n", total); stbi_write_png("out.png", WIDTH, WIDTH, 4, img, WIDTH*4); return 0; }