Compare commits

..

2 commits

Author SHA1 Message Date
94c4c16727
code
All checks were successful
/ deploy (push) Successful in 1m22s
2024-10-23 20:53:01 +02:00
b320dfa4cd
Cosmetic changes 2024-10-22 19:00:50 +02:00
6 changed files with 97 additions and 22 deletions

1
.gitignore vendored
View file

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

View file

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

View file

@ -40,11 +40,16 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
return 1;
}
/*uint32_t pretextSize = 0;
uint8_t *pretext;
uint32_t textSize = 0;
uint8_t *text;
uint32_t rodataSize = 0;
uint8_t *rodata;
uint8_t *rodata;*/
uint32_t written = 0;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
if (gelf_getshdr(scn, &shdr) != &shdr) {
@ -54,9 +59,9 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
char *sectionName = elf_strptr(elf, shdrstrndx, shdr.sh_name);
Elf_Data *data = elf_getdata(scn, NULL);
Elf_Data *sectionData = elf_getdata(scn, NULL);
if (data == NULL || data->d_size == 0) {
if (sectionData == NULL || sectionData->d_size == 0) {
fprintf(stderr, "elf_getdata() failed: %s\n", elf_errmsg(-1));
continue;
}
@ -64,19 +69,49 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
if (shdr.sh_type == SHT_RISCV_ATTRIBUTES) {
// TODO this is highly fragile
// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc
char *content = (char *)data->d_buf;
char *content = (char *)sectionData->d_buf;
content += 19; // first 17 chars are subsection headers, and I have to +2 to make strcmp match
if (strcmp(content, "rv32i2p1") == 0) {
warnedArch = 1;
}
} else if (strcmp(sectionName, ".text.init") == 0) {
uint8_t *data = (uint8_t *)sectionData->d_buf;
uint32_t dataLength = sectionData->d_size;
if (written + dataLength > addressSpace->romSize) {
fprintf(stderr, "Section %s has %d bytes, already written %d bytes, and doesn't fit in ROM of capacity %d bytes\n", sectionName, dataLength, written, addressSpace->romSize);
return 1;
}
printf("Copying %d bytes from %s\n", dataLength, sectionName);
memcpy(addressSpace->rom + written, data, dataLength);
written += dataLength;
} else if (strcmp(sectionName, ".text") == 0) {
text = (uint8_t *)data->d_buf;
textSize = data->d_size;
uint8_t *data = (uint8_t *)sectionData->d_buf;
uint32_t dataLength = sectionData->d_size;
if (written + dataLength > addressSpace->romSize) {
fprintf(stderr, "Section %s has %d bytes, already written %d bytes, and doesn't fit in ROM of capacity %d bytes\n", sectionName, dataLength, written, addressSpace->romSize);
return 1;
}
printf("Copying %d bytes from %s\n", dataLength, sectionName);
memcpy(addressSpace->rom + written, data, dataLength);
written += dataLength;
} else if (strcmp(sectionName, ".rodata") == 0) {
rodata = (uint8_t *)data->d_buf;
rodataSize = data->d_size;
uint8_t *data = (uint8_t *)sectionData->d_buf;
uint32_t dataLength = sectionData->d_size;
if (written + dataLength > addressSpace->romSize) {
fprintf(stderr, "Section %s has %d bytes, already written %d bytes, and doesn't fit in ROM of capacity %d bytes\n", sectionName, dataLength, written, addressSpace->romSize);
return 1;
}
printf("Copying %d bytes from %s\n", dataLength, sectionName);
memcpy(addressSpace->rom + written, data, dataLength);
written += dataLength;
} else {
printf("Unrecognized section: %s (%ub)\n", sectionName, (uint32_t)data->d_size);
printf("Unrecognized section: %s (%ub)\n", sectionName, (uint32_t)sectionData->d_size);
}
}
@ -84,6 +119,15 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
printf("I couldn't verify whether the ELF was compiled for the correct instruction set!\n");
}
/*if (pretextSize > 0) {
if (textSize > addressSpace->romSize) {
fprintf(stderr, "Code has %d bytes, and doesn't fit in ROM of capacity %d bytes\n", textSize, addressSpace->romSize);
return 1;
}
memcpy(addressSpace->rom, text, textSize);
}
if (textSize > 0) {
if (textSize > addressSpace->romSize) {
fprintf(stderr, "Code has %d bytes, and doesn't fit in ROM of capacity %d bytes\n", textSize, addressSpace->romSize);
@ -91,7 +135,7 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
}
memcpy(addressSpace->rom, text, textSize);
} else {
} else if (pretextSize == 0) {
fprintf(stderr, "There's no code\n");
return 1;
}
@ -104,11 +148,15 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
}
memcpy(addressSpace->rom + textSize, rodata, rodataSize);
}
}*/
printf("Loaded from ELF | Code: %d bytes (%d insts) | ROdata: %d bytes \n", textSize, textSize / 4, rodataSize);
//printf("Loaded from ELF | Code: %d bytes (%d insts) | ROdata: %d bytes \n", textSize, textSize / 4, rodataSize);
printf("Loaded %d bytes from ELF\n", written);
cpu->programCounter = ehdr.e_entry;
if (cpu->programCounter == 0x80000000) { // TODO not
cpu->programCounter = 0x0;
}
return 0;
}

