-
-
Save dzaima/645c92635c2717805b65b22d1d9222b0 to your computer and use it in GitHub Desktop.
Visualizing the RISC-V Instruction Set
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef SEL | |
| #define SEL 2 // select between first and second image | |
| #endif | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdint.h> | |
| #include <stdbool.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 | |
| }; | |
| #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 SHIFT 13 | |
| #define WIDTH (1ull<<13) | |
| static const float amt_scale = 1.0 / (1<<6); // 2^(13*2) / 2^32 | |
| #elif SEL == 2 | |
| #define SHIFT 11 | |
| #define WIDTH (1ull<<11) | |
| static const float amt_scale = 1.0 / (1<<8); // 4x larger to compensate only 25% of the encoding space being available | |
| #endif | |
| #include <immintrin.h> | |
| uint32_t rol32(uint32_t v, int a) { | |
| return v << a | v >> (32-a); | |
| } | |
| uint32_t sag(uint32_t v, uint32_t m) { | |
| uint32_t lo = _pext_u32(v, m); | |
| uint32_t hi = _pext_u32(v, ~m); | |
| return hi<<__builtin_popcount(m) | lo; | |
| } | |
| static uint32_t | |
| perm(uint32_t* scal, uint32_t u, bool comp) { | |
| // pull interesting bits to LSB | |
| if (comp) { | |
| // compressed mostly puts the opcode in MSBs; funky sequence to pull bits to LSB in reverse-order-ish | |
| u = sag(u, 0b1110000000000011); | |
| u = sag(u, 0b1000000000011111); | |
| u = sag(u, 0b1000000000111111); | |
| u = sag(u, 0b1000000001111111); | |
| // printf("%016b\n", u); | |
| } else { | |
| // funct7 srcs/imm fn3 dst opcode | |
| u = sag(u, 0b1111111'0000000000'111'00000'1111111); | |
| } | |
| // reverse to put opcode first | |
| u = ((u >> 1) & 0x55555555) | ((u & 0x55555555) << 1); | |
| u = ((u >> 2) & 0x33333333) | ((u & 0x33333333) << 2); | |
| u = ((u >> 4) & 0x0F0F0F0F) | ((u & 0x0F0F0F0F) << 4); | |
| u = __builtin_bswap32(u); | |
| if (SEL==2) u = rol32(u, 2); // for 32B-only, rotate away the boring 0b11 LSBs | |
| int la = 32 - SHIFT*2; | |
| uint32_t hi = u >> la; | |
| uint32_t lo = u & ((1u<<la) - 1); | |
| // if (SEL==1) printf("%032b %026b %06b\n", u, hi, lo); | |
| // if (SEL==2) printf("%032b %022b %010b\n", u, hi, lo); | |
| *scal = 1<<__builtin_popcount(lo); | |
| // interleave for morton code | |
| uint32_t x = _pext_u32(hi, 0b01010101010101010101010101010101) & (WIDTH-1); | |
| uint32_t y = _pext_u32(hi, 0b10101010101010101010101010101010) & (WIDTH-1); | |
| return x+y*WIDTH; | |
| } | |
| void unp(uint32_t dst[4], uint32_t src) { | |
| for (int i = 0; i < 4; i++) dst[i] = (src>>(i*8)) & 0xff; | |
| } | |
| uint32_t pck(uint16_t src[4], bool opaque) { | |
| uint32_t bad = false; | |
| for (int i = 0; i < 4; i++) bad |= src[i]>255; | |
| uint32_t r = 0; | |
| if (bad) { | |
| uint32_t max = 0; | |
| for (int i = 0; i < 4; i++) if (src[i]>=max) max = src[i]; | |
| for (int i = 0; i < 4; i++) r |= (src[i] * 255 / max) << (i*8); | |
| // printf("overflow in [%u,%u,%u,%u]; representing as %08x\n", src[0], src[1], src[2], src[3], r); // overflow does just happen on overlapping encodings (e.g. nop and add) | |
| } else { | |
| for (int i = 0; i < 4; i++) r |= src[i] << (i*8); | |
| } | |
| if (opaque) r |= 0xFF000000; | |
| return r; | |
| } | |
| int | |
| main(void) | |
| { | |
| size_t total = 0; | |
| uint16_t (*raw)[4] = malloc(WIDTH*WIDTH * sizeof *raw); | |
| uint32_t *amt = malloc(WIDTH*WIDTH * sizeof *amt); | |
| for (size_t i = 0; i < WIDTH*WIDTH; ++i) { | |
| for (int j = 0; j < 4; j++) raw[i][j] = 0; | |
| } | |
| for (size_t g = 0; g < ARR_LEN(groups); ++g) { | |
| uint32_t color = colors[g] | 0xFF000000; | |
| uint32_t b1[4]; | |
| unp(b1, color); | |
| printf("%s:\t0x%08X\n", groups[g].name, color); | |
| for (size_t i = 0; i < WIDTH*WIDTH; ++i) amt[i] = 0; | |
| 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 match0 = insns[i].match; | |
| uint32_t mask0 = ~insns[i].mask; | |
| bool comp = (match0&3) != 3; | |
| uint32_t _, scal; | |
| uint32_t match = perm(&_, match0, comp); | |
| uint32_t mask = perm(&scal, mask0, comp); | |
| 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; | |
| amt[idx]+= scal; | |
| opcode = (opcode | ~mask) + 1; | |
| } | |
| } | |
| } | |
| for (size_t i = 0; i < WIDTH*WIDTH; ++i) { | |
| uint32_t n = amt[i]; | |
| if (n) { | |
| float f = n * amt_scale; | |
| for (int j = 0; j < 4; j++) raw[i][j] += b1[j]*f; | |
| } | |
| } | |
| } | |
| uint32_t *img = malloc(WIDTH*WIDTH * sizeof *img); | |
| for (size_t i = 0; i < WIDTH*WIDTH; ++i) { | |
| uint16_t* curr = raw[i]; | |
| // if (curr[3]) for (int i = 0; i < 3; i++) curr[i] = curr[i] * 255 / curr[3]; | |
| img[i] = pck(curr, true); | |
| } | |
| printf("%zu\n", total); | |
| stbi_write_png("out.png", WIDTH, WIDTH, 4, img, WIDTH*4); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment