Files
MyLittleCPU/src/emu.c

172 lines
4.3 KiB
C
Raw Normal View History

2026-07-15 15:02:54 +10:00
#include "emu.h"
inline Instruction fetchInst(Emulator* emu) {
2026-07-16 12:04:17 +10:00
Instruction inst = decodeInstruction(emu->mem, &emu->pc);
printf("%s\n", instructionToCStr(inst));
return inst;
}
inline void updateFlagsRegister(Emulator* emu, int32_t value) {
if (value == 0) {
emu->regs[REG_F] = FLAG_ZERO;
} else if (value < 0) {
emu->regs[REG_F] = FLAG_NEGATIVE;
} else if (value > UINT16_MAX) {
emu->regs[REG_F] = FLAG_OVERFLOW;
}
}
void startEmulator(Emulator* emu) {
static void* dispatchTable[] = {
&&MOV,
&&MVI,
&&ADD,
&&SUB,
&&LOAD,
&&STORE,
&&AND,
&&OR,
&&XOR,
&&SHF,
&&JMP,
&&JIZ,
&&CALL,
&&RET,
&&SYS,
&&HLT
};
emu->halted = false;
Instruction inst;
#define DISPATCH() inst = fetchInst(emu); \
goto *dispatchTable[inst.opcode];
DISPATCH();
MOV: {
emu->regs[inst.operands[0]] = emu->regs[inst.operands[1]];
DISPATCH();
}
MVI: {
emu->regs[inst.operands[0]] = inst.immediate;
DISPATCH();
}
ADD: {
int32_t result = emu->regs[inst.operands[0]] + emu->regs[inst.operands[1]];
updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result;
DISPATCH();
}
SUB: {
int32_t result = emu->regs[inst.operands[0]] - emu->regs[inst.operands[1]];
updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result;
DISPATCH();
}
LOAD: {
uint32_t addr = getAddress(
emu->regs[inst.operands[1]],
emu->regs[inst.operands[2]]
);
emu->regs[inst.operands[0]] = memoryLoadWord(emu->mem, addr);
DISPATCH();
}
STORE: {
uint32_t addr = getAddress(
emu->regs[inst.operands[0]],
emu->regs[inst.operands[1]]
);
memorySaveWord(emu->mem, addr, inst.operands[2]);
DISPATCH();
}
AND: {
int32_t result = emu->regs[inst.operands[0]] & emu->regs[inst.operands[1]];
updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result;
DISPATCH();
}
OR: {
int32_t result = emu->regs[inst.operands[0]] | emu->regs[inst.operands[1]];
updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result;
DISPATCH();
}
XOR: {
int32_t result = emu->regs[inst.operands[0]] ^ emu->regs[inst.operands[1]];
updateFlagsRegister(emu, result);
emu->regs[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]];
else
result = emu->regs[inst.operands[0]] >> emu->regs[inst.operands[1]];
updateFlagsRegister(emu, result);
emu->regs[inst.operands[0]] = result;
DISPATCH();
}
JMP: {
emu->pc = getAddress(inst.operands[0], inst.operands[1]);
DISPATCH();
}
JIZ: {
if (emu->regs[REG_F] & FLAG_ZERO)
emu->pc = getAddress(inst.operands[0], inst.operands[1]);
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;
// jump to given addr
emu->pc = getAddress(inst.operands[0], inst.operands[1]);
DISPATCH();
}
RET: {
// return to value at sp and increment it
emu->pc = ((uint32_t*)emu->mem->data)[++emu->sp];
DISPATCH();
}
SYS: {
// TODO
DISPATCH();
}
HLT: {
emu->halted = true;
return;
}
}
2026-07-15 15:02:54 +10:00
Emulator* initEmulator(uint32_t memorySize) {
Emulator* newEmu = malloc(sizeof(Emulator));
if (!newEmu)
return NULL;
// zero out registers
memset(newEmu->regs, 0, sizeof(newEmu->regs));
2026-07-15 15:54:51 +10:00
// zero out special regs
newEmu->pc = MEM_PROGRAM_START;
2026-07-15 15:54:51 +10:00
newEmu->sp = 0;
newEmu->ihp = 0;
2026-07-15 15:02:54 +10:00
// init memory
newEmu->mem = initMemory(memorySize);
if (!newEmu->mem) {
free(newEmu);
return NULL;
}
return newEmu;
2026-07-15 15:54:51 +10:00
}
void freeEmulator(Emulator* emu) {
freeMemory(emu->mem);
free(emu);
2026-07-15 15:02:54 +10:00
}