Add reading instructions (not execute yet)
And other mods
This commit is contained in:
parent
f6b5f0c394
commit
2a5423d504
11 changed files with 123 additions and 38 deletions
41
Makefile
41
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)
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef ADDRESS_SPACE_H
|
||||
#define ADDRESS_SPACE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
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
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef CPU_H
|
||||
#define CPU_H
|
||||
|
||||
#include "address_space.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -10,4 +13,6 @@ struct CPU_s {
|
|||
typedef struct CPU_s CPU;
|
||||
|
||||
CPU create_cpu(AddressSpace *addressSpace);
|
||||
int cycle(CPU *cpu);
|
||||
int cpu_cycle(CPU *cpu);
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
int execute_instruction_on_cpu(CPU *cpu, uint32_t instruction);
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
int load_to_rom(const char filename[], AddressSpace *addressSpace);
|
||||
|
||||
#endif
|
BIN
simple.bin
Normal file
BIN
simple.bin
Normal file
Binary file not shown.
|
@ -1,12 +1,13 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
|
|
|
@ -1,9 +1,31 @@
|
|||
#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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
13
src/main.c
13
src/main.c
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue