From 2a5423d504dc52e9198db1572bb9cc335d6bc619 Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Tue, 15 Oct 2024 17:07:18 +0200 Subject: [PATCH] Add reading instructions (not execute yet) And other mods --- Makefile | 41 +++++++++++++++++++++++++++------ include/address_space.h | 11 ++++++--- include/cpu.h | 7 +++++- include/instruction_executor.h | 7 +++++- include/program_loader.h | 7 +++++- simple.bin | Bin 0 -> 8 bytes src/address_space.c | 41 +++++++++++++++++++++------------ src/cpu.c | 3 ++- src/instruction_executor.c | 24 ++++++++++++++++++- src/main.c | 13 +++++++---- src/program_loader.c | 7 +++--- 11 files changed, 123 insertions(+), 38 deletions(-) create mode 100644 simple.bin diff --git a/Makefile b/Makefile index 8ecd889..cfcc3f9 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,55 @@ +# Compiler to use 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 + +# Name of the output program PROGRAM_NAME := criscv -# Find all .c files in src directory -SRCS := $(wildcard $(SRC_DIR)/*.c) -# Generate corresponding .o file names in obj directory -OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/obj/%.o,$(SRCS)) +# Find all .c files in the source directory +SRCS := $(wildcard src/*.c) + +# Generate corresponding .o file names in the build/obj directory +OBJS := $(patsubst src/%.c,$(BUILD_DIR)/obj/%.o,$(SRCS)) + # Name of the final executable TARGET := $(BUILD_DIR)/$(PROGRAM_NAME) + + +# Declare 'all' and 'clean' as phony targets (not files) .PHONY: all clean +# Default target: build the executable all: $(TARGET) +# Rule to link object files into the final executable $(TARGET): $(OBJS) | $(BUILD_DIR) $(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 $@ +# Create build directories if they don't exist $(BUILD_DIR) $(BUILD_DIR)/obj: mkdir -p $@ +# Clean target: remove the build directory clean: rm -rf $(BUILD_DIR) \ No newline at end of file diff --git a/include/address_space.h b/include/address_space.h index 35ccceb..202211a 100644 --- a/include/address_space.h +++ b/include/address_space.h @@ -1,3 +1,6 @@ +#ifndef ADDRESS_SPACE_H +#define ADDRESS_SPACE_H + #include struct AddressSpace_s { @@ -9,6 +12,8 @@ struct AddressSpace_s { typedef struct AddressSpace_s AddressSpace; -AddressSpace create_address_space(int romSize, int ramSize); -int read_address_space(const AddressSpace *addressSpace, uint32_t address, const int n, void *dest); -int write_address_space(const AddressSpace *addressSpace, uint32_t address, const int n, void *src); \ No newline at end of file +AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSize); +int read_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *dest); +int write_address_space(const AddressSpace *addressSpace, const uint32_t address, const int n, void *src); + +#endif \ No newline at end of file diff --git a/include/cpu.h b/include/cpu.h index 37aa7a0..d1b09e6 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -1,3 +1,6 @@ +#ifndef CPU_H +#define CPU_H + #include "address_space.h" #include @@ -10,4 +13,6 @@ struct CPU_s { typedef struct CPU_s CPU; CPU create_cpu(AddressSpace *addressSpace); -int cycle(CPU *cpu); \ No newline at end of file +int cpu_cycle(CPU *cpu); + +#endif \ No newline at end of file diff --git a/include/instruction_executor.h b/include/instruction_executor.h index 16d39d4..cd0eeb8 100644 --- a/include/instruction_executor.h +++ b/include/instruction_executor.h @@ -1,3 +1,8 @@ +#ifndef INSTRUCTION_EXECUTOR_H +#define INSTRUCTION_EXECUTOR_H + #include "cpu.h" -int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction); \ No newline at end of file +int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction); + +#endif \ No newline at end of file diff --git a/include/program_loader.h b/include/program_loader.h index eb0e43b..939d58a 100644 --- a/include/program_loader.h +++ b/include/program_loader.h @@ -1,3 +1,8 @@ +#ifndef PROGRAM_LOADER_H +#define PROGRAM_LOADER_H + #include "address_space.h" -int load_to_rom(const char filename[], AddressSpace *addressSpace); \ No newline at end of file +int load_to_rom(const char filename[], AddressSpace *addressSpace); + +#endif \ No newline at end of file diff --git a/simple.bin b/simple.bin new file mode 100644 index 0000000000000000000000000000000000000000..0073af2412982e45e58854b057b60307876664ad GIT binary patch literal 8 PcmWe;6<|njU|;|M1U~@~ literal 0 HcmV?d00001 diff --git a/src/address_space.c b/src/address_space.c index f53e760..f5678a1 100644 --- a/src/address_space.c +++ b/src/address_space.c @@ -1,12 +1,13 @@ #include #include #include +#include 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; + uint32_t romSize; // TODO look into making it const // A pointer to a RAM array. The array can vary in length. uint8_t *ram; @@ -17,33 +18,44 @@ struct AddressSpace_s { typedef struct AddressSpace_s AddressSpace; -AddressSpace create_address_space(int romSize, int ramSize) { - uint8_t rom[romSize]; - uint8_t ram[ramSize]; +AddressSpace *create_address_space(const uint32_t romSize, const uint32_t ramSize) { + uint8_t *rom = calloc(romSize, 1); + 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; } -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 ramSize = addressSpace->ramSize; 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 return 1; } else { memcpy(dest, addressSpace->rom + address, n); } } 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); return 1; } else { - address -= romSize; - memcpy(dest, addressSpace->ram + address, n); + memcpy(dest, addressSpace->ram + address - romSize, n); } } else { @@ -53,24 +65,23 @@ int read_address_space(const AddressSpace *addressSpace, uint32_t address, const 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 ramSize = addressSpace->ramSize; 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); return 1; } else { memcpy(addressSpace->rom + address, src, n); } } 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); return 1; } else { - address -= romSize; - memcpy(addressSpace->ram + address, src, n); + memcpy(addressSpace->ram + address - romSize, src, n); } } else { // TODO IO diff --git a/src/cpu.c b/src/cpu.c index cf84db2..d1bd313 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -1,4 +1,5 @@ #include +#include #include "address_space.h" #include "instruction_executor.h" @@ -26,7 +27,7 @@ CPU create_cpu(AddressSpace *addressSpace) { return cpu; } -int cycle(CPU *cpu) { +int cpu_cycle(CPU *cpu) { uint32_t instruction; if (read_address_space(cpu->addressSpace, cpu->programCounter, 4, &instruction) != 0) { return -1; diff --git a/src/instruction_executor.c b/src/instruction_executor.c index cfbb514..e43eb92 100644 --- a/src/instruction_executor.c +++ b/src/instruction_executor.c @@ -1,9 +1,31 @@ #include "cpu.h" +#include + +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) { 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 return 0; -} \ No newline at end of file +} diff --git a/src/main.c b/src/main.c index 9127476..8b376d3 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,5 @@ #include +#include #include "program_loader.h" #include "cpu.h" @@ -9,16 +10,20 @@ int main(int argc, char *argv[]) { return 1; } - AddressSpace addressSpace = create_address_space(1024, 1024); - printf("Address space: %dB ROM, %dB RAM\n", addressSpace.romSize, addressSpace.ramSize); + AddressSpace *addressSpace = create_address_space(1024, 1024); + 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"); return 1; } - CPU cpu = create_cpu(&addressSpace); + CPU cpu = create_cpu(addressSpace); + while (cpu_cycle(&cpu) != -1) { + sleep(1); + } + printf("Done"); return 0; } \ No newline at end of file diff --git a/src/program_loader.c b/src/program_loader.c index 3b16884..d234223 100644 --- a/src/program_loader.c +++ b/src/program_loader.c @@ -10,18 +10,17 @@ int load_to_rom(const char filename[], AddressSpace *addressSpace) { } int romSize = addressSpace->romSize; - uint8_t buffer[romSize]; - fread(buffer, 1, romSize, file); + fread(addressSpace->rom, 1, romSize, file); fseek(file, 0, SEEK_END); int fileLen = ftell(file); 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; } - addressSpace->rom = buffer; + printf("%s has %d bytes or %d instructions\n", filename, fileLen, fileLen / 4); return 0; } \ No newline at end of file