comit
All checks were successful
/ deploy (push) Successful in 1m16s

This commit is contained in:
Minecon724 2024-10-24 11:38:13 +02:00
parent 94c4c16727
commit a64b878058
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
7 changed files with 131 additions and 18 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
.vscode/ .vscode/
build/ build/
programs/tests/ programs/tests/
toolchain/

View file

@ -1,4 +1,4 @@
RISC-V (rv32mi) emulator in C \ RISC-V (rv32i + Zicsr) emulator in C \
This is just for me to understand how all this works, and to learn something new. \ This is just for me to understand how all this works, and to learn something new. \
So don't use it. So don't use it.

View file

@ -16,6 +16,9 @@ struct AddressSpace_s {
uint8_t *ram; uint8_t *ram;
// The size of RAM. // The size of RAM.
uint32_t ramSize; uint32_t ramSize;
// The CSRs, size is always 4096 (12 bits)
uint32_t *csr;
}; };
typedef struct AddressSpace_s AddressSpace; typedef struct AddressSpace_s AddressSpace;
@ -23,5 +26,7 @@ typedef struct AddressSpace_s AddressSpace;
AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSize); AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSize);
int read_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *dest); int read_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *dest);
int write_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *src); int write_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *src);
int read_csr(const AddressSpace *addressSpace, const uint16_t address, void *dest);
int write_csr(const AddressSpace *addressSpace, const uint16_t address, void *src);
#endif #endif

BIN
programs/fib.elf Executable file

Binary file not shown.

14
programs/src/fib.c Normal file
View file

@ -0,0 +1,14 @@
unsigned int main() {
int n = 47;
if (n <= 1) return n;
unsigned int prev = 0, curr = 1, next;
for (int i = 2; i <= n; i++) {
next = prev + curr;
prev = curr;
curr = next;
}
return curr;
}

View file

@ -23,6 +23,7 @@ AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSiz
addressSpace->romLocked = false; addressSpace->romLocked = false;
addressSpace->ram = ram; addressSpace->ram = ram;
addressSpace->ramSize = ramSize; addressSpace->ramSize = ramSize;
addressSpace->csr = calloc(4096, 1);
return addressSpace; return addressSpace;
} }
@ -84,3 +85,25 @@ int write_address_space(const AddressSpace *addressSpace, const uint32_t address
return 0; return 0;
} }
int read_csr(const AddressSpace *addressSpace, const uint16_t address, void *dest) {
if (address >= 4096) {
fprintf(stderr, "Trying to read from CSR address 0x%X, which is higher than maximum 0xFFF\n", address);
return 1;
}
memcpy(dest, addressSpace->csr + address, 4);
return 0;
}
int write_csr(const AddressSpace *addressSpace, const uint16_t address, void *dest) {
if (address >= 4096) {
fprintf(stderr, "Trying to write to CSR address 0x%X, which is higher than maximum 0xFFF\n", address);
return 1;
}
memcpy(addressSpace->csr + address, dest, 4);
return 0;
}

View file

