diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..13db62b --- /dev/null +++ b/README.txt @@ -0,0 +1,16 @@ +RISC-V (rv32i) emulator in C +This is just for me to understand how all this works, and to learn something new. +So don't use it. + +Example programs: +- return.bin: returns -1094647826 (puts it to register 10) + +To compile stuff: +0. Get the toolchain obviously +1. riscv32-unknown-elf-gcc -c -Oz program.c +2. riscv32-unknown-elf-objcopy -O binary program.o program.bin +3. program.bin is the binary file with the program, pass it as an argument + +rv32i, ilp32 compatible toolchain for 64bit Linux: https://lfs.m724.eu/toolchain.tar.zst adaa74f263dcba430da588b1109bc3b90bd90a84c67b06213bd03a7bbacd1a2a +Or just the stuff necessary to make a binary file: https://lfs.m724.eu/toolchainlite.tar.zst 55e79dff7ba4093dedb8151461508fc157525ad89615d49d737845af03d1643f +Those were compiled with `./configure --prefix=$(pwd)/../toolchain --with-arch=rv32i --with-abi=ilp32` and `make` \ No newline at end of file diff --git a/programs/return.bin b/programs/return.bin new file mode 100644 index 0000000..f0b071e Binary files /dev/null and b/programs/return.bin differ diff --git a/remake.sh b/remake.sh new file mode 100755 index 0000000..b45c0e1 --- /dev/null +++ b/remake.sh @@ -0,0 +1,4 @@ +#!/bin/bash +make clean +make +./build/criscv $1 \ No newline at end of file diff --git a/simple.bin b/simple.bin deleted file mode 100644 index 0073af2..0000000 Binary files a/simple.bin and /dev/null differ diff --git a/src/address_space.c b/src/address_space.c index f5678a1..4b71446 100644 --- a/src/address_space.c +++ b/src/address_space.c @@ -60,6 +60,7 @@ int read_address_space(const AddressSpace *addressSpace, const uint32_t address, } else { // TODO IO + return 1; } return 0; @@ -85,6 +86,7 @@ int write_address_space(const AddressSpace *addressSpace, const uint32_t address } } else { // TODO IO + return 1; } return 0; diff --git a/src/instruction_executor.c b/src/instruction_executor.c index e43eb92..eb71330 100644 --- a/src/instruction_executor.c +++ b/src/instruction_executor.c @@ -10,13 +10,15 @@ static void printBinary(int num) { int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { AddressSpace *addressSpace = cpu->addressSpace; - cpu->registers[0] = 0; // x0 is always 0 + uint32_t *registers = cpu->registers; + registers[0] = 0; // x0 is always 0 uint8_t opcode = instruction & 0x7F; uint8_t rd = instruction >> 7 & 0x1F; + printf("\nPC: %d\n", cpu->programCounter); + if (opcode != 0) { - printf("\nPC: %d\n", cpu->programCounter); printf("Instruction: "); printBinary(instruction); printf("\nOpcode: 0x%X (", opcode); @@ -25,6 +27,51 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { printf("Dest. reg.: x%d\n", rd); } + switch (opcode) { + case 0b0010011: { // OP-IMM for Integer Register-Immediate Instructions (I type) + uint8_t funct3 = instruction >> 12 & 0x7; + uint8_t rs1 = instruction >> 15 & 0x1F; + uint32_t imm = (int32_t)instruction >> 20; + + switch (funct3) { + case 0b000: // ADDI + registers[rd] = registers[rs1] + imm; + break; + default: + // TODO other and illegal instruction + break; + } + /* code */ + break; + } + case 0b0110111: { // LUI load upper immediate (U type) + uint32_t imm = instruction & 0xFFFFF000; + registers[rd] = imm; + break; + } + case 0b1100111: { // JALR for unconditional jump and link register (I type) + uint8_t funct3 = instruction >> 12 & 0x7; + + if (funct3 != 0) { + // TODO illegal instruction + } + + uint8_t rs1 = instruction >> 15 & 0x1F; + uint32_t imm = (int32_t)instruction >> 20; + + int result = registers[rs1] + imm; + result &= ~1; // set LSB to 0 + + registers[rd] = cpu->programCounter + 4; + cpu->programCounter = result - 4; // program counter is always incremented after executing instruction + + break; + } + default: + // TODO illegal instruction + break; + } + // TODO return 0; diff --git a/src/main.c b/src/main.c index 8b376d3..7cefdc1 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "program_loader.h" #include "cpu.h" @@ -19,11 +21,68 @@ int main(int argc, char *argv[]) { } CPU cpu = create_cpu(addressSpace); + cpu.registers[1] = addressSpace->romSize + addressSpace->ramSize; // make jumping to x1 end the program - while (cpu_cycle(&cpu) != -1) { - sleep(1); + int code; + while ((code = cpu_cycle(&cpu)) != -1) { + //sleep(1); } - printf("Done"); + + printf("\n Emulator exited with code \033[1m%d\033[0m\n", code); + printf(" Program exited with code \033[1m%d\033[0m\n\n", cpu.registers[10]); + + int cols[8] = {0}; + int total = 0; + + for (int col=0; col<8; col++) { + int len; + for (int row=0; row<4; row++) { + int i = 8 * row + col; + len = snprintf(NULL, 0, "%d: \033[1m0x%X\033[0m (%u)", i, cpu.registers[i], cpu.registers[i]); + if (len > cols[col]) { + cols[col] = len; + } + } + total += len; + } + + printf("+"); + for (int i=0; i<8; i++) { + for (int j=0; j