something's very wrong idk what
This commit is contained in:
Minecon724 2024-10-17 19:35:00 +02:00
parent c5173df335
commit 86d73692f9
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
5 changed files with 166 additions and 19 deletions

View file

@ -4,6 +4,13 @@ So don't use it.
Example programs: Example programs:
- return.bin: returns -1094647826 (puts it to register 10) - return.bin: returns -1094647826 (puts it to register 10)
- return2.bin: returns a different value with more steps
Emulator exit codes:
- <0 = OK
- 0 = never happens
- 1 - invalid opcode
- 2 - illegal instruction argument (like funct3)
To compile stuff: To compile stuff:
0. Get the toolchain obviously 0. Get the toolchain obviously

BIN
programs/return2.bin Normal file

Binary file not shown.

View file

@ -33,9 +33,9 @@ int cpu_cycle(CPU *cpu) {
return -1; return -1;
} }
execute_instruction_on_cpu(cpu, instruction); int result = execute_instruction_on_cpu(cpu, instruction);
cpu->programCounter += 4; cpu->programCounter += 4;
return 0; return result;
} }

View file

@ -1,5 +1,8 @@
#include "cpu.h" #include "cpu.h"
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#define VERBOSE_LOGGING 0
static void printBinary(int num) { static void printBinary(int num) {
if (num > 1) { if (num > 1) {
@ -8,7 +11,7 @@ static void printBinary(int num) {
printf("%d", num % 2); printf("%d", num % 2);
} }
int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) { // TODO consider making instruction int
AddressSpace *addressSpace = cpu->addressSpace; AddressSpace *addressSpace = cpu->addressSpace;
uint32_t *registers = cpu->registers; uint32_t *registers = cpu->registers;
registers[0] = 0; // x0 is always 0 registers[0] = 0; // x0 is always 0
@ -16,60 +19,191 @@ int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction) {
uint8_t opcode = instruction & 0x7F; uint8_t opcode = instruction & 0x7F;
uint8_t rd = instruction >> 7 & 0x1F; uint8_t rd = instruction >> 7 & 0x1F;
printf("\nPC: %d\n", cpu->programCounter); if (VERBOSE_LOGGING == 1) {
printf("\n\nPC: %d\n", cpu->programCounter);
if (opcode != 0) {
printf("Instruction: "); printf("Instruction: ");
printBinary(instruction); printBinary(instruction);
printf("\nOpcode: 0x%X (", opcode); printf("\nOpcode: 0x%X (", opcode);
printBinary(opcode); printBinary(opcode);
printf(")\n"); printf(")\n");
printf("Dest. reg.: x%d\n", rd); printf("Dest. reg.: x%d\n", rd);
} else {
// TODO perhaps no break between instructions? Would look better but there would be padding to fix
printf("\n\nPC: %d ", cpu->programCounter);
} }
switch (opcode) { switch (opcode) {
case 0b1100011: { // BRANCH instruction (B type)
uint8_t funct3 = instruction >> 12 & 0x7;
uint8_t rs1 = instruction >> 15 & 0x1F;
uint8_t rs2 = instruction >> 20 & 0x1F;
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[0] is implicitly 0
bool branch = false;
if (funct3 == 0b000) { // BEQ
printf("BEQ: x%d %d == x%d %d?", rs1, registers[rs1], rs2, registers[rs2]);
branch = registers[rs1] == registers[rs2];
} else if (funct3 == 0b001) { // BNE
printf("BNE: x%d %d != x%d %d?", rs1, registers[rs1], rs2, registers[rs2]);
branch = registers[rs1] != registers[rs2];
} else if (funct3 == 0b100) { // BLT
printf("BLT: x%d %d < x%d %d?", rs1, registers[rs1], rs2, registers[rs2]);
branch = (int32_t)registers[rs1] < (int32_t)registers[rs2];
} else if (funct3 == 0b101) { // BGE
printf("BGE: x%d %d > x%d %d?", rs1, registers[rs1], rs2, registers[rs2]);
branch = (int32_t)registers[rs1] > (int32_t)registers[rs2];
} else if (funct3 == 0b110) { // BLTU
printf("BLTU: x%d %u < x%d %u?", rs1, registers[rs1], rs2, registers[rs2]);
branch = registers[rs1] < registers[rs2];
} else if (funct3 == 0b111) { // BGEU
printf("BGEU: x%d %u > x%d %u?", rs1, registers[rs1], rs2, registers[rs2]);
branch = registers[rs1] > registers[rs2];
} else {
// TODO illegal instruction
}
if (branch) {
printf(" Yes, branching");
cpu->programCounter += imm - 4; // program counter is always incremented after executing instruction so -4
} else {
printf(" No, not branching");
}
break;
}
case 0b0010011: { // OP-IMM for Integer Register-Immediate Instructions (I type) case 0b0010011: { // OP-IMM for Integer Register-Immediate Instructions (I type)
uint8_t funct3 = instruction >> 12 & 0x7; uint8_t funct3 = instruction >> 12 & 0x7;
uint8_t rs1 = instruction >> 15 & 0x1F; uint8_t rs1 = instruction >> 15 & 0x1F;
uint32_t imm = (int32_t)instruction >> 20; int32_t imm = (int32_t)instruction >> 20;
switch (funct3) { switch (funct3) {
case 0b000: // ADDI case 0b000: // ADDI
printf("ADDI - x%u %d + %d = %d -> x%u", rs1, registers[rs1], imm, registers[rs1] + imm, rd);
registers[rd] = registers[rs1] + imm; registers[rd] = registers[rs1] + imm;
break; break;
default: default:
// TODO other and illegal instruction // TODO proper error handling
fprintf(stderr, "Unrecognized OP-IMM funct3!");
return 2;
break; break;
} }
/* code */ /* code */
break; break;
} }
case 0b0110111: { // LUI load upper immediate (U type) case 0b0110111: { // LUI load upper immediate (U type)
uint32_t imm = instruction & 0xFFFFF000; int32_t imm = instruction & 0xFFFFF000; // no need for cast because no sign extension
registers[rd] = imm; registers[rd] = imm;
printf("LUI - 0x%X (%d) -> x%u", imm, imm, rd);
break; break;
} }
case 0b1100111: { // JALR for unconditional jump and link register (I type) case 0b1100111: { // JALR for unconditional jump and link register (I type)
uint8_t funct3 = instruction >> 12 & 0x7; uint8_t funct3 = instruction >> 12 & 0x7;
uint8_t rs1 = instruction >> 15 & 0x1F;
int32_t imm = (int32_t)instruction >> 20;
if (funct3 != 0) { if (funct3 != 0) {
// TODO illegal instruction // TODO proper error handling
fprintf(stderr, "Invalid JALR funct3! Should always be 0");
return 2;
} }
uint8_t rs1 = instruction >> 15 & 0x1F;
uint32_t imm = (int32_t)instruction >> 20;
int result = registers[rs1] + imm; int result = registers[rs1] + imm;
result &= ~1; // set LSB to 0 result &= ~1; // set LSB to 0
registers[rd] = cpu->programCounter + 4; registers[rd] = cpu->programCounter + 4;
cpu->programCounter = result - 4; // program counter is always incremented after executing instruction cpu->programCounter = result - 4; // program counter is always incremented after executing instruction
printf("JALR - x%u %u + %u = %u", rs1, result - imm, imm, result);
break; break;
} }
default: case 0b0100011: { // STORE instruction (S type)
// TODO illegal instruction uint8_t funct3 = instruction >> 12 & 0x7;
uint8_t rs1 = instruction >> 15 & 0x1F;
uint8_t rs2 = instruction >> 20 & 0x1F;
int32_t imm = ((int32_t)instruction >> 20 & 0xffffffe0) | rd;
uint32_t addr = registers[rs1] + imm;
if (funct3 == 0b000) { // SB
// SB stores an 8-bit value from the low bits of register rs2 to memory.
uint8_t val = registers[rs2] & 0xFF;
write_address_space(addressSpace, addr, 1, &val);
printf("SB: x%d %u -> %u", rs2, val, addr);
} else if (funct3 == 0b001) { // SH
// SH stores a 16-bit value from the low bits of register rs2 to memory.
uint8_t val = registers[rs2] & 0xFFFF;
write_address_space(addressSpace, addr, 2, &val);
printf("SH: x%d %u -> %u", rs2, val, addr);
} else if (funct3 == 0b010) { // SW
// SW stores a 32-bit value from the low bits of register rs2 to memory.
write_address_space(addressSpace, addr, 4, registers + rs2);
printf("SW: x%d %u -> %u", rs2, registers[rs2], addr);
} else {
// TODO illegal funct3
}
break; break;
}
case 0b0000011: { // LOAD instruction (I type)
uint8_t funct3 = instruction >> 12 & 0x7;
uint8_t rs1 = instruction >> 15 & 0x1F;
int32_t imm = (int32_t)instruction >> 20; // sign extends automatically
uint32_t addr = registers[rs1] + imm;
int32_t val;
if (funct3 == 0b000) { // LB
// LB loads an 8-bit value from memory, then sign-extends to 32-bits.
read_address_space(addressSpace, addr, 1, &val);
val >>= 24;
printf("LB (8bit)");
} else if (funct3 == 0b001) { // LH
// LH loads a 16-bit value from memory, then sign-extends to 32-bits.
read_address_space(addressSpace, addr, 2, &val);
val >>= 16;
printf("LH (16bit)");
} else if (funct3 == 0b010) { // LW
// LW instruction loads a 32-bit value from memory into rd.
read_address_space(addressSpace, addr, 4, &val); // TODO we could assign directly
printf("LW (32bit)");
} else if (funct3 == 0b100) { // LBU
// LBU loads an 8-bit value from memory but then zero extends to 32-bits.
read_address_space(addressSpace, addr, 1, &val);
val = (uint32_t)val >> 24; // TODO optimize that perhaps
printf("LBU (8bit)");
} else if (funct3 == 0b101) { // LHU
// LHU loads a 16-bit value from memory but then zero extends to 32-bits.
read_address_space(addressSpace, addr, 2, &val);
val = (uint32_t)val >> 16; // TODO optimize that perhaps
printf("LHU (16bit)");
} else {
// TODO illegal funct3
}
printf(" - 0x%X -> x%u: 0x%X", addr, rd, val);
registers[rd] = val;
break;
}
default: {
// TODO illegal instruction
fprintf(stderr, "Unrecognized opcode!");
return 1;
break;
}
} }
// TODO // TODO