View file

@ -224,24 +224,25 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
break;
}
case 0b1101111: { // JAL for unconditional jump (J type)
int32_t imm = (int32_t)instruction >> 31;
/*int32_t imm = (int32_t)instruction >> 31;
imm <<= 8;
imm |= instruction >> 12 & 0xFF;
imm <<= 1;
imm |= instruction >> 20 & 0x1;
imm <<= 10;
imm |= instruction >> 21 & 0x3FF;
imm <<= 1;
imm <<= 1;*/
/*int32_t imm = ((int32_t)instruction >> 31) << 20; // Extract imm[20] and sign-extend
imm |= (instruction >> 21) & 0x3FF << 1; // Extract imm[10:1]
imm |= (instruction >> 20) & 0x1 << 11; // Extract imm[11]
imm |= (instruction >> 12) & 0xFF << 12; // Extract imm[19:12]*/
int32_t imm = ((int32_t)instruction >> 31) << 20; // Sign bit
imm |= ((instruction >> 12) & 0xFF) << 12; // imm[19:12]
imm |= ((instruction >> 20) & 0x1) << 11; // imm[11]
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;
cpu->programCounter += imm - 4; // program counter is incremented after this, and we have to execute the function we point to
printf("JAL: Jumped to %u + %d = 0x%X (inst %d)", registers[rd], imm, cpu->programCounter, cpu->programCounter / 4);
break;
}
case 0b0110011: { // OP for Integer Register-Register Operations (R type)
@ -276,6 +277,29 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
break;
}
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;
uint32_t rs1 = instruction >> 15 & 0x1F;
uint32_t func12 = instruction >> 20 & 0xFFF;
if (funct3 != 0 || rd != 0 || rs1 != 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);
return 2;
}
if (func12 == 0) { // ECALL
printf("--- ECALL ---");
// TODO do something
} else if (func12 == 1) { // EBREAK
printf("--- EBREAK---");
// TODO do something
} else {
fprintf(stderr, "Invalid SYSTEM func12: 0x%X", func12);
return 2;
}
break;
}
default: {
// TODO illegal instruction, proper error handling
fprintf(stderr, "Unrecognized opcode: 0x%X", opcode);

View file

@ -14,7 +14,7 @@ int main(int argc, char *argv[]) {
return 1;
}
AddressSpace *addressSpace = create_address_space(512, 512);
AddressSpace *addressSpace = create_address_space(2048, 512);
printf("Address space: %dB ROM, %dB RAM\n", addressSpace->romSize, addressSpace->ramSize);
CPU cpu = create_cpu(addressSpace);

View file

@ -26,6 +26,8 @@ int load_to_rom(const char filename[], AddressSpace *addressSpace) {
return -1;
}
printf("Loading a binary file is deprecated. Please use an ELF.\n");
// size_t is not used because a program can't be larger than the 32bit address space
int romSize = addressSpace->romSize;
int bytesRead = fread(addressSpace->rom, 1, romSize, file);