parent
b320dfa4cd
commit
94c4c16727
6 changed files with 89 additions and 16 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
.vscode/
|
.vscode/
|
||||||
build/
|
build/
|
||||||
|
programs/tests/
|
|
@ -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. \
|
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.
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,16 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*uint32_t pretextSize = 0;
|
||||||
|
uint8_t *pretext;
|
||||||
|
|
||||||
uint32_t textSize = 0;
|
uint32_t textSize = 0;
|
||||||
uint8_t *text;
|
uint8_t *text;
|
||||||
|
|
||||||
uint32_t rodataSize = 0;
|
uint32_t rodataSize = 0;
|
||||||
uint8_t *rodata;
|
uint8_t *rodata;*/
|
||||||
|
|
||||||
|
uint32_t written = 0;
|
||||||
|
|
||||||
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||||||
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
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);
|
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));
|
fprintf(stderr, "elf_getdata() failed: %s\n", elf_errmsg(-1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -64,19 +69,49 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
|
||||||
if (shdr.sh_type == SHT_RISCV_ATTRIBUTES) {
|
if (shdr.sh_type == SHT_RISCV_ATTRIBUTES) {
|
||||||
// TODO this is highly fragile
|
// TODO this is highly fragile
|
||||||
// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc
|
// 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
|
content += 19; // first 17 chars are subsection headers, and I have to +2 to make strcmp match
|
||||||
if (strcmp(content, "rv32i2p1") == 0) {
|
if (strcmp(content, "rv32i2p1") == 0) {
|
||||||
warnedArch = 1;
|
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) {
|
} else if (strcmp(sectionName, ".text") == 0) {
|
||||||
text = (uint8_t *)data->d_buf;
|
uint8_t *data = (uint8_t *)sectionData->d_buf;
|
||||||
textSize = data->d_size;
|
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) {
|
} else if (strcmp(sectionName, ".rodata") == 0) {
|
||||||
rodata = (uint8_t *)data->d_buf;
|
uint8_t *data = (uint8_t *)sectionData->d_buf;
|
||||||
rodataSize = data->d_size;
|
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 {
|
} 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");
|
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 > 0) {
|
||||||
if (textSize > addressSpace->romSize) {
|
if (textSize > addressSpace->romSize) {
|
||||||
fprintf(stderr, "Code has %d bytes, and doesn't fit in ROM of capacity %d bytes\n", 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);
|
memcpy(addressSpace->rom, text, textSize);
|
||||||
} else {
|
} else if (pretextSize == 0) {
|
||||||
fprintf(stderr, "There's no code\n");
|
fprintf(stderr, "There's no code\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -104,11 +148,15 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(addressSpace->rom + textSize, rodata, rodataSize);
|
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;
|
cpu->programCounter = ehdr.e_entry;
|
||||||
|
if (cpu->programCounter == 0x80000000) { // TODO not
|
||||||
|
cpu->programCounter = 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,6 +277,29 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
|
||||||
|
|
||||||
break;
|
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: {
|
default: {
|
||||||
// TODO illegal instruction, proper error handling
|
// TODO illegal instruction, proper error handling
|
||||||
fprintf(stderr, "Unrecognized opcode: 0x%X", opcode);
|
fprintf(stderr, "Unrecognized opcode: 0x%X", opcode);
|
||||||
|
|
|
@ -14,7 +14,7 @@ int main(int argc, char *argv[]) {
|
||||||
return 1;
|
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);
|
printf("Address space: %dB ROM, %dB RAM\n", addressSpace->romSize, addressSpace->ramSize);
|
||||||
|
|
||||||
CPU cpu = create_cpu(addressSpace);
|
CPU cpu = create_cpu(addressSpace);
|
||||||
|
@ -23,7 +23,6 @@ int main(int argc, char *argv[]) {
|
||||||
int lres = load_to_rom(argv[1], addressSpace);
|
int lres = load_to_rom(argv[1], addressSpace);
|
||||||
|
|
||||||
if (lres == -1) {
|
if (lres == -1) {
|
||||||
printf("Loading a binary file is deprecated. Please use an ELF.\n");
|
|
||||||
lres = load_elf_to_cpu_and_rom(argv[1], &cpu);
|
lres = load_elf_to_cpu_and_rom(argv[1], &cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ int load_to_rom(const char filename[], AddressSpace *addressSpace) {
|
||||||
return -1;
|
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
|
// size_t is not used because a program can't be larger than the 32bit address space
|
||||||
int romSize = addressSpace->romSize;
|
int romSize = addressSpace->romSize;
|
||||||
int bytesRead = fread(addressSpace->rom, 1, romSize, file);
|
int bytesRead = fread(addressSpace->rom, 1, romSize, file);
|
||||||
|
|
Loading…
Reference in a new issue