Created
July 16, 2021 08:16
-
-
Save bplaat/2e357c434c940aa412d65590904f6ea0 to your computer and use it in GitHub Desktop.
Kora Reincranation: simple RISC-V 32IM core simulator in C
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
| rm -rf .vscode | |
| if gcc -s -Os kora.c -o kora -lelf; then | |
| ./kora $(find riscv-tests/isa -name "rv32ui-p-*") | |
| fi |
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
| // Kora Reincranation: simple RISC-V 32IM core simulator in C | |
| // That runs risc-v tests kinda??? | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdint.h> | |
| #include <stdbool.h> | |
| #include <libelf.h> | |
| #define bit(number, bit) ((number >> bit) & 1) | |
| int string_ends_with(const char *str, const char *suffix) { | |
| if (!str || !suffix) return 0; | |
| size_t lenstr = strlen(str); | |
| size_t lensuffix = strlen(suffix); | |
| if (lensuffix > lenstr) return 0; | |
| return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; | |
| } | |
| typedef struct Kora { | |
| uint32_t ticks; | |
| int32_t r[32]; | |
| uint32_t pc; | |
| uint8_t mem[0xffff]; | |
| bool running; | |
| bool debug; | |
| bool passed; | |
| } Kora; | |
| const char *kora_rn[] = { | |
| "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", | |
| "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" | |
| }; | |
| void kora_init(Kora *kora, bool debug) { | |
| kora->ticks = 0; | |
| kora->r[0] = 0; | |
| kora->pc = 0x80000000; | |
| kora->running = true; | |
| kora->debug = debug; | |
| kora->passed = false; | |
| } | |
| int8_t kora_read_byte(Kora *kora, uint32_t address) { | |
| address -= 0x80000000; | |
| if (address > sizeof(kora->mem)) { | |
| printf("Memory read out of bounds: 0x%08x\n", address); | |
| exit(1); | |
| } | |
| return kora->mem[address]; | |
| } | |
| int16_t kora_read_half(Kora *kora, uint32_t address) { | |
| address -= 0x80000000; | |
| if (address > sizeof(kora->mem) - 1) { | |
| printf("Memory read out of bounds: 0x%08x\n", address); | |
| exit(1); | |
| } | |
| return *(int16_t *)&kora->mem[address]; | |
| } | |
| int32_t kora_read_word(Kora *kora, uint32_t address) { | |
| address -= 0x80000000; | |
| if (address > sizeof(kora->mem) - 3) { | |
| printf("Memory read out of bounds: 0x%08x\n", address); | |
| exit(1); | |
| } | |
| return *(int32_t *)&kora->mem[address]; | |
| } | |
| void kora_write_byte(Kora *kora, uint32_t address, uint8_t data) { | |
| address -= 0x80000000; | |
| if (address > sizeof(kora->mem)) { | |
| printf("Memory write out of bounds: 0x%08x = 0x%02x\n", address, data); | |
| exit(1); | |
| } | |
| kora->mem[address] = data; | |
| } | |
| void kora_write_half(Kora *kora, uint32_t address, uint16_t data) { | |
| address -= 0x80000000; | |
| if (address > sizeof(kora->mem) - 1) { | |
| printf("Memory write out of bounds: 0x%08x = 0x%04x\n", address, data); | |
| exit(1); | |
| } | |
| *(uint16_t *)&kora->mem[address] = data; | |
| } | |
| void kora_write_word(Kora *kora, uint32_t address, uint32_t data) { | |
| address -= 0x80000000; | |
| if (address > sizeof(kora->mem) - 3) { | |
| printf("Memory write out of bounds: 0x%08x = 0x%08x\n", address, data); | |
| exit(1); | |
| } | |
| *(uint32_t *)&kora->mem[address] = data; | |
| } | |
| void kora_step(Kora *p) { | |
| uint32_t i = kora_read_word(p, p->pc); | |
| if (p->debug) { | |
| printf("%08d | pc:%08x ", p->ticks++, p->pc); | |
| for (size_t i = 0; i < 8; i++) { | |
| printf("%s:%08x ", kora_rn[i], p->r[i]); | |
| } | |
| printf("| %02x %02x %02x %02x ", i >> 24, (i >> 16) &0xff, (i >> 8) &0xff, i & 0xff); | |
| } | |
| p->pc += 4; | |
| uint8_t opcode = i & 0b1111111; | |
| // R-type | |
| uint8_t rd = (i >> 7) & 0b11111; | |
| uint8_t funct3 = (i >> 12) & 0b111; | |
| uint8_t rs1 = (i >> 15) & 0b11111; | |
| uint8_t rs2 = (i >> 20) & 0b11111; | |
| uint8_t funct7 = i >> 25; | |
| // I-type | |
| int32_t i_imm = (i >> 20) & 0b11111111111; | |
| if (bit(i, 31)) i_imm = -i_imm; | |
| uint8_t i_shamt = (i >> 20) & 0b11111; | |
| // S-type | |
| int32_t s_imm = ((i >> 7) & 0b11111) | (((i >> 25) & 0b111111) << 4); | |
| if (bit(i, 31)) s_imm = -s_imm; | |
| // B-type | |
| int32_t b_imm = ((i >> 8) & 0b1111) | (((i >> 25) & 0b111111) << 4) | (bit(i, 7) << 10); | |
| b_imm <<= 1; | |
| if (bit(i, 31)) b_imm = -b_imm; | |
| // U-type | |
| int32_t u_imm = (i >> 12) & 0b1111111111111111111; | |
| if (bit(i, 31)) u_imm = -u_imm; | |
| // J-type | |
| int32_t j_imm = ((i >> 21) & 0b1111111111) | (bit(i, 19) << 10) | (((i >> 12) & 0b11111111) << 11); | |
| j_imm <<= 1; | |
| if (bit(i, 31)) j_imm = -j_imm; | |
| // System | |
| uint32_t funct12 = (i >> 20) & 0b11111111111; | |
| // OP | |
| if (opcode == 0b0110011) { | |
| // ADD | |
| if (funct3 == 0b000 && funct7 == 0b0000000) { | |
| if (p->debug) printf("add %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] + p->r[rs2]; | |
| return; | |
| } | |
| // MUL | |
| if (funct3 == 0b000 && funct7 == 0b0000001) { | |
| if (p->debug) printf("mul %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = ((int64_t)p->r[rs1] * (int64_t)p->r[rs2]) & 0xffffffff; | |
| return; | |
| } | |
| // MULH | |
| if (funct3 == 0b001 && funct7 == 0b0000001) { | |
| if (p->debug) printf("mulh %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = ((int64_t)p->r[rs1] * (int64_t)p->r[rs2]) >> 32; | |
| return; | |
| } | |
| // MULSU | |
| if (funct3 == 0b010 && funct7 == 0b0000001) { | |
| if (p->debug) printf("mulsu %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = ((int64_t)p->r[rs1] * (uint64_t)p->r[rs2]) >> 32; | |
| return; | |
| } | |
| // MULU | |
| if (funct3 == 0b011 && funct7 == 0b0000001) { | |
| if (p->debug) printf("mulu %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = ((uint64_t)p->r[rs1] * (uint64_t)p->r[rs2]) >> 32; | |
| return; | |
| } | |
| // DIV | |
| if (funct3 == 0b100 && funct7 == 0b0000001) { | |
| if (p->debug) printf("div %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] / p->r[rs2]; | |
| return; | |
| } | |
| // DIVU | |
| if (funct3 == 0b101 && funct7 == 0b0000001) { | |
| if (p->debug) printf("divu %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = (uint32_t)p->r[rs1] / (uint32_t)p->r[rs2]; | |
| return; | |
| } | |
| // REM | |
| if (funct3 == 0b110 && funct7 == 0b0000001) { | |
| if (p->debug) printf("rem %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] % p->r[rs2]; | |
| return; | |
| } | |
| // REMU | |
| if (funct3 == 0b111 && funct7 == 0b0000001) { | |
| if (p->debug) printf("remu %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = (uint32_t)p->r[rs1] % (uint32_t)p->r[rs2]; | |
| return; | |
| } | |
| // SUB | |
| if (funct3 == 0b000 && funct7 == 0b0100000) { | |
| if (p->debug) printf("sub %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] - p->r[rs2]; | |
| return; | |
| } | |
| // SLL | |
| if (funct3 == 0b001) { | |
| if (p->debug) printf("sll %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] << (p->r[rs2] & 0x11111); | |
| return; | |
| } | |
| // SLT | |
| if (funct3 == 0b010) { | |
| if (p->debug) printf("slt %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] < p->r[rs2]; | |
| return; | |
| } | |
| // SLTU | |
| if (funct3 == 0b011) { | |
| if (p->debug) printf("sltu %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = (uint32_t)p->r[rs1] < (uint32_t)p->r[rs2]; | |
| return; | |
| } | |
| // XOR | |
| if (funct3 == 0b100) { | |
| if (p->debug) printf("xor %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] ^ p->r[rs2]; | |
| return; | |
| } | |
| // SRL | |
| if (funct3 == 0b101 && funct7 == 0b0000000) { | |
| if (p->debug) printf("srl %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = (uint32_t)p->r[rs1] >> ((uint32_t)p->r[rs2] & 0x11111); | |
| return; | |
| } | |
| // SRA | |
| if (funct3 == 0b101 && funct7 == 0b0100000) { | |
| if (p->debug) printf("sra %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] >> (p->r[rs2] & 0x11111); | |
| return; | |
| } | |
| // OR | |
| if (funct3 == 0b110) { | |
| if (p->debug) printf("or %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] | p->r[rs2]; | |
| return; | |
| } | |
| // AND | |
| if (funct3 == 0b111) { | |
| if (p->debug) printf("and %s, %s, %s\n", kora_rn[rd], kora_rn[rs1], kora_rn[rs2]); | |
| if (rd != 0) p->r[rd] = p->r[rs1] & p->r[rs2]; | |
| return; | |
| } | |
| } | |
| // IMM | |
| if (opcode == 0b0010011) { | |
| // ADDI | |
| if (funct3 == 0b000) { | |
| if (p->debug) printf("addi %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = p->r[rs1] + i_imm; | |
| return; | |
| } | |
| // SLLI | |
| if (funct3 == 0b001) { | |
| if (p->debug) printf("ssli %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_shamt); | |
| if (rd != 0) p->r[rd] = p->r[rs1] << i_shamt; | |
| return; | |
| } | |
| // SLTI | |
| if (funct3 == 0b010) { | |
| if (p->debug) printf("slti %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = p->r[rs1] < i_imm; | |
| return; | |
| } | |
| // SLTIU | |
| if (funct3 == 0b011) { | |
| if (p->debug) printf("sltiu %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = (uint32_t)p->r[rs1] < (uint32_t)i_imm; | |
| return; | |
| } | |
| // XORI | |
| if (funct3 == 0b100) { | |
| if (p->debug) printf("xori %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = p->r[rs1] ^ i_imm; | |
| return; | |
| } | |
| // SRLI | |
| if (funct3 == 0b101 && funct7 == 0b0000000) { | |
| if (p->debug) printf("srli %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_shamt); | |
| if (rd != 0) p->r[rd] = (uint32_t)p->r[rs1] >> i_shamt; | |
| return; | |
| } | |
| // SRAI | |
| if (funct3 == 0b101 && funct7 == 0b0100000) { | |
| if (p->debug) printf("srai %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_shamt); | |
| if (rd != 0) p->r[rd] = p->r[rs1] >> i_shamt; | |
| return; | |
| } | |
| // ORI | |
| if (funct3 == 0b110) { | |
| if (p->debug) printf("ori %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = p->r[rs1] | i_imm; | |
| return; | |
| } | |
| // ANDI | |
| if (funct3 == 0b111) { | |
| if (p->debug) printf("andi %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = p->r[rs1] & i_imm; | |
| return; | |
| } | |
| } | |
| // LUI | |
| if (opcode == 0b0110111) { | |
| if (p->debug) printf("lui %s, %d\n", kora_rn[rd], u_imm); | |
| if (rd != 0) p->r[rd] = u_imm << 12; | |
| return; | |
| } | |
| // AUIPC | |
| if (opcode == 0b0010111) { | |
| if (p->debug) printf("auipc %s, %d\n", kora_rn[rd], u_imm); | |
| if (rd != 0) p->r[rd] = (p->pc - 4) + (u_imm << 12); | |
| return; | |
| } | |
| // JAL | |
| if (opcode == 0b1101111) { | |
| if (p->debug) printf("jal %s, %d\n", kora_rn[rd], j_imm); | |
| if (rd != 0) p->r[rd] = p->pc; | |
| p->pc += j_imm - 4; | |
| return; | |
| } | |
| // JALR | |
| if (opcode == 0b1100111) { | |
| if (p->debug) printf("jalr %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = p->pc; | |
| p->pc = ((p->r[rs1] + i_imm) & (~ 0b1)) - 4; | |
| return; | |
| } | |
| // Branch | |
| if (opcode == 0b1100011) { | |
| // BEQ | |
| if (funct3 == 0b000) { | |
| if (p->debug) printf("beq %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], b_imm); | |
| if (p->r[rd] == p->r[rs1]) p->pc += b_imm - 4; | |
| return; | |
| } | |
| // BNE | |
| if (funct3 == 0b001) { | |
| if (p->debug) printf("bne %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], b_imm); | |
| if (p->r[rd] != p->r[rs1]) p->pc += b_imm - 4; | |
| return; | |
| } | |
| // BLT | |
| if (funct3 == 0b100) { | |
| if (p->debug) printf("blt %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], b_imm); | |
| if (p->r[rd] < p->r[rs1]) p->pc += b_imm - 4; | |
| return; | |
| } | |
| // BGE | |
| if (funct3 == 0b101) { | |
| if (p->debug) printf("bge %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], b_imm); | |
| if (p->r[rd] >= p->r[rs1]) p->pc += b_imm - 4; | |
| return; | |
| } | |
| // BLTU | |
| if (funct3 == 0b110) { | |
| if (p->debug) printf("bltu %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], b_imm); | |
| if ((uint32_t)p->r[rd] < (uint32_t)p->r[rs1]) p->pc += b_imm - 4; | |
| return; | |
| } | |
| // BGEU | |
| if (funct3 == 0b111) { | |
| if (p->debug) printf("bgeu %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], b_imm); | |
| if ((uint32_t)p->r[rd] >= (uint32_t)p->r[rs1]) p->pc += b_imm - 4; | |
| return; | |
| } | |
| } | |
| // Load | |
| if (opcode == 0b0000011) { | |
| // LB | |
| if (funct3 == 0b000) { | |
| if (p->debug) printf("lb %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = (int8_t)kora_read_byte(p, p->r[rs1] + i_imm); | |
| return; | |
| } | |
| // LH | |
| if (funct3 == 0b001) { | |
| if (p->debug) printf("lh %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = (int16_t)kora_read_half(p, p->r[rs1] + i_imm); | |
| return; | |
| } | |
| // LW | |
| if (funct3 == 0b010) { | |
| if (p->debug) printf("lw %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = kora_read_word(p, p->r[rs1] + i_imm); | |
| return; | |
| } | |
| // LBU | |
| if (funct3 == 0b100) { | |
| if (p->debug) printf("lbu %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = kora_read_byte(p, p->r[rs1] + i_imm); | |
| return; | |
| } | |
| // LHU | |
| if (funct3 == 0b101) { | |
| if (p->debug) printf("lhu %s, %s, %d\n", kora_rn[rd], kora_rn[rs1], i_imm); | |
| if (rd != 0) p->r[rd] = kora_read_half(p, p->r[rs1] + i_imm); | |
| return; | |
| } | |
| } | |
| // Store | |
| if (opcode == 0b0100011) { | |
| // SB | |
| if (funct3 == 0b000) { | |
| if (p->debug) printf("sb %s, %s, %d\n", kora_rn[rs2], kora_rn[rs1], s_imm); | |
| kora_write_byte(p, p->r[rs1] + s_imm, p->r[rs2]); | |
| return; | |
| } | |
| // SH | |
| if (funct3 == 0b001) { | |
| if (p->debug) printf("sh %s, %s, %d\n", kora_rn[rs2], kora_rn[rs1], s_imm); | |
| kora_write_half(p, p->r[rs1] + s_imm, p->r[rs2]); | |
| return; | |
| } | |
| // SW | |
| if (funct3 == 0b010) { | |
| if (p->debug) printf("sw %s, %s, %d\n", kora_rn[rs2], kora_rn[rs1], s_imm); | |
| kora_write_word(p, p->r[rs1] + s_imm, p->r[rs2]); | |
| return; | |
| } | |
| } | |
| // Fench / Misc Mem | |
| if (opcode == 0b0001111) { | |
| if (p->debug) printf("fench skip\n"); | |
| return; | |
| } | |
| // System | |
| if (opcode == 0b1110011) { | |
| // ECALL | |
| if (funct12 == 0b000000000000) { | |
| if (p->debug) printf("ecall\n"); | |
| p->running = false; | |
| p->passed = p->r[10] == 0; | |
| return; | |
| } | |
| if (p->debug) printf("system skip\n"); | |
| return; | |
| } | |
| printf("Unkown instruction: %d\n", opcode); | |
| exit(1); | |
| } | |
| int main(int argc, char **argv) { | |
| printf("Kora RISC-V Processor Tester!\n"); | |
| if (elf_version(EV_CURRENT) == EV_NONE) | |
| printf("ELF library initialization failed: %s", elf_errmsg(-1)); | |
| for (int i = 1; i < argc; i++) { | |
| if (string_ends_with(argv[i], ".dump")) { | |
| continue; | |
| } | |
| printf("Running test: %s\n", argv[i]); | |
| Kora kora; | |
| kora_init(&kora, false); | |
| FILE *file = fopen(argv[i], "rb"); | |
| fseek(file, 0, SEEK_END); | |
| size_t file_size = ftell(file); | |
| fseek(file, 0, SEEK_SET); | |
| uint8_t *file_buffer = malloc(file_size); | |
| fread(file_buffer, 1, file_size, file); | |
| fclose(file); | |
| Elf *elf_file = elf_memory(file_buffer, file_size); | |
| Elf_Scn *section = NULL; | |
| Elf32_Shdr *section_data = NULL; | |
| while ((section = elf_nextscn(elf_file, section)) != NULL) { | |
| section_data = elf32_getshdr(section); | |
| // printf("- Section at %x of %d bytes\n", section_data->sh_addr, section_data->sh_size); | |
| if (section_data->sh_addr != 0) { | |
| Elf_Data *data = NULL; | |
| data = elf_getdata(section, data); | |
| uint8_t *section_buffer = data->d_buf; | |
| for (size_t i = 0; i < section_data->sh_size; i++) { | |
| kora_write_byte(&kora, section_data->sh_addr + i, section_buffer[i]); | |
| } | |
| } | |
| } | |
| elf_end(elf_file); | |
| free(file_buffer); | |
| while (kora.running) { | |
| kora_step(&kora); | |
| } | |
| if (kora.passed) { | |
| printf("Test passed!\n"); | |
| } else { | |
| printf("Test failed!\n"); | |
| exit(1); | |
| } | |
| } | |
| return EXIT_SUCCESS; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment