diff --git a/meson.build b/meson.build index 6111661..d62363e 100644 --- a/meson.build +++ b/meson.build @@ -7,6 +7,6 @@ sources = [ 'src/instruction.c' ] -args = ['-Wall', '-Wextra', '-Wpedantic', '-O3'] +args = ['-Wall', '-Wextra', '-Wpedantic', '-O3', '-ggdb', '-fsanitize=address'] executable('emu', sources, c_args: args) \ No newline at end of file diff --git a/src/emu.c b/src/emu.c index d514cc8..e507b3c 100644 --- a/src/emu.c +++ b/src/emu.c @@ -8,6 +8,11 @@ Emulator* initEmulator(uint32_t memorySize) { // zero out registers memset(newEmu->regs, 0, sizeof(newEmu->regs)); + // zero out special regs + newEmu->pc = 0; + newEmu->sp = 0; + newEmu->ihp = 0; + // init memory newEmu->mem = initMemory(memorySize); if (!newEmu->mem) { @@ -16,4 +21,9 @@ Emulator* initEmulator(uint32_t memorySize) { } return newEmu; +} + +void freeEmulator(Emulator* emu) { + freeMemory(emu->mem); + free(emu); } \ No newline at end of file diff --git a/src/emu.h b/src/emu.h index 9d481c5..3e1d04d 100644 --- a/src/emu.h +++ b/src/emu.h @@ -6,22 +6,15 @@ #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; + + uint32_t pc; + uint32_t ihp; + uint32_t sp; } Emulator; // -- FUNCTIONS -- // -Emulator* initEmulator(uint32_t memorySize); \ No newline at end of file +Emulator* initEmulator(uint32_t memorySize); +void freeEmulator(Emulator* emu); \ No newline at end of file diff --git a/src/instruction.c b/src/instruction.c index 705cbf2..8b4330f 100644 --- a/src/instruction.c +++ b/src/instruction.c @@ -1,20 +1,110 @@ #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 +const OperandType INSTRUCTION_OPERAND_TYPES[][3] = { + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_IMM16, OP_NONE}, + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_REG, OP_REG}, + {OP_REG, OP_REG, OP_REG}, + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_REG, OP_REG}, + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_REG, OP_NONE}, + {OP_REG, OP_REG, OP_NONE}, + {OP_NONE, OP_NONE, OP_NONE}, + {OP_REG, OP_REG, OP_REG}, + {OP_NONE, OP_NONE, OP_NONE} +}; + +char* opcodeToCStr(InstructionOpcode opcode) { + switch (opcode) { + case INST_MVI: return "MVI"; + case INST_MOV: return "MOV"; + case INST_ADD: return "ADD"; + case INST_SUB: return "SUB"; + case INST_STORE: return "STORE"; + case INST_LOAD: return "LOAD"; + case INST_OR: return "OR"; + case INST_AND: return "AND"; + case INST_XOR: return "XOR"; + case INST_SHF: return "SHF"; + case INST_JMP: return "JMP"; + case INST_JIZ: return "JIZ"; + case INST_CALL: return "CALL"; + case INST_RET: return "RET"; + case INST_SYS: return "SYS"; + case INST_HLT: return "HLT"; + default: return "FIXME"; + } +} + +char* registerToCStr(Register reg) { + switch (reg) { + case REG_A: return "A"; + case REG_B: return "B"; + case REG_C: return "C"; + case REG_X: return "X"; + case REG_Y: return "Y"; + case REG_Z: return "Z"; + case REG_R: return "R"; + case REG_F: return "F"; + default: return "FIXME"; + } +} + +char* instructionToCStr(Instruction inst) { + + size_t bufferSize = 64; + char* buffer = malloc(bufferSize); + if (!buffer) + return NULL; + buffer[0] = 0; + + int written = 0; + int remaining = bufferSize; + + written += snprintf(buffer + written, remaining, "%s ", opcodeToCStr(inst.opcode)); + remaining = bufferSize - written; + + const OperandType* operandTypes = INSTRUCTION_OPERAND_TYPES[inst.opcode]; + + for (uint8_t opIdx = 0; opIdx < 3; opIdx++) { + switch (operandTypes[opIdx]) { + case OP_REG: + written += snprintf( + buffer + written, + remaining, + "%s", + registerToCStr(inst.operands[opIdx]) + ); + break; + case OP_IMM16: + written += snprintf( + buffer + written, + remaining, + "%d", + inst.immediate + ); + break; + case OP_NONE: + break; + } + + + + + remaining = bufferSize - written; + + if (opIdx == 3 || operandTypes[opIdx+1] == OP_NONE) + break; + else + written += snprintf(buffer + written, remaining, ", "); + + remaining = bufferSize - written; + } + + return buffer; +} \ No newline at end of file diff --git a/src/instruction.h b/src/instruction.h index ea9c401..d36ee5b 100644 --- a/src/instruction.h +++ b/src/instruction.h @@ -1,30 +1,42 @@ #pragma once #include +#include +#include // -- TYPES -- // -typedef enum { +typedef enum : uint8_t { 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 enum { + REG_A, REG_B, REG_C, + + REG_X, REG_Y, REG_Z, + REG_R, + + 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 uint16_t SerializedInst; typedef struct { InstructionOpcode opcode; - uint16_t a; - uint16_t b; - uint16_t c; + uint8_t operands[3]; + uint16_t immediate; // unused for almost all instructions } Instruction; typedef enum { - OP_NONE, OP_IMM4 + OP_NONE, OP_REG, OP_IMM16 } OperandType; -typedef struct { - InstructionOpcode opcode; - OperandType operandTypes[3]; -} InstructionOperands; - // -- CONSTANTS -- // -extern const InstructionOperands INSTRUCTION_OPERAND_TYPES[]; \ No newline at end of file +extern const OperandType INSTRUCTION_OPERAND_TYPES[][3]; + +char* opcodeToCStr(InstructionOpcode opcode); +char* instructionToCStr(Instruction inst); +char* registerToCStr(Register reg); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 82a23eb..91a59b2 100644 --- a/src/main.c +++ b/src/main.c @@ -8,7 +8,10 @@ int main() { return 1; } - free(emu); + Instruction inst = decodeInstruction(emu->mem, &emu->pc); + printf("%s\n", instructionToCStr(inst)); + + freeEmulator(emu); return 0; -} \ No newline at end of file +} diff --git a/src/memory.c b/src/memory.c index 097cf62..57dbfca 100644 --- a/src/memory.c +++ b/src/memory.c @@ -22,3 +22,43 @@ inline uint16_t memoryLoadWord(Memory* m, uint32_t address) { inline void memorySaveWord(Memory* m, uint32_t address, uint16_t value) { ((uint16_t*)m->data)[address] = value; } + +Instruction decodeInstruction(Memory* m, uint32_t* pc) { + SerializedInst serialized = m->data[*pc]; + Instruction outputInst = {}; + + uint8_t opcode = serialized & 0b0000000000001111; // get four lowest bits for the opcode + outputInst.opcode = opcode; + + const OperandType* opTypes = INSTRUCTION_OPERAND_TYPES[opcode]; + + uint8_t offset = 0; + for (uint8_t i = 0; i < 3; i++) { + switch (opTypes[i]) { + case OP_REG: { + // get the data at the current offset, and grab the 4 bits that are there with a bitwise + // "and" operator + outputInst.operands[offset] = (serialized >> (4 * (offset + 1))) & 0b0000000000001111; + offset++; + break; + } + + case OP_IMM16: { // the immediate 16 takes up the space where the next instruction would be + uint16_t nextDataOver = m->data[++*pc]; + outputInst.immediate = nextDataOver; + break; + } + + case OP_NONE: { + break; + } + } + } + + return outputInst; +} + +void freeMemory(Memory* m) { + free(m->data); + free(m); +} \ No newline at end of file diff --git a/src/memory.h b/src/memory.h index 388e419..ab750b8 100644 --- a/src/memory.h +++ b/src/memory.h @@ -17,6 +17,7 @@ typedef struct { // -- FUNCTIONS -- // Memory* initMemory(uint32_t size); +void freeMemory(Memory* m); 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 +Instruction decodeInstruction(Memory* m, uint32_t* pc); \ No newline at end of file