From b58b5adf65162b451a2a4bd922b6e22a437047b0 Mon Sep 17 00:00:00 2001 From: SpookyDervish Date: Thu, 16 Jul 2026 18:28:55 +1000 Subject: [PATCH] start work on interrupts --- src/emu.c | 102 +++++++++++++++++++++++++++++++--------------- src/emu.h | 8 +++- src/instruction.c | 4 +- src/instruction.h | 2 + 4 files changed, 79 insertions(+), 37 deletions(-) diff --git a/src/emu.c b/src/emu.c index 7dece4e..fd3b65c 100644 --- a/src/emu.c +++ b/src/emu.c @@ -26,6 +26,39 @@ static inline void updateDevices(Emulator* emu) { } } +static inline void pushProgramCounter(Emulator* emu) { + ((uint32_t*)emu->mem->data)[emu->sp--] = emu->pc; +} + +void handleInterrupt(Emulator* emu) { + FlagsRegister flags = (FlagsRegister)emu->regs[REG_F]; + if (!flags.fields.interrupts) return; + + InterruptHandlerTable interruptTable = *((InterruptHandlerTable*)&emu->mem->data[emu->iht]); + + pushProgramCounter(emu); + + emu->pc = interruptTable.interruptHandlers[emu->irq-1]; + emu->irq = 0; +} + +uint32_t getRegister(Emulator* emu, uint8_t reg) { + if (reg == REG_IHT_OFFSET) { + return emu->iht; + } + + return emu->regs[reg]; +} + +void setRegister(Emulator* emu, uint8_t reg, uint32_t value) { + if (reg == REG_IHT_OFFSET) { + emu->iht = value; + return; + } + + emu->regs[reg] = value; +} + void startEmulator(Emulator* emu) { static void* dispatchTable[] = { &&MOV, @@ -49,93 +82,96 @@ void startEmulator(Emulator* emu) { emu->halted = false; Instruction inst; - #define DISPATCH() updateDevices(emu); \ + #define DISPATCH() if (emu->irq != 0) handleInterrupt(emu); \ + updateDevices(emu); \ inst = fetchInst(emu); \ goto *dispatchTable[inst.opcode] DISPATCH(); MOV: { - emu->regs[inst.operands[0]] = emu->regs[inst.operands[1]]; + setRegister(emu, inst.operands[0], getRegister(emu, inst.operands[1])); DISPATCH(); } MVI: { - emu->regs[inst.operands[0]] = inst.immediate; + setRegister(emu, inst.operands[0], inst.immediate); DISPATCH(); } ADD: { - int32_t result = emu->regs[inst.operands[0]] + emu->regs[inst.operands[1]]; + int32_t result = getRegister(emu, inst.operands[0]) + getRegister(emu, inst.operands[1]); updateFlagsRegister(emu, result); - emu->regs[inst.operands[0]] = result; + setRegister(emu, inst.operands[0], result); DISPATCH(); } SUB: { - int32_t result = emu->regs[inst.operands[0]] - emu->regs[inst.operands[1]]; + int32_t result = getRegister(emu, inst.operands[0]) - getRegister(emu, inst.operands[1]); updateFlagsRegister(emu, result); - emu->regs[inst.operands[0]] = result; + setRegister(emu, inst.operands[0], result); DISPATCH(); } LOAD: { uint32_t addr = getAddress( - emu->regs[inst.operands[1]], - emu->regs[inst.operands[2]] + getRegister(emu, inst.operands[1]), + getRegister(emu, inst.operands[2]) ); - emu->regs[inst.operands[0]] = memoryLoadWord(emu->mem, addr); + setRegister(emu, inst.operands[0], memoryLoadWord(emu->mem, addr)); DISPATCH(); } STORE: { uint32_t addr = getAddress( - emu->regs[inst.operands[0]], - emu->regs[inst.operands[1]] + getRegister(emu, inst.operands[1]), + getRegister(emu, inst.operands[2]) ); - memorySaveWord(emu->mem, addr, inst.operands[2]); + + memorySaveWord(emu->mem, addr, getRegister(emu, inst.operands[2])); DISPATCH(); } AND: { - int32_t result = emu->regs[inst.operands[0]] & emu->regs[inst.operands[1]]; + int32_t result = getRegister(emu, inst.operands[0]) & getRegister(emu, inst.operands[1]); updateFlagsRegister(emu, result); - emu->regs[inst.operands[0]] = result; + setRegister(emu, inst.operands[0], result); DISPATCH(); } OR: { - int32_t result = emu->regs[inst.operands[0]] | emu->regs[inst.operands[1]]; + int32_t result = getRegister(emu, inst.operands[0]) | getRegister(emu, inst.operands[1]); updateFlagsRegister(emu, result); - emu->regs[inst.operands[0]] = result; + setRegister(emu, inst.operands[0], result); DISPATCH(); } XOR: { - int32_t result = emu->regs[inst.operands[0]] ^ emu->regs[inst.operands[1]]; + int32_t result = getRegister(emu, inst.operands[0]) ^ getRegister(emu, inst.operands[1]); updateFlagsRegister(emu, result); - emu->regs[inst.operands[0]] = result; + setRegister(emu, inst.operands[0], result); DISPATCH(); } SHF: { int32_t result; - if (inst.operands[2] == 0) - result = emu->regs[inst.operands[0]] << emu->regs[inst.operands[1]]; + + if (inst.operands[0] == 0) + result = getRegister(emu, inst.operands[0]) << getRegister(emu, inst.operands[1]); else - result = emu->regs[inst.operands[0]] >> emu->regs[inst.operands[1]]; + result = getRegister(emu, inst.operands[0]) >> getRegister(emu, inst.operands[1]); updateFlagsRegister(emu, result); - emu->regs[inst.operands[0]] = result; + setRegister(emu, inst.operands[0], result); DISPATCH(); } JMP: { - emu->pc = getAddress(inst.operands[0], inst.operands[1]); + emu->pc = inst.immediate; DISPATCH(); } JIZ: { - if (emu->regs[REG_F] & FLAG_ZERO) - emu->pc = getAddress(inst.operands[0], inst.operands[1]); + if (((FlagsRegister)emu->regs[REG_F]).fields.zero) + emu->pc = inst.immediate; DISPATCH(); } CALL: { // save the pc at the current sp and decrement the sp (stack grows downward) - ((uint32_t*)emu->mem->data)[emu->sp--] = emu->pc; + pushProgramCounter(emu); // jump to given addr - emu->pc = getAddress(inst.operands[0], inst.operands[1]); + emu->pc = inst.immediate; DISPATCH(); } @@ -145,7 +181,7 @@ void startEmulator(Emulator* emu) { DISPATCH(); } PORT: { - uint16_t port = emu->regs[inst.operands[0]]; + uint16_t port = getRegister(emu, inst.operands[0]); if (port >= MAX_DEVICES) { DISPATCH(); } @@ -158,7 +194,7 @@ void startEmulator(Emulator* emu) { } if (direction == 0) { - uint16_t value = emu->regs[inst.operands[1]]; + uint16_t value = getRegister(emu, inst.operands[1]); if (device->inPos == DEVICE_BUFFER_LENGTH) { DISPATCH(); @@ -168,11 +204,11 @@ void startEmulator(Emulator* emu) { device->inPos++; } else { if (device->outPos == 0) { - emu->regs[inst.operands[1]] = 0; + setRegister(emu, inst.operands[1], 0); DISPATCH(); } - emu->regs[inst.operands[1]] = device->out[device->outPos-1]; + setRegister(emu, inst.operands[1], device->out[device->outPos-1]); if (device->outPos > 0) device->outPos--; } @@ -196,7 +232,7 @@ Emulator* initEmulator(uint32_t memorySize) { // zero out special regs newEmu->pc = MEM_PROGRAM_START; newEmu->sp = 0; - newEmu->ihp = 0; + newEmu->iht = 0; // init memory newEmu->mem = initMemory(memorySize); diff --git a/src/emu.h b/src/emu.h index b9d3508..a0cd7c3 100644 --- a/src/emu.h +++ b/src/emu.h @@ -21,13 +21,17 @@ typedef struct { Device* devices[MAX_DEVICES]; uint32_t pc; - uint32_t ihp; + uint32_t iht; uint32_t sp; - bool irq; + uint16_t irq; bool halted; } Emulator; +typedef struct { + uint32_t interruptHandlers[32]; +} __attribute__((packed)) InterruptHandlerTable; + typedef union { struct { uint16_t zero : 1; diff --git a/src/instruction.c b/src/instruction.c index 08eb147..0fd4c51 100644 --- a/src/instruction.c +++ b/src/instruction.c @@ -11,8 +11,8 @@ const OperandType INSTRUCTION_OPERAND_TYPES[][3] = { {OP_REG, OP_REG, OP_NONE}, // OR {OP_REG, OP_REG, OP_NONE}, // XOR {OP_REG, OP_REG, OP_REG}, // SHF - {OP_REG, OP_REG, OP_NONE}, // JMP - {OP_REG, OP_REG, OP_NONE}, // JIZ + {OP_IMM16, OP_NONE, OP_NONE}, // JMP + {OP_IMM16, OP_NONE, OP_NONE}, // JIZ {OP_IMM16, OP_NONE, OP_NONE},// CALL {OP_NONE, OP_NONE, OP_NONE}, // RET {OP_REG, OP_REG, OP_IMM4}, // PORT diff --git a/src/instruction.h b/src/instruction.h index d026009..bd6ce7e 100644 --- a/src/instruction.h +++ b/src/instruction.h @@ -28,6 +28,8 @@ typedef enum : uint8_t { // automatically know the length of the registers array } Register; +#define REG_IHT_OFFSET 8 // offset of interrupt handler table register + typedef uint16_t SerializedInst; typedef struct {