summaryrefslogtreecommitdiffstats
path: root/src/emu/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu.c')
-rw-r--r--src/emu/cpu.c175
1 files changed, 90 insertions, 85 deletions
diff --git a/src/emu/cpu.c b/src/emu/cpu.c
index 7e62ffb..f32bb7f 100644
--- a/src/emu/cpu.c
+++ b/src/emu/cpu.c
@@ -11,16 +11,25 @@
#include "opc.h"
#include "syscall.h"
-// program counter
-uint32_t PC;
+/* stack pointer register*/
+uint32_t SP;
-// status bits
+/* base pointer register */
+uint32_t BP;
+
+/* return value register */
+uint32_t RV;
+
+/* instruction pointer */
+uint32_t IP;
+
+/* status bits */
bool N, Z;
-// 32 general purpose registers
-uint32_t GPR[32];
+/* general purpose registers */
+uint32_t *GPR;
-/* extract operands from the instruction regiter */
+/* extract operands from the instruction register */
static inline
uint32_t __OPEXT(uint32_t IR, uint8_t start, uint8_t length)
{
@@ -41,16 +50,19 @@ void trap(int num)
{
switch (num) {
case TRP_UNALIGNED:
- raise(SIGSEGV);
+ fprintf(stderr, "trap: unaligned memory access\n");
+ abort();
break;
case TRP_DIVBYZERO:
- raise(SIGFPE);
+ fprintf(stderr, "trap: division by zero\n");
+ abort();
break;
case TRP_SYSCALL:
do_syscall();
break;
case TRP_ILL:
- raise(SIGILL);
+ fprintf(stderr, "trap: illegal instruction\n");
+ abort();
break;
}
}
@@ -62,17 +74,17 @@ void execute(uint32_t IR)
int32_t a, b, c;
if (opcode < OPC_MOV) {
- /* arithmetic & logic */
+ /* arithmetic, logic, comparison */
a = REGa;
b = REGb;
c = REGc;
- debug("PC@%#08x: %-3s r%i, r%i, r%i", PC,
+ debug("IP@%#08x: %-4s r%i, r%i, r%i", IP,
opc2mnemonic(IR), a, b, c);
}
- else if (opcode < OPC_J) {
- /* load/store & branch */
+ else if (opcode < OPC_BEZ) {
+ /* load/store */
a = REGa;
b = REGb;
c = IMMc;
@@ -81,40 +93,59 @@ void execute(uint32_t IR)
if (c >= 0x8000)
c -= 0x10000;
- if (opcode < OPC_LB) {
- debug("PC@%#08x: %-3s r%i, %i", PC,
- opc2mnemonic(IR), b, c);
- } else {
- debug("PC@%#08x: %-3s r%i, r%i, %i", PC,
+ if (opcode < OPC_LW) {
+ debug("IP@%#08x: %-4s r%i, %i", IP,
+ opc2mnemonic(IR), a, c);
+ } else if (opcode < OPC_PUSH) {
+ debug("IP@%#08x: %-4s r%i, r%i, %i", IP,
opc2mnemonic(IR), a, b, c);
+ } else {
+ debug("IP@%#08x: %-4s r%i", IP,
+ opc2mnemonic(IR), a);
}
}
else if (opcode < OPC_SYS) {
/* jump */
a = REGa;
- b = c = 0;
+ b = 0;
+ c = IMMc;
- debug("PC@%#08x: %-3s r%i", PC,
- opc2mnemonic(IR), a);
+ /* sign extension */
+ if (c >= 0x8000)
+ c -= 0x10000;
+
+ switch (opcode) {
+ case OPC_BEZ:
+ debug("IP@%#08x: %-4s r%i, %i", IP,
+ opc2mnemonic(IR), a, c);
+ break;
+ case OPC_JMP:
+ debug("IP@%#08x: %-4s %i", IP,
+ opc2mnemonic(IR), c);
+ break;
+ case OPC_CALL:
+ debug("IP@%#08x: %-4s %i", IP,
+ opc2mnemonic(IR), c);
+ break;
+ case OPC_RET:
+ debug("IP@%#08x: %-4s", IP,
+ opc2mnemonic(IR));
+ break;
+ }
}
else {
/* misc */
a = b = c = 0;
- debug("PC@%#08x: %-3s", PC,
+ debug("IP@%#08x: %-3s", IP,
opc2mnemonic(IR));
}
// make sure r0 is zero
GPR[0] = 0;
- // buffer for load/store instructions
- uint8_t tmp8;
- uint16_t tmp16;
- uint32_t tmp32;
-
switch (opcode) {
case OPC_ADD:
// XXX: signed/unsigned?
@@ -139,69 +170,16 @@ void execute(uint32_t IR)
// XXX: signed/unsigned?
GPR[a] = GPR[b] % GPR[c];
break;
- case OPC_SHL:
- // XXX: signed/unsigned?
- GPR[a] = GPR[b] << GPR[c];
- break;
- case OPC_SHR:
- // XXX: signed/unsigned?
- GPR[a] = GPR[b] >> GPR[c];
- break;
case OPC_AND:
GPR[a] = GPR[b] & GPR[c];
break;
case OPC_OR:
GPR[a] = GPR[b] | GPR[c];
break;
- case OPC_XOR:
- GPR[a] = GPR[b] ^ GPR[c];
- break;
- case OPC_NOR:
- GPR[a] = ~(GPR[b] & GPR[c]);
- break;
- case OPC_MOV:
- GPR[b] = c;
- break;
- case OPC_LB:
- memcpy(&tmp8, &MEM[GPR[a] + c], sizeof(uint8_t));
- GPR[b] = tmp8;
- break;
- case OPC_LH:
- if ((GPR[a] + c) & 0x1)
- trap(TRP_UNALIGNED);
- memcpy(&tmp16, &MEM[GPR[a] + c], sizeof(uint16_t));
- GPR[b] = tmp16;
- break;
- case OPC_LW:
- if ((GPR[a] + c) & 0x2)
- trap(TRP_UNALIGNED);
- memcpy(&tmp32, &MEM[GPR[a] + c], sizeof(uint32_t));
- GPR[b] = tmp32;
- break;
- case OPC_SB:
- tmp8 = GPR[b];
- memcpy(&MEM[GPR[a] + c], &tmp8, sizeof(uint8_t));
- break;
- case OPC_SH:
- if ((GPR[a] + c) & 0x1)
- trap(TRP_UNALIGNED);
- tmp16 = GPR[b];
- memcpy(&MEM[GPR[a] + c], &tmp16, sizeof(uint16_t));
- break;
- case OPC_SW:
- if ((GPR[a] + c) & 0x2)
- trap(TRP_UNALIGNED);
- tmp32 = GPR[b];
- memcpy(&MEM[GPR[a] + c], &tmp32, sizeof(uint32_t));
- break;
case OPC_CMP:
Z = (GPR[a] == GPR[b]);
N = (GPR[a] < GPR[b]);
break;
- case OPC_BEZ:
- if (GPR[a] == 0)
- PC += c * sizeof(uint32_t);
- break;
case OPC_EQ:
GPR[a] = Z;
break;
@@ -219,12 +197,37 @@ void execute(uint32_t IR)
break;
case OPC_GT:
GPR[a] = !Z && !N;
- case OPC_J:
- PC = GPR[a];
+ case OPC_MOV:
+ GPR[a] = c;
break;
- case OPC_JAL:
- GPR[31] = PC + sizeof(uint32_t);
- PC = GPR[a];
+ case OPC_LW:
+ GPR[b] = load(GPR[a] + c);
+ break;
+ case OPC_SW:
+ store(GPR[a] + c, GPR[b]);
+ break;
+ case OPC_PUSH:
+ push(GPR[a]);
+ break;
+ case OPC_POP:
+ GPR[a] = pop();
+ break;
+ case OPC_BEZ:
+ if (GPR[a] == 0) {
+ IP += c * 4;
+ return;
+ }
+ break;
+ case OPC_JMP:
+ IP += c * 4;
+ return;
+ case OPC_CALL:
+ push(IP + 4);
+ IP += c * 4;
+ return;
+ case OPC_RET:
+ IP = pop();
+ return;
case OPC_SYS:
trap(TRP_SYSCALL);
break;
@@ -232,4 +235,6 @@ void execute(uint32_t IR)
/* illegal instruction */
trap(TRP_ILL);
}
+
+ IP += 4;
}