View file

@ -12,7 +12,7 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
AddressSpace *addressSpace = create_address_space(1024, 1024); AddressSpace *addressSpace = create_address_space(256, 256);
printf("Address space: %dB ROM, %dB RAM\n", addressSpace->romSize, addressSpace->ramSize); printf("Address space: %dB ROM, %dB RAM\n", addressSpace->romSize, addressSpace->ramSize);
if (load_to_rom(argv[1], addressSpace) != 0) { if (load_to_rom(argv[1], addressSpace) != 0) {
@ -23,14 +23,20 @@ int main(int argc, char *argv[]) {
CPU cpu = create_cpu(addressSpace); CPU cpu = create_cpu(addressSpace);
cpu.registers[1] = addressSpace->romSize + addressSpace->ramSize; // make jumping to x1 end the program cpu.registers[1] = addressSpace->romSize + addressSpace->ramSize; // make jumping to x1 end the program
printf("\n----- Start of program -----");
int code; int code;
while ((code = cpu_cycle(&cpu)) != -1) { uint32_t cycles = 0;
while ((code = cpu_cycle(&cpu)) == 0) {
cycles++;
//sleep(1); //sleep(1);
} }
printf("\n\n----- End of program -----\n");
printf("\n Emulator exited with code \033[1m%d\033[0m\n", code); printf("\n Emulator exit code: \033[1m%d\033[0m\n", code);
printf(" Program exited with code \033[1m%d\033[0m\n\n", cpu.registers[10]); printf(" Program exit code: \033[1m%d\033[0m (x10)\n", cpu.registers[10]);
printf(" Cycles: \033[1m%u\033[0m\n\n", cycles);
int cols[8] = {0}; int cols[8] = {0};
int total = 0; int total = 0;