gipu/cpp/vm.cpp
Giulio De Pasquale ffb11f9a2e reg2reg assembler
2017-05-17 18:58:00 +02:00

283 lines
5.6 KiB
C++

#include "vm.h"
#include "debug.h"
#include "opcodes.h"
#include "vmas.h"
#include <string.h>
unsigned rol(unsigned x, int L, int N) {
unsigned lsbs = x & ((1 >> L) - 1);
return (x << L) | (lsbs >> (N - L));
}
void VM::defineOpcodes(uint8_t *key) {
uint32_t i, j, keysize;
keysize = strlen((char *)key);
for (i = 0; i < keysize; i++) {
for (j = 0; j < NUM_OPS; j++) {
if (key[i] % 2) {
OPS[j] = rol(key[i] ^ OPS[j], key[i] % 8, 8);
} else {
OPS[j] = rol(key[i] ^ OPS[j], (key[i] + 1) % 8, 8);
}
}
}
for (i = 0; i < NUM_OPS; i++) {
for (j = 0; j < NUM_OPS; j++) {
OPS[j] = rol(OPS[j], OPS[i] % 8, 8);
}
}
#ifdef DBG
//#TODO ASSEGNARE I NOMI AGLI OPCODES
DBG_INFO(("~~~~~~~~~~\nOPCODES:\n"));
for (i = 0; i < NUM_OPS; i++) {
DBG_INFO(("0x%x: 0x%x\n", i, OPS[i]));
}
DBG_INFO(("~~~~~~~~~~\n"));
#endif
return;
}
/*
DBG UTILS
*/
uint8_t *VM::getRegName(uint8_t regvalue) {
uint8_t *buf = new uint8_t[2];
#ifdef DBG
switch (regvalue) {
case R0:
memcpy(buf, "R0", 2);
break;
case R1:
memcpy(buf, "R1", 2);
break;
case R2:
memcpy(buf, "R2", 2);
break;
case R3:
memcpy(buf, "R3", 2);
break;
case S0:
memcpy(buf, "S0", 2);
break;
case S1:
memcpy(buf, "S1", 2);
break;
case S2:
memcpy(buf, "S2", 2);
break;
case S3:
memcpy(buf, "S3", 2);
break;
case IP:
memcpy(buf, "IP", 2);
break;
case BP:
memcpy(buf, "BP", 2);
break;
case SP:
memcpy(buf, "SP", 2);
break;
default:
memcpy(buf, "??", 2);
break;
}
#endif
return buf;
}
void VM::status(void) {
#ifdef DBG
uint8_t i;
DBG_SUCC(("VM Status:\n"));
DBG_SUCC(("~~~~~~~~~~\n"));
for (i = R0; i <= SP; i++) {
switch (i) {
case R0:
DBG_INFO(("R0:\t0x%x\n", this->regs[i]));
break;
case R1:
DBG_INFO(("R1:\t0x%x\n", this->regs[i]));
break;
case R2:
DBG_INFO(("R2:\t0x%x\n", this->regs[i]));
break;
case R3:
DBG_INFO(("R3:\t0x%x\n", this->regs[i]));
break;
case S0:
DBG_INFO(("S0:\t0x%x\n", this->regs[i]));
break;
case S1:
DBG_INFO(("S1:\t0x%x\n", this->regs[i]));
break;
case S2:
DBG_INFO(("S2:\t0x%x\n", this->regs[i]));
break;
case S3:
DBG_INFO(("S3:\t0x%x\n", this->regs[i]));
break;
case IP:
DBG_INFO(("IP:\t0x%x\n", this->regs[i]));
break;
case BP:
DBG_INFO(("BP:\t0x%x\n", this->regs[i]));
break;
case SP:
DBG_INFO(("SP:\t0x%x\n", this->regs[i]));
break;
}
}
DBG_SUCC(("~~~~~~~~~~\n"));
#endif
return;
}
/*
CONSTRUCTORS
*/
VM::VM(uint8_t *key) {
DBG_SUCC(("Creating VM without code.\n"));
as.allocate();
initVariables();
defineOpcodes(key);
}
VM::VM(uint8_t *key, uint8_t *code, uint32_t codesize) {
DBG_SUCC(("Creating VM with code.\n"));
if (as.allocate()) {
as.insCode(code, codesize);
}
initVariables();
defineOpcodes(key);
}
void VM::initVariables(void) {
uint32_t i;
for (i = R0; i < NUM_REGS; i++) {
this->regs[i] = 0;
}
for (i = 0; i < NUM_OPS; i++) {
OPS[i] = i;
}
return;
}
/*
INSTRUCTIONS IMPLEMENTATIONS
*/
bool VM::execMOVI(void) {
/*
MOVI R0, 0x2400 | R0 = 0x2400
*/
uint8_t dst;
uint16_t imm;
dst = as.code[regs[IP] + 1];
imm = *((uint16_t *)&as.code[regs[IP] + 2]);
DBG_INFO(("MOVI %s, 0x%x\n", getRegName(dst), imm));
if (dst == IP) {
DBG_ERROR(("Can't MOVI to IP!\n"));
return false;
}
regs[dst] = imm;
return true;
}
bool VM::execMOVR(void) {
/*
MOVR R1, R0 | R1 = R0
---------------------
R1, R0 = 0x10 <- DST / SRC are nibbles!
*/
uint8_t dst, src;
dst = as.code[regs[IP] + 1] >> 4;
src = as.code[regs[IP] + 1] & 0b00001111;
DBG_INFO(("MOVR %s, %s\n", getRegName(dst), getRegName(src)));
if (dst == IP || src == IP) {
DBG_ERROR(("Can't MOVR IP!\n"));
return false;
}
regs[dst] = regs[src];
return true;
}
bool VM::execLOAD(void) {
/*
LOAD R0, 0x1000 | R0 = data[0x1000]
*/
uint8_t dst;
uint16_t src;
dst = as.code[regs[IP] + 1];
src = *((uint16_t *)&as.code[regs[IP] + 2]);
DBG_INFO(("LOAD %s, 0x%x\n", getRegName(dst), src));
regs[dst] = *((uint16_t *)&as.data[src]);
return true;
}
bool VM::execSTOR(void) {
/*
STOR 0x1000, R0 | data[0x1000] = R0
*/
uint16_t dst;
uint8_t src;
dst = *((uint16_t *)&as.code[regs[IP] + 1]);
src = as.code[regs[IP] + 3];
DBG_INFO(("STOR 0x%x, %s\n", dst, getRegName(src)));
*((uint16_t *)&as.data[dst]) = regs[src];
return true;
}
bool VM::execADDI(void) {
/*
ADDI R0, 0x2 | R0 += 2
*/
uint8_t dst;
uint16_t src;
dst = as.code[regs[IP] + 1];
src = *((uint16_t *)&as.code[regs[IP] + 2]);
DBG_INFO(("ADDI %s, 0x%x\n", getRegName(dst), src));
regs[dst] += src;
return true;
}
void VM::execADDR(void) {
uint8_t dst;
uint8_t src;
dst = as.code[regs[IP] + 1] >> 4;
src = as.code[regs[IP] + 1] & 0b00001111;
DBG_INFO(("ADDR %s, 0x%x\n", getRegName(dst), src));
regs[dst] += regs[src];
return;
}
void VM::run(void) {
uint8_t opcode;
bool finished = false;
while (!finished) {
opcode = (uint8_t)as.code[regs[IP]];
if (opcode == OPS[MOVI]) {
execMOVI();
regs[IP] += MOVI_SIZE;
} else if (opcode == OPS[MOVR]) {
execMOVR();
regs[IP] += MOVR_SIZE;
} else if (opcode == OPS[LOAD]) {
execLOAD();
regs[IP] += LOAD_SIZE;
} else if (opcode == OPS[STOR]) {
execSTOR();
regs[IP] += STOR_SIZE;
} else if (opcode == OPS[ADDI]) {
execADDI();
regs[IP] += ADDI_SIZE;
} else if (opcode == OPS[SHIT]) {
finished = true;
} else {
DBG_ERROR(("WAT\n"));
finished = true;
}
}
return;
}