parent
94c4c16727
commit
a64b878058
7 changed files with 131 additions and 18 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
.vscode/
|
.vscode/
|
||||||
build/
|
build/
|
||||||
programs/tests/
|
programs/tests/
|
||||||
|
toolchain/
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
BIN
programs/fib.elf
Executable file
Binary file not shown.
14
programs/src/fib.c
Normal file
14
programs/src/fib.c
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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: {
|
||||||
|
|
Loading…
Reference in a new issue