Add reading instructions (not execute yet)

And other mods
This commit is contained in:
Minecon724 2024-10-15 17:07:18 +02:00
parent f6b5f0c394
commit 2a5423d504
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
11 changed files with 123 additions and 38 deletions

View file

@ -1,28 +1,55 @@
# Compiler to use
CC := gcc CC := gcc
CFLAGS := -Wall -Wextra -std=gnu23 -I include -O3
SRC_DIR := src # Compiler flags:
# -Wall: Enable all warnings
# -Wextra: Enable extra warnings
# -std=gnu23: Use GNU C23 standard
# -I include: Add 'include' directory to the include path
# -O3: Optimize code (level 3)
# -Wno-unused-variable: Disable warnings for unused variables
ifeq ($(DEBUG),1)
CFLAGS := -Wall -Wextra -std=gnu23 -I include -O0 -g
else
CFLAGS := -Wall -Wextra -std=gnu23 -I include -O3 -Wno-unused-variable
endif
# Directory for build outputs
BUILD_DIR := build BUILD_DIR := build
# Name of the output program
PROGRAM_NAME := criscv PROGRAM_NAME := criscv
# Find all .c files in src directory # Find all .c files in the source directory
SRCS := $(wildcard $(SRC_DIR)/*.c) SRCS := $(wildcard src/*.c)
# Generate corresponding .o file names in obj directory
OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/obj/%.o,$(SRCS)) # Generate corresponding .o file names in the build/obj directory
OBJS := $(patsubst src/%.c,$(BUILD_DIR)/obj/%.o,$(SRCS))
# Name of the final executable # Name of the final executable
TARGET := $(BUILD_DIR)/$(PROGRAM_NAME) TARGET := $(BUILD_DIR)/$(PROGRAM_NAME)
# Declare 'all' and 'clean' as phony targets (not files)
.PHONY: all clean .PHONY: all clean
# Default target: build the executable
all: $(TARGET) all: $(TARGET)
# Rule to link object files into the final executable
$(TARGET): $(OBJS) | $(BUILD_DIR) $(TARGET): $(OBJS) | $(BUILD_DIR)
$(CC) $(CFLAGS) $^ -o $@ $(CC) $(CFLAGS) $^ -o $@
du -b $(TARGET) # Size of the executable in bytes
$(BUILD_DIR)/obj/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR)/obj # Rule to compile source files into object files
$(BUILD_DIR)/obj/%.o: src/%.c | $(BUILD_DIR)/obj
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
# Create build directories if they don't exist
$(BUILD_DIR) $(BUILD_DIR)/obj: $(BUILD_DIR) $(BUILD_DIR)/obj:
mkdir -p $@ mkdir -p $@
# Clean target: remove the build directory
clean: clean:
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)

View file

@ -1,3 +1,6 @@
#ifndef ADDRESS_SPACE_H
#define ADDRESS_SPACE_H
#include <stdint.h> #include <stdint.h>
struct AddressSpace_s { struct AddressSpace_s {
@ -9,6 +12,8 @@ struct AddressSpace_s {
typedef struct AddressSpace_s AddressSpace; typedef struct AddressSpace_s AddressSpace;
AddressSpace create_address_space(int romSize, int ramSize); AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSize);
int read_address_space(const AddressSpace *addressSpace, 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, uint32_t address, const int n, void *src); int write_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *src);
#endif

View file

@ -1,3 +1,6 @@
#ifndef CPU_H
#define CPU_H
#include "address_space.h" #include "address_space.h"
#include <stdint.h> #include <stdint.h>
@ -10,4 +13,6 @@ struct CPU_s {
typedef struct CPU_s CPU; typedef struct CPU_s CPU;
CPU create_cpu(AddressSpace *addressSpace); CPU create_cpu(AddressSpace *addressSpace);
int cycle(CPU *cpu); int cpu_cycle(CPU *cpu);
#endif

View file

@ -1,3 +1,8 @@
#ifndef INSTRUCTION_EXECUTOR_H
#define INSTRUCTION_EXECUTOR_H
#include "cpu.h" #include "cpu.h"
int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction); int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction);
#endif

View file

@ -1,3 +1,8 @@
#ifndef PROGRAM_LOADER_H
#define PROGRAM_LOADER_H
#include "address_space.h" #include "address_space.h"
int load_to_rom(const char filename[], AddressSpace *addressSpace); int load_to_rom(const char filename[], AddressSpace *addressSpace);
#endif

BIN
simple.bin Normal file

Binary file not shown.

View file

@ -1,12 +1,13 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
struct AddressSpace_s { struct AddressSpace_s {
// A pointer to a ROM array. The array can vary in length. // A pointer to a ROM array. The array can vary in length.
uint8_t *rom; uint8_t *rom;
// The size of ROM. // The size of ROM.
uint32_t romSize; uint32_t romSize; // TODO look into making it const
// A pointer to a RAM array. The array can vary in length. // A pointer to a RAM array. The array can vary in length.
uint8_t *ram; uint8_t *ram;
@ -17,33 +18,44 @@ struct AddressSpace_s {
typedef struct AddressSpace_s AddressSpace; typedef struct AddressSpace_s AddressSpace;
AddressSpace create_address_space(int romSize, int ramSize) { AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSize) {
uint8_t rom[romSize]; uint8_t *rom = calloc(romSize, 1);
uint8_t ram[ramSize]; uint8_t *ram = calloc(ramSize, 1);
AddressSpace *addressSpace = malloc(sizeof(AddressSpace));
AddressSpace addressSpace = { rom, romSize, ram, ramSize }; if (rom == NULL || ram == NULL || addressSpace == NULL) {
free(rom);
free(ram);
free(addressSpace);
return NULL; // Memory allocation failed
}
addressSpace->rom = rom;
addressSpace->romSize = romSize;
addressSpace->ram = ram;
addressSpace->ramSize = ramSize;
return addressSpace; return addressSpace;
} }
int read_address_space(const AddressSpace *addressSpace, uint32_t address, const int n, void *dest) { int read_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *dest) {
uint32_t romSize = addressSpace->romSize; uint32_t romSize = addressSpace->romSize;
uint32_t ramSize = addressSpace->ramSize; uint32_t ramSize = addressSpace->ramSize;
if (address < romSize) { if (address < romSize) {
if (address + n < romSize) { if (address + n >= romSize) {
fprintf(stderr, "Reading %d bytes from %d will exceed ROM address space of %d\n", n, address, romSize); // TODO maybe move to perror fprintf(stderr, "Reading %d bytes from %d will exceed ROM address space of %d\n", n, address, romSize); // TODO maybe move to perror
return 1; return 1;
} else { } else {
memcpy(dest, addressSpace->rom + address, n); memcpy(dest, addressSpace->rom + address, n);
} }
} else if (address < romSize + ramSize) { } else if (address < romSize + ramSize) {
if (address + n < romSize + ramSize) { if (address + n >= romSize + ramSize) {
fprintf(stderr, "Reading %d bytes from %d (total %d) will exceed RAM address space of %d (total %d)\n", n, address, address + romSize, ramSize, romSize + ramSize); fprintf(stderr, "Reading %d bytes from %d (total %d) will exceed RAM address space of %d (total %d)\n", n, address, address + romSize, ramSize, romSize + ramSize);
return 1; return 1;
} else { } else {
address -= romSize; memcpy(dest, addressSpace->ram + address - romSize, n);
memcpy(dest, addressSpace->ram + address, n);
} }
} else { } else {
@ -53,24 +65,23 @@ int read_address_space(const AddressSpace *addressSpace, uint32_t address, const
return 0; return 0;
} }
int write_address_space(const AddressSpace *addressSpace, uint32_t address, const int n, void *src) { int write_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *src) {
uint32_t romSize = addressSpace->romSize; uint32_t romSize = addressSpace->romSize;
uint32_t ramSize = addressSpace->ramSize; uint32_t ramSize = addressSpace->ramSize;
if (address < romSize) { if (address < romSize) {
if (address + n < romSize) { if (address + n >= romSize) {
fprintf(stderr, "Writing %d bytes to %d will exceed ROM address space of %d\n", n, address, romSize); fprintf(stderr, "Writing %d bytes to %d will exceed ROM address space of %d\n", n, address, romSize);
return 1; return 1;
} else { } else {
memcpy(addressSpace->rom + address, src, n); memcpy(addressSpace->rom + address, src, n);
} }
} else if (address < romSize + ramSize) { } else if (address < romSize + ramSize) {
if (address + n < romSize + ramSize) { if (address + n >= romSize + ramSize) {
fprintf(stderr, "Writing %d bytes to %d (total %d) will exceed RAM address space of %d (total %d)\n", n, address, address + romSize, ramSize, romSize + ramSize); fprintf(stderr, "Writing %d bytes to %d (total %d) will exceed RAM address space of %d (total %d)\n", n, address, address + romSize, ramSize, romSize + ramSize);
return 1; return 1;
} else { } else {
address -= romSize; memcpy(addressSpace->ram + address - romSize, src, n);
memcpy(addressSpace->ram + address, src, n);
} }
} else { } else {
// TODO IO // TODO IO

View file

@ -1,4 +1,5 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include "address_space.h" #include "address_space.h"
#include "instruction_executor.h" #include "instruction_executor.h"
@ -26,7 +27,7 @@ CPU create_cpu(AddressSpace *addressSpace) {
return cpu; return cpu;
} }
int cycle(CPU *cpu) { int cpu_cycle(CPU *cpu) {
uint32_t instruction; uint32_t instruction;
if (read_address_space(cpu->addressSpace, cpu->programCounter, 4, &instruction) != 0) { if (read_address_space(cpu->addressSpace, cpu->programCounter, 4, &instruction) != 0) {
return -1; return -1;

View file

@ -1,7 +1,29 @@
#include "cpu.h" #include "cpu.h"
#include <stdio.h>
static void printBinary(int num) {
if (num > 1) {
printBinary(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) {
AddressSpace *addressSpace = cpu->addressSpace; AddressSpace *addressSpace = cpu->addressSpace;
cpu->registers[0] = 0; // x0 is always 0
uint8_t opcode = instruction & 0x7F;
uint8_t rd = instruction >> 7 & 0x1F;
if (opcode != 0) {
printf("\nPC: %d\n", cpu->programCounter);
printf("Instruction: ");
printBinary(instruction);
printf("\nOpcode: 0x%X (", opcode);
printBinary(opcode);
printf(")\n");
printf("Dest. reg.: x%d\n", rd);
}
// TODO // TODO

View file

@ -1,4 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include "program_loader.h" #include "program_loader.h"
#include "cpu.h" #include "cpu.h"
@ -9,16 +10,20 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
AddressSpace addressSpace = create_address_space(1024, 1024); AddressSpace *addressSpace = create_address_space(1024, 1024);
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) {
fprintf(stderr, "Error loading program\n"); fprintf(stderr, "Error loading program\n");
return 1; return 1;
} }
CPU cpu = create_cpu(&addressSpace); CPU cpu = create_cpu(addressSpace);
while (cpu_cycle(&cpu) != -1) {
sleep(1);
}
printf("Done");
return 0; return 0;
} }

View file

@ -10,18 +10,17 @@ int load_to_rom(const char filename[], AddressSpace *addressSpace) {
} }
int romSize = addressSpace->romSize; int romSize = addressSpace->romSize;
uint8_t buffer[romSize]; fread(addressSpace->rom, 1, romSize, file);
fread(buffer, 1, romSize, file);
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
int fileLen = ftell(file); int fileLen = ftell(file);
if (fileLen > romSize) { if (fileLen > romSize) {
fprintf(stderr, "File has %d bytes, and won't fit in ROM of capacity %d bytes\n", fileLen, romSize); fprintf(stderr, "File has %d bytes, and doesn't fit in ROM of capacity %d bytes\n", fileLen, romSize);
return 1; return 1;
} }
addressSpace->rom = buffer; printf("%s has %d bytes or %d instructions\n", filename, fileLen, fileLen / 4);
return 0; return 0;
} }