work
Some checks failed
/ deploy (push) Has been cancelled

This commit is contained in:
Minecon724 2024-10-21 19:42:27 +02:00
parent 0e9a116bad
commit d9bd57f984
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
9 changed files with 103 additions and 38 deletions

View file

@ -11,6 +11,7 @@ Emulator exit codes:
- `0` - never happens
- `1` - invalid opcode
- `2` - illegal instruction argument (like funct3)
- `3` - memory error (for example writing to ROM)
Compile:
1. Dependencies: `libelf`

View file

@ -2,11 +2,19 @@
#define ADDRESS_SPACE_H
#include <stdint.h>
#include <stdbool.h>
struct AddressSpace_s {
// A pointer to a ROM array. The array can vary in length.
uint8_t *rom;
uint32_t romSize;
// The size of ROM.
uint32_t romSize; // TODO look into making it const
// Is ROM read only
bool romLocked;
// A pointer to a RAM array. The array can vary in length.
uint8_t *ram;
// The size of RAM.
uint32_t ramSize;
};

BIN
programs/segfault.elf Executable file

Binary file not shown.

15
programs/src/segfault.c Normal file
View file

@ -0,0 +1,15 @@
/**
* This normally causes a segfault, but won't on the emulator because it requires a strict check.
* The emulator emulates bare metal, where there's no such checks.
*/
int main() {
int *i = (int*)1;
*i = 10;
for (int j = 0; j < 100; j++) {
*(i + j) = j;
}
return i;
}

View file