@ -238,11 +238,11 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
imm |= ((instruction >> 20) & 0x1) << 11; // imm[11] imm |= ((instruction >> 20) & 0x1) << 11; // imm[11]
imm |= ((instruction >> 21) & 0x3FF) << 1; // imm[10:1] imm |= ((instruction >> 21) & 0x3FF) << 1; // imm[10:1]
printf("JAL: Jumped to 0x%X + %d = 0x%X (inst %u), link x%u", cpu->programCounter, imm, cpu->programCounter, cpu->programCounter / 4, rd);
registers[rd] = cpu->programCounter + 4; registers[rd] = cpu->programCounter + 4;
cpu->programCounter += imm - 4; // program counter is incremented after this, and we have to execute the function we point to cpu->programCounter += imm - 4; // program counter is incremented after this, and we have to execute the function we point to
printf("JAL: Jumped to 0x%X + %d = 0x%X (inst %u), link x%u", registers[rd], imm, cpu->programCounter, cpu->programCounter / 4, rd);
break; break;
} }
case 0b0110011: { // OP for Integer Register-Register Operations (R type) case 0b0110011: { // OP for Integer Register-Register Operations (R type)
@ -279,11 +279,12 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
} }
case 0b1110011: {// SYSTEM (I type) instructions are used to access system functionality that might require privileged access, here only ECALL and EBREAK case 0b1110011: {// SYSTEM (I type) instructions are used to access system functionality that might require privileged access, here only ECALL and EBREAK
uint8_t funct3 = instruction >> 12 & 0x7; uint8_t funct3 = instruction >> 12 & 0x7;
uint32_t rs1 = instruction >> 15 & 0x1F; uint32_t rs1 = instruction >> 15 & 0x1F; // aka uimm. zero extends automatically
uint32_t func12 = instruction >> 20 & 0xFFF; uint32_t func12 = instruction >> 20 & 0xFFF; // aka csr
if (funct3 != 0 || rd != 0 || rs1 != 0) { if (funct3 == 0) {
fprintf(stderr, "For SYSTEM instructions, funct3, rd and rs1 must be 0, but are 0x%X, 0x%X and 0x%X. Zicsr is not supported.", funct3, rd, rs1); if (rd != 0 || rs1 != 0) {
fprintf(stderr, "For ECALL / EBREAK instructions, rd and rs1 must be 0, but are 0x%X and 0x%X.", rd, rs1);
return 2; return 2;
} }
@ -294,10 +295,79 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
printf("--- EBREAK---"); printf("--- EBREAK---");
// TODO do something // TODO do something
} else { } else {
fprintf(stderr, "Invalid SYSTEM func12: 0x%X", func12); fprintf(stderr, "Invalid func12 for environment instructions: 0x%X", func12);
return 2; //return 2;
}
} else if (funct3 == 0b001) { // CSRRW Atomic Read/Write CSR
printf("CSRRW: (0x%X <-> x%u) -> x%u", func12, rs1, rd);
if (rd != 0) {
uint32_t csrValue;
read_csr(addressSpace, func12, &csrValue);
write_csr(addressSpace, func12, registers + rs1);
registers[rd] = csrValue;
} else {
write_csr(addressSpace, func12, registers + rs1);
}
} else if (funct3 == 0b010) { // CSRRS Atomic Read and Set Bits in CSR
printf("CSRRS: (0x%X | x%u) -> x%u", func12, rs1, rd);
uint32_t csrValue;
read_csr(addressSpace, func12, &csrValue);
if (rs1 != 0) {
uint32_t csrValueNew = csrValue | registers[rs1];
write_csr(addressSpace, func12, &csrValueNew);
} }
registers[rd] = csrValue;
} else if (funct3 == 0b011) { // CSRRC Atomic Read and Clear Bits in CSR
printf("CSRRC: (0x%X & ~x%u) -> x%u", func12, rs1, rd);
uint32_t csrValue;
read_csr(addressSpace, func12, &csrValue);
if (rs1 != 0) {
uint32_t csrValueNew = csrValue & ~registers[rs1];
write_csr(addressSpace, func12, &csrValueNew);
}
registers[rd] = csrValue;
} else if (funct3 == 0b101) { // CSRRWI Atomic Read/Write CSR Immediate
printf("CSRRWI: (0x%X <-> 0x%X) -> x%u", func12, rs1, rd);
// since we don't worry about order, we can simplify
if (rd != 0) {
read_csr(addressSpace, func12, registers + rd);
}
write_csr(addressSpace, func12, &rs1); // rs1 is uimm
} else if (funct3 == 0b110) { // CSRRSI Atomic Read and Set Bits in CSR Immediate
printf("CSRRSI: (0x%X | 0x%X) -> x%u", func12, rs1, rd);
read_csr(addressSpace, func12, registers + rd);
if (rs1 != 0) {
uint32_t csrValueNew = registers[rd] | rs1;
write_csr(addressSpace, func12, &csrValueNew);
}
} else if (funct3 == 0b111) { // CSRRCI Atomic Read and Clear Bits in CSR Immediate
printf("CSRRCI: (0x%X & 0x%X) -> x%u", func12, rs1, rd);
read_csr(addressSpace, func12, registers + rd);
if (rs1 != 0) {
uint32_t csrValueNew = registers[rd] & ~rs1;
write_csr(addressSpace, func12, &csrValueNew);
}
}
break;
}
case 0b0001111: { // MISC-MEM
uint8_t funct3 = instruction >> 12 & 0x7;
uint8_t rs1 = instruction >> 15 & 0x1F;
if (funct3 != 0) {
fprintf(stderr, "funct3 in MISC-MEM must be zero, but is 0x%X", funct3);
}
// TODO
break; break;
} }
default: { default: {