From 49f510d2d60129526832bfcd9c0f4049962bc80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20B=C3=B6hm?= Date: Mon, 18 May 2009 20:53:42 +0200 Subject: move stuff around and create initial source structure --- src/emu/cpu.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 src/emu/cpu.c (limited to 'src/emu/cpu.c') diff --git a/src/emu/cpu.c b/src/emu/cpu.c new file mode 100644 index 0000000..b0664cd --- /dev/null +++ b/src/emu/cpu.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "log.h" +#include "mem.h" +#include "opc.h" +#include "syscall.h" + +// program counter +uint32_t PC; + +// status bits +bool N, Z; + +// 32 general purpose registers +uint32_t GPR[32]; + +/* extract operands from the instruction regiter */ +static inline +uint32_t __OPEXT(uint32_t IR, uint8_t start, uint8_t length) +{ + return (IR >> start) & ((1 << length) - 1); +} + +#define OPEXT(start, length) __OPEXT(IR, start, length) + +/* operands */ +#define OPCODE OPEXT(26, 6) +#define REGa OPEXT(21, 5) +#define REGb OPEXT(16, 5) +#define REGc OPEXT(11, 5) +#define IMMc OPEXT(0, 16) + +/* cpu traps */ +void trap(int num) +{ + switch (num) { + case TRP_UNALIGNED: + raise(SIGSEGV); + break; + case TRP_DIVBYZERO: + raise(SIGFPE); + break; + case TRP_SYSCALL: + do_syscall(); + break; + case TRP_ILL: + raise(SIGILL); + break; + } +} + +void execute(uint32_t IR) +{ + /* decode op-code */ + uint8_t opcode = OPCODE; + int32_t a, b, c; + + if (opcode < OPC_MOV) { + /* arithmetic & logic */ + a = REGa; + b = REGb; + c = REGc; + + debug("PC@%#08x: %-3s r%i, r%i, r%i", PC, + opc2mnemonic(IR), a, b, c); + } + + else if (opcode < OPC_J) { + /* load/store & branch */ + a = REGa; + b = REGb; + c = IMMc; + + /* sign extension */ + 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, + opc2mnemonic(IR), a, b, c); + } + } + + else if (opcode < OPC_SYS) { + /* jump */ + a = REGa; + b = c = 0; + + debug("PC@%#08x: %-3s r%i", PC, + opc2mnemonic(IR), a); + } + + else { + /* misc */ + a = b = c = 0; + + debug("PC@%#08x: %-3s", PC, + 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? + GPR[a] = GPR[b] + GPR[c]; + break; + case OPC_SUB: + // XXX: signed/unsigned? + GPR[a] = GPR[b] - GPR[c]; + break; + case OPC_MUL: + // XXX: signed/unsigned? + GPR[a] = GPR[b] * GPR[c]; + break; + case OPC_DIV: + // XXX: signed/unsigned? + if (GPR[c] == 0) + trap(TRP_DIVBYZERO); + else + GPR[a] = GPR[b] / GPR[c]; + break; + case OPC_MOD: + // 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[b] == (uint32_t) c); + N = (GPR[b] < (uint32_t) c); + break; + case OPC_BEQ: + if (Z) + PC += c * sizeof(uint32_t); + break; + case OPC_BNE: + if (!Z) + PC += c * sizeof(uint32_t); + break; + case OPC_BLT: + if (N) + PC += c * sizeof(uint32_t); + break; + case OPC_BGE: + if (!N) + PC += c * sizeof(uint32_t); + break; + case OPC_BLE: + if (Z || N) + PC += c * sizeof(uint32_t); + break; + case OPC_BGT: + if (!Z && !N) + PC += c * sizeof(uint32_t); + case OPC_J: + PC = GPR[a]; + break; + case OPC_JAL: + GPR[31] = PC + sizeof(uint32_t); + PC = GPR[a]; + case OPC_SYS: + trap(TRP_SYSCALL); + break; + default: + /* illegal instruction */ + trap(TRP_ILL); + } +} -- cgit v1.2.3