start work on interrupts

This commit is contained in:
2026-07-16 18:28:55 +10:00
parent 82f9644e15
commit b58b5adf65
4 changed files with 79 additions and 37 deletions

102
src/emu.c
View File

@@ -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) { void startEmulator(Emulator* emu) {
static void* dispatchTable[] = { static void* dispatchTable[] = {
&&MOV, &&MOV,
@@ -49,93 +82,96 @@ void startEmulator(Emulator* emu) {
emu->halted = false; emu->halted = false;
Instruction inst; Instruction inst;
#define DISPATCH() updateDevices(emu); \ #define DISPATCH() if (emu->irq != 0) handleInterrupt(emu); \
updateDevices(emu); \
inst = fetchInst(emu); \ inst = fetchInst(emu); \
goto *dispatchTable[inst.opcode] goto *dispatchTable[inst.opcode]
DISPATCH(); DISPATCH();
MOV: { MOV: {
emu->regs[inst.operands[0]] = emu->regs[inst.operands[1]]; setRegister(emu, inst.operands[0], getRegister(emu, inst.operands[1]));
DISPATCH(); DISPATCH();
} }
MVI: { MVI: {
emu->regs[inst.operands[0]] = inst.immediate; setRegister(emu, inst.operands[0], inst.immediate);
DISPATCH(); DISPATCH();
} }
ADD: { 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); updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result; setRegister(emu, inst.operands[0], result);
DISPATCH(); DISPATCH();
} }
SUB: { 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); updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result; setRegister(emu, inst.operands[0], result);
DISPATCH(); DISPATCH();
} }
LOAD: { LOAD: {
uint32_t addr = getAddress( uint32_t addr = getAddress(
emu->regs[inst.operands[1]], getRegister(emu, inst.operands[1]),
emu->regs[inst.operands[2]] getRegister(emu, inst.operands[2])
); );
emu->regs[inst.operands[0]] = memoryLoadWord(emu->mem, addr); setRegister(emu, inst.operands[0], memoryLoadWord(emu->mem, addr));
DISPATCH(); DISPATCH();
} }
STORE: { STORE: {
uint32_t addr = getAddress( uint32_t addr = getAddress(
emu->regs[inst.operands[0]], getRegister(emu, inst.operands[1]),
emu->regs[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(); DISPATCH();
} }
AND: { 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); updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result; setRegister(emu, inst.operands[0], result);
DISPATCH(); DISPATCH();
} }
OR: { 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); updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result; setRegister(emu, inst.operands[0], result);
DISPATCH(); DISPATCH();
} }
XOR: { 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); updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result; setRegister(emu, inst.operands[0], result);
DISPATCH(); DISPATCH();
} }
SHF: { SHF: {
int32_t result; 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 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); updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result; setRegister(emu, inst.operands[0], result);
DISPATCH(); DISPATCH();
} }
JMP: { JMP: {
emu->pc = getAddress(inst.operands[0], inst.operands[1]); emu->pc = inst.immediate;
DISPATCH(); DISPATCH();
} }
JIZ: { JIZ: {
if (emu->regs[REG_F] & FLAG_ZERO) if (((FlagsRegister)emu->regs[REG_F]).fields.zero)
emu->pc = getAddress(inst.operands[0], inst.operands[1]); emu->pc = inst.immediate;
DISPATCH(); DISPATCH();
} }
CALL: { CALL: {
// save the pc at the current sp and decrement the sp (stack grows downward) // 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 // jump to given addr
emu->pc = getAddress(inst.operands[0], inst.operands[1]); emu->pc = inst.immediate;
DISPATCH(); DISPATCH();
} }
@@ -145,7 +181,7 @@ void startEmulator(Emulator* emu) {
DISPATCH(); DISPATCH();
} }
PORT: { PORT: {
uint16_t port = emu->regs[inst.operands[0]]; uint16_t port = getRegister(emu, inst.operands[0]);
if (port >= MAX_DEVICES) { if (port >= MAX_DEVICES) {
DISPATCH(); DISPATCH();
} }
@@ -158,7 +194,7 @@ void startEmulator(Emulator* emu) {
} }
if (direction == 0) { 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) { if (device->inPos == DEVICE_BUFFER_LENGTH) {
DISPATCH(); DISPATCH();
@@ -168,11 +204,11 @@ void startEmulator(Emulator* emu) {
device->inPos++; device->inPos++;
} else { } else {
if (device->outPos == 0) { if (device->outPos == 0) {
emu->regs[inst.operands[1]] = 0; setRegister(emu, inst.operands[1], 0);
DISPATCH(); 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) if (device->outPos > 0)
device->outPos--; device->outPos--;
} }
@@ -196,7 +232,7 @@ Emulator* initEmulator(uint32_t memorySize) {
// zero out special regs // zero out special regs
newEmu->pc = MEM_PROGRAM_START; newEmu->pc = MEM_PROGRAM_START;
newEmu->sp = 0; newEmu->sp = 0;
newEmu->ihp = 0; newEmu->iht = 0;
// init memory // init memory
newEmu->mem = initMemory(memorySize); newEmu->mem = initMemory(memorySize);

View File

@@ -21,13 +21,17 @@ typedef struct {
Device* devices[MAX_DEVICES]; Device* devices[MAX_DEVICES];
uint32_t pc; uint32_t pc;
uint32_t ihp; uint32_t iht;
uint32_t sp; uint32_t sp;
bool irq; uint16_t irq;
bool halted; bool halted;
} Emulator; } Emulator;
typedef struct {
uint32_t interruptHandlers[32];
} __attribute__((packed)) InterruptHandlerTable;
typedef union { typedef union {
struct { struct {
uint16_t zero : 1; uint16_t zero : 1;

View File

@@ -11,8 +11,8 @@ const OperandType INSTRUCTION_OPERAND_TYPES[][3] = {
{OP_REG, OP_REG, OP_NONE}, // OR {OP_REG, OP_REG, OP_NONE}, // OR
{OP_REG, OP_REG, OP_NONE}, // XOR {OP_REG, OP_REG, OP_NONE}, // XOR
{OP_REG, OP_REG, OP_REG}, // SHF {OP_REG, OP_REG, OP_REG}, // SHF
{OP_REG, OP_REG, OP_NONE}, // JMP {OP_IMM16, OP_NONE, OP_NONE}, // JMP
{OP_REG, OP_REG, OP_NONE}, // JIZ {OP_IMM16, OP_NONE, OP_NONE}, // JIZ
{OP_IMM16, OP_NONE, OP_NONE},// CALL {OP_IMM16, OP_NONE, OP_NONE},// CALL
{OP_NONE, OP_NONE, OP_NONE}, // RET {OP_NONE, OP_NONE, OP_NONE}, // RET
{OP_REG, OP_REG, OP_IMM4}, // PORT {OP_REG, OP_REG, OP_IMM4}, // PORT

View File

@@ -28,6 +28,8 @@ typedef enum : uint8_t {
// automatically know the length of the registers array // automatically know the length of the registers array
} Register; } Register;
#define REG_IHT_OFFSET 8 // offset of interrupt handler table register
typedef uint16_t SerializedInst; typedef uint16_t SerializedInst;
typedef struct { typedef struct {