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
|
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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
BIN
simple.bin
Normal file
Binary file not shown.
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -1,9 +1,31 @@
|
||||||
#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
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
13
src/main.c
13
src/main.c
|
@ -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;
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
Loading…
Reference in a new issue