start work on interrupts
This commit is contained in:
102
src/emu.c
102
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) {
|
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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user