commit 8e26d3e19d422f7f48fc6bd56f22dc449e97495e Author: SpookyDervish Date: Wed Jul 15 15:02:54 2026 +1000 initial commit diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..6111661 --- /dev/null +++ b/meson.build @@ -0,0 +1,12 @@ +project('MyLittleCPU', 'c') + +sources = [ + 'src/main.c', + 'src/emu.c', + 'src/memory.c', + 'src/instruction.c' +] + +args = ['-Wall', '-Wextra', '-Wpedantic', '-O3'] + +executable('emu', sources, c_args: args) \ No newline at end of file diff --git a/src/emu.c b/src/emu.c new file mode 100644 index 0000000..d514cc8 --- /dev/null +++ b/src/emu.c @@ -0,0 +1,19 @@ +#include "emu.h" + +Emulator* initEmulator(uint32_t memorySize) { + Emulator* newEmu = malloc(sizeof(Emulator)); + if (!newEmu) + return NULL; + + // zero out registers + memset(newEmu->regs, 0, sizeof(newEmu->regs)); + + // init memory + newEmu->mem = initMemory(memorySize); + if (!newEmu->mem) { + free(newEmu); + return NULL; + } + + return newEmu; +} \ No newline at end of file diff --git a/src/emu.h b/src/emu.h new file mode 100644 index 0000000..9d481c5 --- /dev/null +++ b/src/emu.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include "memory.h" + +// -- TYPES -- // +typedef enum { + REG_A, REG_B, REG_C, + + REG_X, REG_Y, REG_Z, + REG_R, + + REG_PC, REG_IHP, REG_SP, REG_F, + + REG_MAX // all registers should come before this one, this is so we can + // automatically know the length of the registers array +} Register; + +typedef struct { + uint16_t regs[REG_MAX]; + Memory* mem; +} Emulator; + +// -- FUNCTIONS -- // +Emulator* initEmulator(uint32_t memorySize); \ No newline at end of file diff --git a/src/instruction.c b/src/instruction.c new file mode 100644 index 0000000..705cbf2 --- /dev/null +++ b/src/instruction.c @@ -0,0 +1,20 @@ +#include "instruction.h" + +const InstructionOperands INSTRUCTION_OPERAND_TYPES[] = { + { INST_MVI, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_MOV, {OP_IMM4, OP_NONE, OP_NONE} }, + { INST_ADD, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_SUB, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_LOAD, {OP_IMM4, OP_IMM4, OP_IMM4} }, + { INST_STORE, {OP_IMM4, OP_IMM4, OP_IMM4} }, + { INST_AND, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_OR, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_XOR, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_SHF, {OP_IMM4, OP_IMM4, OP_IMM4} }, + { INST_JMP, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_JIZ, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_CALL, {OP_IMM4, OP_IMM4, OP_NONE} }, + { INST_RET, {OP_NONE, OP_NONE, OP_NONE} }, + { INST_SYS, {OP_IMM4, OP_IMM4, OP_IMM4} }, + { INST_HLT, {OP_NONE, OP_NONE, OP_NONE} }, +}; \ No newline at end of file diff --git a/src/instruction.h b/src/instruction.h new file mode 100644 index 0000000..ea9c401 --- /dev/null +++ b/src/instruction.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +// -- TYPES -- // +typedef enum { + INST_MOV, INST_MVI, INST_ADD, INST_SUB, INST_LOAD, INST_STORE, INST_AND, INST_OR, + INST_XOR, INST_SHF, INST_JMP, INST_JIZ, INST_CALL, INST_RET, INST_SYS, INST_HLT +} InstructionOpcode; + +typedef uint16_t SerializedInst; + +typedef struct { + InstructionOpcode opcode; + uint16_t a; + uint16_t b; + uint16_t c; +} Instruction; + +typedef enum { + OP_NONE, OP_IMM4 +} OperandType; + +typedef struct { + InstructionOpcode opcode; + OperandType operandTypes[3]; +} InstructionOperands; + +// -- CONSTANTS -- // +extern const InstructionOperands INSTRUCTION_OPERAND_TYPES[]; \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..82a23eb --- /dev/null +++ b/src/main.c @@ -0,0 +1,14 @@ +#include +#include "emu.h" + +int main() { + Emulator* emu = initEmulator(0x00010FFF); + if (!emu) { + fprintf(stderr, "emu: error: failed to allocate memory for emulator\n"); + return 1; + } + + free(emu); + + return 0; +} \ No newline at end of file diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..097cf62 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,24 @@ +#include "memory.h" + +Memory* initMemory(uint32_t size) { + Memory* newMemory = malloc(sizeof(Memory)); + if (!newMemory) + return NULL; + + newMemory->size = size; + newMemory->data = calloc(size, sizeof(uint8_t)); + if (!newMemory->data) { + free(newMemory); + return NULL; + } + + return newMemory; +} + +inline uint16_t memoryLoadWord(Memory* m, uint32_t address) { + return m->data[address]; +} + +inline void memorySaveWord(Memory* m, uint32_t address, uint16_t value) { + ((uint16_t*)m->data)[address] = value; +} diff --git a/src/memory.h b/src/memory.h new file mode 100644 index 0000000..388e419 --- /dev/null +++ b/src/memory.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include "instruction.h" + +#define MEM_CALL_STACK_OFFSET 0x00000FFF +#define MEM_PROGRAM_START 0x00001000 +#define MEM_PROGRAM_END 0x0000FFFF +#define MEM_GP_START 0x00010000 + +// -- TYPES -- // +typedef struct { + uint32_t size; + uint8_t* data; +} Memory; + +// -- FUNCTIONS -- // +Memory* initMemory(uint32_t size); +uint16_t memoryLoadWord(Memory* m, uint32_t address); +void memorySaveWord(Memory* m, uint32_t address, uint16_t value); +Instruction decodeInstruction(Memory* m, uint32_t pc); \ No newline at end of file