@ -3,20 +3,7 @@
#include <string.h>
#include <stdlib.h>
struct AddressSpace_s {
// A pointer to a ROM array. The array can vary in length.
uint8_t *rom;
// The size of ROM.
uint32_t romSize; // TODO look into making it const
// A pointer to a RAM array. The array can vary in length.
uint8_t *ram;
// The size of RAM.
uint32_t ramSize;
};
typedef struct AddressSpace_s AddressSpace;
#include "address_space.h"
AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSize) {
uint8_t *rom = calloc(romSize, 1);
@ -33,6 +20,7 @@ AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSiz
addressSpace->rom = rom;
addressSpace->romSize = romSize;
addressSpace->romLocked = false;
addressSpace->ram = ram;
addressSpace->ramSize = ramSize;
@ -71,6 +59,11 @@ int write_address_space(const AddressSpace *addressSpace, const uint32_t address
uint32_t ramSize = addressSpace->ramSize;
if (address < romSize) {
if (addressSpace->romLocked) {
fprintf(stderr, "Cannot write to ROM\n");
return 2;
}
if (address + n >= romSize) {
fprintf(stderr, "Writing %d bytes to %d will exceed ROM address space of %d\n", n, address, romSize);
return 1;

View file

@ -69,8 +69,7 @@ void print_registers(CPU *cpu) {
for (int rown=0; rown<rows; rown++) {
printf("");
for (int coln=0; coln<columns; coln++) {
//printf("%d", colSize[coln]);
char *entry = malloc(colSize[coln]);
char entry[50] = {0};
int len = snprintf(entry, colSize[coln]+1, "x%d: \033[1m0x%X\033[0m (%u)", i, registers[i], registers[i]);
memset(entry + len, ' ', colSize[coln] - len);

View file

@ -40,6 +40,12 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
return 1;
}
uint32_t textSize = 0;
uint8_t *text;
uint32_t rodataSize = 0;
uint8_t *rodata;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
if (gelf_getshdr(scn, &shdr) != &shdr) {
fprintf(stderr, "getshdr() failed: %s\n", elf_errmsg(-1));
@ -73,17 +79,18 @@ static inline int process_elf(Elf *elf, CPU *cpu) {
continue;
}
char *content = (char *)data->d_buf;
uint32_t contentSize = data->d_size;
if (contentSize > addressSpace->romSize) {
fprintf(stderr, "Code has %d bytes, and doesn't fit in ROM of capacity %d bytes\n", contentSize, addressSpace->romSize);
return 1;
text = (uint8_t *)data->d_buf;
textSize = data->d_size;
} else if (strcmp(sectionName, ".rodata") == 0) {
Elf_Data *data = elf_getdata(scn, NULL);
if (data == NULL || data->d_size == 0) {
fprintf(stderr, "elf_getdata() failed: %s\n", elf_errmsg(-1));
continue;
}
memcpy(addressSpace->rom, content, contentSize);
printf("Loaded %d bytes or %d instructions from an ELF file\n", contentSize, contentSize / 4);
rodata = (uint8_t *)data->d_buf;
rodataSize = data->d_size;
} else {
printf("Unrecognized section: %s\n", sectionName);
}
@ -93,6 +100,30 @@ 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 (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);
return 1;
}
memcpy(addressSpace->rom, text, textSize);
} else {
fprintf(stderr, "There's no code\n");
return 1;
}
if (rodataSize > 0) {
uint32_t totalSize = rodataSize + textSize;
if (totalSize > addressSpace->romSize) {
fprintf(stderr, "Code %d + rodata %d = %d bytes, which doesn't fit in ROM of capacity %d bytes\n", textSize, rodataSize, totalSize, addressSpace->romSize);
return 1;
}
memcpy(addressSpace->rom + textSize, rodata, rodataSize);
}
printf("Loaded from ELF | Code: %d bytes (%d insts) | ROdata: %d bytes \n", textSize, textSize / 4, rodataSize);
cpu->programCounter = ehdr.e_entry;
return 0;

View file

@ -2,7 +2,7 @@
#include <stdio.h>
#include <stdbool.h>
#define VERBOSE_LOGGING 0
#define VERBOSE_LOGGING 1
static void printBinary(uint32_t num) {
if (num > 1) {
@ -40,8 +40,8 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
int32_t imm = ((int32_t)instruction >> 31) << 12; // imm[12] and sign extension
imm |= ((instruction >> 7) & 0x1) << 11; // imm[11]
imm |= ((instruction >> 25) & 0x3f) << 5; // imm[10:5]
imm |= ((instruction >> 8) & 0xf) << 1; // imm[4:1]
imm |= ((instruction >> 25) & 0x3F) << 5; // imm[10:5]
imm |= ((instruction >> 8) & 0xF) << 1; // imm[4:1]
// imm[0] is implicitly 0
bool branch = false;
@ -69,10 +69,10 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
}
if (branch) {
printf(" Yes, branching");
printf(" Yes, branching by 0x%X to 0x%X", imm, cpu->programCounter + imm);
cpu->programCounter += imm - 4; // program counter is always incremented after executing instruction so -4
} else {
printf(" No, not branching");
printf(" No, not branching by 0x%X to 0x%X", imm, cpu->programCounter + imm);
}
break;
}
@ -82,15 +82,29 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
int32_t imm = (int32_t)instruction >> 20;
switch (funct3) {
case 0b000: // ADDI
printf("ADDI - x%u 0x%X (%d) + 0x%X (%d) = 0x%X -> x%u", rs1, registers[rs1], registers[rs1], imm, imm, registers[rs1] + imm, rd);
case 0b000: {
// ADDI
printf("ADDI: x%u 0x%X (%d) + 0x%X (%d) = 0x%X -> x%u", rs1, registers[rs1], registers[rs1], imm, imm, registers[rs1] + imm, rd);
registers[rd] = registers[rs1] + imm;
break;
default:
}
case 0b001: { // SLLI
uint8_t shamt = imm & 0x1F;
imm = imm >> 5 & 0x3F;
if (imm != 0b0000000) {
fprintf(stderr, "Invalid SLLI imm[11:5], must be zero but is 0x%X", (imm >> 5 & 0x3F));
return 2;
}
printf("SLLI: x%u 0x%X (%d) << %d = 0x%X -> x%u", rs1, registers[rs1], registers[rs1], imm, registers[rs1] << shamt, rd);
registers[rd] = registers[rs1] << shamt;
break;
}
default: {
// TODO proper error handling
fprintf(stderr, "Invalid OP-IMM funct3: 0x%X", funct3);
return 2;
break;
}
}
/* code */
break;
@ -119,11 +133,11 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
registers[rd] = cpu->programCounter + 4;
cpu->programCounter = result - 4; // program counter is always incremented after executing instruction
printf("JALR - x%u %u + %u = %u", rs1, result - imm, imm, result);
printf("JALR - x%u %u + %u = 0x%X", rs1, result - imm, imm, result);
break;
}
case 0b0100011: { // STORE instruction (S type)
case 0b0100011: { // STORE instruction (S type), write errors are ignored
uint8_t funct3 = instruction >> 12 & 0x7;
uint8_t rs1 = instruction >> 15 & 0x1F;
uint8_t rs2 = instruction >> 20 & 0x1F;
@ -152,6 +166,7 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
fprintf(stderr, "Invalid STORE funct3: 0x%X", funct3);
return 2;
}
break;
}
case 0b0000011: { // LOAD instruction (I type)
@ -218,7 +233,7 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO conside
registers[rd] = cpu->programCounter; // program counter is always incremented after executing instruction
cpu->programCounter += imm;
printf("JAL: Jumped to %u + %d = %u (inst %d)", registers[rd], imm, cpu->programCounter, cpu->programCounter / 4);
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)

View file

@ -14,7 +14,7 @@ int main(int argc, char *argv[]) {
return 1;
}
AddressSpace *addressSpace = create_address_space(256, 256);
AddressSpace *addressSpace = create_address_space(512, 512);
printf("Address space: %dB ROM, %dB RAM\n", addressSpace->romSize, addressSpace->ramSize);
CPU cpu = create_cpu(addressSpace);
@ -31,6 +31,8 @@ int main(int argc, char *argv[]) {
return 1;
}
addressSpace->romLocked = true;
printf("\n----- Start of program (0x%X) -----", cpu.programCounter);
@ -47,6 +49,7 @@ int main(int argc, char *argv[]) {
printf(" Program exit code: \033[1m%d\033[0m (x10)\n", cpu.registers[10]);
printf(" Cycles: \033[1m%u\033[0m\n\n", cycles);
cpu.registers[0] = 0; // if x0 is changed in the last instruction (it usually is) it will be displayed what if was set to
print_registers(&cpu);
return 0;