2017-05-14 13:06:17 +01:00
|
|
|
#include "vm.h"
|
2017-05-13 18:36:46 +01:00
|
|
|
#include "debug.h"
|
2017-05-17 17:32:05 +01:00
|
|
|
#include "opcodes.h"
|
2017-05-14 13:06:17 +01:00
|
|
|
#include "vmas.h"
|
|
|
|
#include <string.h>
|
2017-05-13 18:36:46 +01:00
|
|
|
|
2017-05-17 10:21:40 +01:00
|
|
|
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++) {
|
2017-05-18 16:28:10 +01:00
|
|
|
OPS[j] = rol(key[i] ^ OPS[j], key[i] % 8, 8);
|
2017-05-17 10:21:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < NUM_OPS; i++) {
|
|
|
|
for (j = 0; j < NUM_OPS; j++) {
|
2017-05-17 17:32:05 +01:00
|
|
|
OPS[j] = rol(OPS[j], OPS[i] % 8, 8);
|
2017-05-17 10:21:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DBG
|
2017-05-17 17:32:05 +01:00
|
|
|
//#TODO ASSEGNARE I NOMI AGLI OPCODES
|
|
|
|
DBG_INFO(("~~~~~~~~~~\nOPCODES:\n"));
|
2017-05-17 10:21:40 +01:00
|
|
|
for (i = 0; i < NUM_OPS; i++) {
|
2017-05-17 17:32:05 +01:00
|
|
|
DBG_INFO(("0x%x: 0x%x\n", i, OPS[i]));
|
2017-05-17 10:21:40 +01:00
|
|
|
}
|
2017-05-17 17:32:05 +01:00
|
|
|
DBG_INFO(("~~~~~~~~~~\n"));
|
2017-05-17 10:21:40 +01:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2017-05-14 21:10:58 +01:00
|
|
|
/*
|
2017-05-15 11:49:11 +01:00
|
|
|
DBG UTILS
|
2017-05-14 21:10:58 +01:00
|
|
|
*/
|
2017-05-13 18:36:46 +01:00
|
|
|
|
2017-05-17 17:58:00 +01:00
|
|
|
uint8_t *VM::getRegName(uint8_t regvalue) {
|
2017-05-15 11:49:11 +01:00
|
|
|
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;
|
2017-05-14 21:10:58 +01:00
|
|
|
}
|
2017-05-15 11:49:11 +01:00
|
|
|
#endif
|
|
|
|
return buf;
|
2017-05-14 13:06:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void VM::status(void) {
|
2017-05-15 11:49:11 +01:00
|
|
|
#ifdef DBG
|
2017-05-14 13:06:17 +01:00
|
|
|
uint8_t i;
|
2017-05-15 14:31:12 +01:00
|
|
|
DBG_SUCC(("VM Status:\n"));
|
|
|
|
DBG_SUCC(("~~~~~~~~~~\n"));
|
2017-05-14 13:06:17 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2017-05-18 16:28:10 +01:00
|
|
|
DBG_INFO(("Flags: ZF = %d, CF = %d\n", flags.ZF, flags.CF));
|
2017-05-15 14:31:12 +01:00
|
|
|
DBG_SUCC(("~~~~~~~~~~\n"));
|
2017-05-15 11:49:11 +01:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
CONSTRUCTORS
|
|
|
|
*/
|
2017-05-17 10:21:40 +01:00
|
|
|
VM::VM(uint8_t *key) {
|
2017-05-15 14:31:12 +01:00
|
|
|
DBG_SUCC(("Creating VM without code.\n"));
|
2017-05-15 11:49:11 +01:00
|
|
|
as.allocate();
|
2017-05-17 10:21:40 +01:00
|
|
|
initVariables();
|
|
|
|
defineOpcodes(key);
|
2017-05-15 11:49:11 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 10:21:40 +01:00
|
|
|
VM::VM(uint8_t *key, uint8_t *code, uint32_t codesize) {
|
2017-05-15 14:31:12 +01:00
|
|
|
DBG_SUCC(("Creating VM with code.\n"));
|
2017-05-15 11:49:11 +01:00
|
|
|
if (as.allocate()) {
|
|
|
|
as.insCode(code, codesize);
|
|
|
|
}
|
2017-05-17 10:21:40 +01:00
|
|
|
initVariables();
|
|
|
|
defineOpcodes(key);
|
2017-05-15 11:49:11 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 10:21:40 +01:00
|
|
|
void VM::initVariables(void) {
|
|
|
|
uint32_t i;
|
2017-05-15 11:49:11 +01:00
|
|
|
|
2017-05-17 10:21:40 +01:00
|
|
|
for (i = R0; i < NUM_REGS; i++) {
|
2017-05-15 11:49:11 +01:00
|
|
|
this->regs[i] = 0;
|
|
|
|
}
|
2017-05-17 17:32:05 +01:00
|
|
|
for (i = 0; i < NUM_OPS; i++) {
|
|
|
|
OPS[i] = i;
|
2017-05-17 10:21:40 +01:00
|
|
|
}
|
2017-05-14 13:06:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-14 21:10:58 +01:00
|
|
|
/*
|
|
|
|
INSTRUCTIONS IMPLEMENTATIONS
|
|
|
|
*/
|
|
|
|
|
2017-05-17 17:58:00 +01:00
|
|
|
bool VM::execMOVI(void) {
|
2017-05-14 21:10:58 +01:00
|
|
|
/*
|
|
|
|
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]);
|
2017-05-17 17:58:00 +01:00
|
|
|
DBG_INFO(("MOVI %s, 0x%x\n", getRegName(dst), imm));
|
2017-05-15 13:39:40 +01:00
|
|
|
if (dst == IP) {
|
|
|
|
DBG_ERROR(("Can't MOVI to IP!\n"));
|
|
|
|
return false;
|
|
|
|
}
|
2017-05-14 21:10:58 +01:00
|
|
|
regs[dst] = imm;
|
2017-05-15 13:39:40 +01:00
|
|
|
return true;
|
2017-05-14 21:10:58 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 17:58:00 +01:00
|
|
|
bool VM::execMOVR(void) {
|
2017-05-14 21:10:58 +01:00
|
|
|
/*
|
2017-05-18 14:41:05 +01:00
|
|
|
MOVR R1, R0 -> R1 = R0
|
2017-05-14 21:10:58 +01:00
|
|
|
---------------------
|
|
|
|
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;
|
2017-05-17 17:58:00 +01:00
|
|
|
DBG_INFO(("MOVR %s, %s\n", getRegName(dst), getRegName(src)));
|
2017-05-15 13:39:40 +01:00
|
|
|
if (dst == IP || src == IP) {
|
|
|
|
DBG_ERROR(("Can't MOVR IP!\n"));
|
|
|
|
return false;
|
|
|
|
}
|
2017-05-14 21:10:58 +01:00
|
|
|
regs[dst] = regs[src];
|
2017-05-15 13:39:40 +01:00
|
|
|
return true;
|
2017-05-14 21:10:58 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 17:58:00 +01:00
|
|
|
bool VM::execLOAD(void) {
|
2017-05-14 21:10:58 +01:00
|
|
|
/*
|
2017-05-18 14:41:05 +01:00
|
|
|
LOAD R0, 0x1000 -> R0 = data[0x1000]
|
2017-05-14 21:10:58 +01:00
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint16_t src;
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = *((uint16_t *)&as.code[regs[IP] + 2]);
|
2017-05-17 17:58:00 +01:00
|
|
|
DBG_INFO(("LOAD %s, 0x%x\n", getRegName(dst), src));
|
2017-05-14 21:10:58 +01:00
|
|
|
regs[dst] = *((uint16_t *)&as.data[src]);
|
2017-05-15 13:39:40 +01:00
|
|
|
return true;
|
2017-05-14 21:10:58 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 17:58:00 +01:00
|
|
|
bool VM::execSTOR(void) {
|
2017-05-14 21:10:58 +01:00
|
|
|
/*
|
2017-05-18 14:41:05 +01:00
|
|
|
STOR 0x1000, R0 -> data[0x1000] = R0
|
2017-05-14 21:10:58 +01:00
|
|
|
*/
|
|
|
|
uint16_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
dst = *((uint16_t *)&as.code[regs[IP] + 1]);
|
|
|
|
src = as.code[regs[IP] + 3];
|
2017-05-17 17:58:00 +01:00
|
|
|
DBG_INFO(("STOR 0x%x, %s\n", dst, getRegName(src)));
|
2017-05-14 21:10:58 +01:00
|
|
|
*((uint16_t *)&as.data[dst]) = regs[src];
|
2017-05-15 13:39:40 +01:00
|
|
|
return true;
|
2017-05-14 21:10:58 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 17:58:00 +01:00
|
|
|
bool VM::execADDI(void) {
|
2017-05-14 21:10:58 +01:00
|
|
|
/*
|
2017-05-18 14:41:05 +01:00
|
|
|
ADDI R0, 0x2 -> R0 += 2
|
2017-05-14 21:10:58 +01:00
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint16_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = *((uint16_t *)&as.code[regs[IP] + 2]);
|
2017-05-17 17:58:00 +01:00
|
|
|
DBG_INFO(("ADDI %s, 0x%x\n", getRegName(dst), src));
|
2017-05-14 21:10:58 +01:00
|
|
|
regs[dst] += src;
|
2017-05-15 13:39:40 +01:00
|
|
|
return true;
|
2017-05-14 21:10:58 +01:00
|
|
|
}
|
|
|
|
|
2017-05-17 18:31:27 +01:00
|
|
|
bool VM::execADDR(void) {
|
2017-05-18 14:41:05 +01:00
|
|
|
/*
|
|
|
|
ADDR R0, R1 -> R0 += R1
|
|
|
|
*/
|
2017-05-17 17:58:00 +01:00
|
|
|
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];
|
2017-05-17 18:31:27 +01:00
|
|
|
return true;
|
2017-05-17 17:58:00 +01:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:41:05 +01:00
|
|
|
bool VM::execSUBI(void) {
|
|
|
|
/*
|
|
|
|
SUBI 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(("SUBI %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] -= src;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execSUBR(void) {
|
|
|
|
/*
|
|
|
|
SUBR R0, R1 -> R0 -= R1
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1] >> 4;
|
|
|
|
src = as.code[regs[IP] + 1] & 0b00001111;
|
|
|
|
DBG_INFO(("SUBR %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] -= regs[src];
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-18 16:28:10 +01:00
|
|
|
bool VM::execANDB(void) {
|
|
|
|
/*
|
|
|
|
ANDB R0, 0x2 -> R0 &= 0x02 or R0 &= [BYTE] 0x02 (low byte)
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = as.code[regs[IP] + 2];
|
|
|
|
DBG_INFO(("ANDB %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] &= src;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execANDW(void) {
|
|
|
|
/*
|
|
|
|
ANDW R0, 0x2 -> R0 &= 0x0002 or R0, ^= [WORD] 0x2
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint16_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = *((uint16_t *)&as.code[regs[IP] + 2]);
|
|
|
|
DBG_INFO(("XORW %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] &= src;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execANDR(void) {
|
|
|
|
/*
|
|
|
|
ANDR R0, R1 -> R0 ^= R1
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1] >> 4;
|
|
|
|
src = as.code[regs[IP] + 1] & 0b00001111;
|
|
|
|
DBG_INFO(("ANDR %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] &= regs[src];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execYORB(void) {
|
|
|
|
/*
|
|
|
|
YORB R0, 0x2 -> R0 |= 0x02 or R0 |= [BYTE] 0x02 (low byte)
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = as.code[regs[IP] + 2];
|
|
|
|
DBG_INFO(("YORB %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] |= src;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execYORW(void) {
|
|
|
|
/*
|
|
|
|
YORW R0, 0x2 -> R0 |= 0x0002 or R0, |= [WORD] 0x2
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint16_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = *((uint16_t *)&as.code[regs[IP] + 2]);
|
|
|
|
DBG_INFO(("XORW %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] |= src;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execYORR(void) {
|
|
|
|
/*
|
|
|
|
YORR R0, R1 -> R0 |= R1
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1] >> 4;
|
|
|
|
src = as.code[regs[IP] + 1] & 0b00001111;
|
|
|
|
DBG_INFO(("XORR %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] |= regs[src];
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-18 14:41:05 +01:00
|
|
|
bool VM::execXORB(void) {
|
|
|
|
/*
|
|
|
|
XORB R0, 0x2 -> R0 ^= 0x02 or R0 ^= [BYTE] 0x02 (low byte)
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = as.code[regs[IP] + 2];
|
|
|
|
DBG_INFO(("XORB %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] ^= src;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execXORW(void) {
|
|
|
|
/*
|
|
|
|
XORW R0, 0x2 -> R0 ^= 0x0002 or R0, ^= [WORD] 0x2
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint16_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
src = *((uint16_t *)&as.code[regs[IP] + 2]);
|
|
|
|
DBG_INFO(("XORW %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] ^= src;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execXORR(void) {
|
|
|
|
/*
|
|
|
|
XORR R0, R1 -> R0 ^= R1
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1] >> 4;
|
|
|
|
src = as.code[regs[IP] + 1] & 0b00001111;
|
|
|
|
DBG_INFO(("XORR %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] ^= regs[src];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execNOTR(void) {
|
|
|
|
/*
|
|
|
|
NOTR R0, R1 -> R0 = ~R1
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1] >> 4;
|
|
|
|
src = as.code[regs[IP] + 1] & 0b00001111;
|
|
|
|
DBG_INFO(("NOTR %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] = ~regs[src];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execMULI(void) {
|
|
|
|
/*
|
|
|
|
MULI 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(("SUBI %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] *= src;
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-18 16:28:10 +01:00
|
|
|
bool VM::execMULR(void) {
|
|
|
|
/*
|
|
|
|
MULR R0, R1 -> R0 *= R1
|
|
|
|
*/
|
|
|
|
uint8_t dst;
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1] >> 4;
|
|
|
|
src = as.code[regs[IP] + 1] & 0b00001111;
|
|
|
|
DBG_INFO(("MULR %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] *= regs[src];
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-18 14:41:05 +01:00
|
|
|
bool VM::execDIVI(void) {
|
|
|
|
/*
|
|
|
|
DIVI 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(("DIVI %s, 0x%x\n", getRegName(dst), src));
|
|
|
|
regs[dst] /= src;
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-18 16:28:10 +01:00
|
|
|
bool VM::execDIVR(void) {
|
|
|
|
/*
|
|
|
|
DIVR R0, R1 -> R0 /= R1
|
|
|
|
*/
|
|
|
|
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 true;
|
|
|
|
}
|
|
|
|
bool VM::execPUSH(void) {
|
|
|
|
// TODO: STACK < 0
|
|
|
|
uint8_t src;
|
|
|
|
|
|
|
|
src = as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("PUSH %s\n", getRegName(src)));
|
|
|
|
memcpy(&as.stack[regs[SP]], ®s[src], sizeof(uint16_t));
|
|
|
|
regs[SP] += sizeof(uint16_t);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execPOOP(void) {
|
|
|
|
// TODO: STACK < 0
|
|
|
|
uint8_t dst;
|
|
|
|
|
|
|
|
dst = as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("POOP %s\n", getRegName(dst)));
|
|
|
|
regs[SP] -= sizeof(uint16_t);
|
|
|
|
memcpy(®s[dst], &as.stack[regs[SP]], sizeof(uint16_t));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execCMPI(void) {
|
|
|
|
/*
|
|
|
|
CMPI R0, 0x2 -> Compare immediate with register
|
|
|
|
*/
|
|
|
|
uint8_t reg;
|
|
|
|
uint16_t imm;
|
|
|
|
|
|
|
|
reg = as.code[regs[IP] + 1];
|
|
|
|
imm = *((uint16_t *)&as.code[regs[IP] + 2]);
|
|
|
|
DBG_INFO(("CMPI %s, 0x%x\n", getRegName(reg), imm));
|
|
|
|
if (regs[reg] == imm) {
|
|
|
|
flags.ZF = 1;
|
|
|
|
} else {
|
|
|
|
flags.ZF = 0;
|
|
|
|
}
|
|
|
|
if (regs[reg] > imm) {
|
|
|
|
flags.CF = 1;
|
|
|
|
} else {
|
|
|
|
flags.CF = 0;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execCMPR(void) {
|
|
|
|
/*
|
|
|
|
CMPR R0, R1 -> Compares 2 registers
|
|
|
|
*/
|
|
|
|
uint8_t r1;
|
|
|
|
uint8_t r2;
|
|
|
|
|
|
|
|
r1 = as.code[regs[IP] + 1] >> 4;
|
|
|
|
r2 = as.code[regs[IP] + 1] & 0b00001111;
|
|
|
|
DBG_INFO(("CMPR %s, %s\n", getRegName(r1), getRegName(r2)));
|
|
|
|
if (regs[r1] == regs[r2]) {
|
|
|
|
flags.ZF = 1;
|
|
|
|
} else {
|
|
|
|
flags.ZF = 0;
|
|
|
|
}
|
|
|
|
if (regs[r1] > regs[r2]) {
|
|
|
|
flags.CF = 1;
|
|
|
|
} else {
|
|
|
|
flags.CF = 0;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execJMPI(void) {
|
|
|
|
/*
|
|
|
|
JMPI 0x2000 -> IP = 0x2000
|
|
|
|
*/
|
|
|
|
uint16_t imm;
|
|
|
|
|
|
|
|
imm = *(uint16_t *)&as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JMPI 0x%x\n", imm));
|
|
|
|
regs[IP] = imm;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execJMPR(void) {
|
|
|
|
/*
|
|
|
|
JMPR R0 -> IP = R0
|
|
|
|
*/
|
|
|
|
uint8_t reg;
|
|
|
|
|
|
|
|
reg = as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JMPR %s = 0x%x\n", getRegName(reg), regs[reg]));
|
|
|
|
regs[IP] = regs[reg];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VM::execJPAI(void) {
|
|
|
|
/*
|
|
|
|
JPAI 0x2000 -> Jump to 0x2000 if above
|
|
|
|
*/
|
|
|
|
uint16_t imm;
|
|
|
|
|
|
|
|
imm = *(uint16_t *)&as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPAI 0x%x\n", imm));
|
|
|
|
if (flags.CF == 1) {
|
|
|
|
regs[IP] = imm;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execJPAR(void) {
|
|
|
|
/*
|
|
|
|
JPAR R0 -> Jump to [R0] if above
|
|
|
|
*/
|
|
|
|
uint8_t reg;
|
|
|
|
|
|
|
|
reg = as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPAR %s = 0x%x\n", getRegName(reg), regs[reg]));
|
|
|
|
if (flags.CF == 1) {
|
|
|
|
regs[IP] = reg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execJPBI(void) {
|
|
|
|
/*
|
|
|
|
JPBI 0x2000 -> Jump to 0x2000 if below
|
|
|
|
*/
|
|
|
|
uint16_t imm;
|
|
|
|
|
|
|
|
imm = *(uint16_t *)&as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPBI 0x%x\n", imm));
|
|
|
|
if (flags.CF == 0) {
|
|
|
|
regs[IP] = imm;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execJPBR(void) {
|
|
|
|
/*
|
|
|
|
JPBR R0 -> Jump to [R0] if below
|
|
|
|
*/
|
|
|
|
uint8_t reg;
|
|
|
|
|
|
|
|
reg = as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPBR %s = 0x%x\n", getRegName(reg), regs[reg]));
|
|
|
|
if (flags.CF == 0) {
|
|
|
|
regs[IP] = reg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execJPEI(void) {
|
|
|
|
/*
|
|
|
|
JPEI 0x2000 -> Jump to 0x2000 if equal
|
|
|
|
*/
|
|
|
|
uint16_t imm;
|
|
|
|
|
|
|
|
imm = *(uint16_t *)&as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPEI 0x%x\n", imm));
|
|
|
|
if (flags.ZF == 1) {
|
|
|
|
regs[IP] = imm;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execJPER(void) {
|
|
|
|
/*
|
|
|
|
JPNR R0 -> Jump to [R0] if equal
|
|
|
|
*/
|
|
|
|
uint8_t reg;
|
|
|
|
|
|
|
|
reg = as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPER %s = 0x%x\n", getRegName(reg), regs[reg]));
|
|
|
|
if (flags.ZF == 1) {
|
|
|
|
regs[IP] = reg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execJPNI(void) {
|
|
|
|
/*
|
|
|
|
JPEI 0x2000 -> Jump to 0x2000 if not equal
|
|
|
|
*/
|
|
|
|
uint16_t imm;
|
|
|
|
|
|
|
|
imm = *(uint16_t *)&as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPNI 0x%x\n", imm));
|
|
|
|
if (flags.ZF == 0) {
|
|
|
|
regs[IP] = imm;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execJPNR(void) {
|
|
|
|
/*
|
|
|
|
JPER R0 -> Jump to [R0] if not equal
|
|
|
|
*/
|
|
|
|
uint8_t reg;
|
|
|
|
|
|
|
|
reg = as.code[regs[IP] + 1];
|
|
|
|
DBG_INFO(("JPNR %s = 0x%x\n", getRegName(reg), regs[reg]));
|
|
|
|
if (flags.ZF == 0) {
|
|
|
|
regs[IP] = reg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool VM::execGRMN(void) {
|
|
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < NUM_REGS; i++) {
|
|
|
|
regs[i] = 0x4747;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-14 21:10:58 +01:00
|
|
|
void VM::run(void) {
|
|
|
|
uint8_t opcode;
|
|
|
|
bool finished = false;
|
|
|
|
while (!finished) {
|
|
|
|
opcode = (uint8_t)as.code[regs[IP]];
|
2017-05-17 17:32:05 +01:00
|
|
|
if (opcode == OPS[MOVI]) {
|
2017-05-17 17:58:00 +01:00
|
|
|
execMOVI();
|
2017-05-14 21:10:58 +01:00
|
|
|
regs[IP] += MOVI_SIZE;
|
2017-05-17 17:32:05 +01:00
|
|
|
} else if (opcode == OPS[MOVR]) {
|
2017-05-17 17:58:00 +01:00
|
|
|
execMOVR();
|
2017-05-14 21:10:58 +01:00
|
|
|
regs[IP] += MOVR_SIZE;
|
2017-05-17 17:32:05 +01:00
|
|
|
} else if (opcode == OPS[LOAD]) {
|
2017-05-17 17:58:00 +01:00
|
|
|
execLOAD();
|
2017-05-17 17:32:05 +01:00
|
|
|
regs[IP] += LOAD_SIZE;
|
|
|
|
} else if (opcode == OPS[STOR]) {
|
2017-05-17 17:58:00 +01:00
|
|
|
execSTOR();
|
2017-05-17 17:32:05 +01:00
|
|
|
regs[IP] += STOR_SIZE;
|
|
|
|
} else if (opcode == OPS[ADDI]) {
|
2017-05-17 17:58:00 +01:00
|
|
|
execADDI();
|
2017-05-14 21:10:58 +01:00
|
|
|
regs[IP] += ADDI_SIZE;
|
2017-05-17 18:58:00 +01:00
|
|
|
} else if (opcode == OPS[ADDR]) {
|
|
|
|
execADDR();
|
|
|
|
regs[IP] += ADDR_SIZE;
|
|
|
|
} else if (opcode == OPS[SUBI]) {
|
|
|
|
execSUBI();
|
|
|
|
regs[IP] += SUBI_SIZE;
|
|
|
|
} else if (opcode == OPS[SUBR]) {
|
|
|
|
execSUBR();
|
|
|
|
regs[IP] += SUBR_SIZE;
|
2017-05-18 16:28:10 +01:00
|
|
|
} else if (opcode == OPS[ANDB]) {
|
|
|
|
execANDB();
|
|
|
|
regs[IP] += ANDB_SIZE;
|
|
|
|
} else if (opcode == OPS[ANDW]) {
|
|
|
|
execANDW();
|
|
|
|
regs[IP] += ANDW_SIZE;
|
|
|
|
} else if (opcode == OPS[ANDR]) {
|
|
|
|
execANDR();
|
|
|
|
regs[IP] += ANDR_SIZE;
|
|
|
|
} else if (opcode == OPS[YORB]) {
|
|
|
|
execYORB();
|
|
|
|
regs[IP] += YORB_SIZE;
|
|
|
|
} else if (opcode == OPS[YORW]) {
|
|
|
|
execYORW();
|
|
|
|
regs[IP] += YORW_SIZE;
|
|
|
|
} else if (opcode == OPS[YORR]) {
|
|
|
|
execYORR();
|
|
|
|
regs[IP] += YORR_SIZE;
|
2017-05-17 18:58:00 +01:00
|
|
|
} else if (opcode == OPS[XORB]) {
|
|
|
|
execXORB();
|
|
|
|
regs[IP] += XORB_SIZE;
|
|
|
|
} else if (opcode == OPS[XORW]) {
|
|
|
|
execXORW();
|
|
|
|
regs[IP] += XORW_SIZE;
|
|
|
|
} else if (opcode == OPS[XORR]) {
|
|
|
|
execXORR();
|
|
|
|
regs[IP] += XORR_SIZE;
|
|
|
|
} else if (opcode == OPS[NOTR]) {
|
|
|
|
execNOTR();
|
|
|
|
regs[IP] += NOTR_SIZE;
|
|
|
|
} else if (opcode == OPS[MULI]) {
|
|
|
|
execMULI();
|
|
|
|
regs[IP] += MULI_SIZE;
|
|
|
|
} else if (opcode == OPS[MULR]) {
|
|
|
|
execMULR();
|
|
|
|
regs[IP] += MULR_SIZE;
|
|
|
|
} else if (opcode == OPS[DIVI]) {
|
|
|
|
execDIVI();
|
|
|
|
regs[IP] += DIVI_SIZE;
|
|
|
|
} else if (opcode == OPS[PUSH]) {
|
|
|
|
execPUSH();
|
|
|
|
regs[IP] += PUSH_SIZE;
|
|
|
|
} else if (opcode == OPS[POOP]) {
|
|
|
|
execPOOP();
|
|
|
|
regs[IP] += POOP_SIZE;
|
|
|
|
} else if (opcode == OPS[CMPI]) {
|
|
|
|
execCMPI();
|
|
|
|
regs[IP] += CMPI_SIZE;
|
|
|
|
} else if (opcode == OPS[CMPR]) {
|
|
|
|
execCMPR();
|
|
|
|
regs[IP] += CMPR_SIZE;
|
2017-05-18 14:41:05 +01:00
|
|
|
} else if (opcode == OPS[JMPI]) {
|
|
|
|
execJMPI();
|
|
|
|
} else if (opcode == OPS[JMPR]) {
|
|
|
|
execJMPR();
|
2017-05-18 16:28:10 +01:00
|
|
|
} else if (opcode == OPS[JPAI]) {
|
|
|
|
if (!execJPAI()) {
|
|
|
|
regs[IP] += JPAI_SIZE;
|
|
|
|
}
|
|
|
|
} else if (opcode == OPS[JPAR]) {
|
|
|
|
if (!execJPAR()) {
|
|
|
|
regs[IP] += JPAR_SIZE;
|
|
|
|
}
|
|
|
|
} else if (opcode == OPS[JPBI]) {
|
|
|
|
if (!execJPBI()) {
|
|
|
|
regs[IP] += JPBI_SIZE;
|
|
|
|
}
|
|
|
|
} else if (opcode == OPS[JPBR]) {
|
|
|
|
if (!execJPBR()) {
|
|
|
|
regs[IP] += JPBR_SIZE;
|
|
|
|
}
|
|
|
|
} else if (opcode == OPS[JPEI]) {
|
|
|
|
if (!execJPEI()) {
|
|
|
|
regs[IP] += JPEI_SIZE;
|
|
|
|
}
|
|
|
|
} else if (opcode == OPS[JPER]) {
|
|
|
|
if (!execJPER()) {
|
|
|
|
regs[IP] += JPER_SIZE;
|
|
|
|
}
|
|
|
|
} else if (opcode == OPS[JPNI]) {
|
|
|
|
if (!execJPNI()) {
|
|
|
|
regs[IP] += JPNI_SIZE;
|
|
|
|
}
|
|
|
|
} else if (opcode == OPS[JPNR]) {
|
|
|
|
if (!execJPNR()) {
|
|
|
|
regs[IP] += JPNR_SIZE;
|
|
|
|
}
|
2017-05-17 18:58:00 +01:00
|
|
|
} else if (opcode == OPS[GRMN]) {
|
|
|
|
execGRMN();
|
|
|
|
regs[IP] += GRMN_SIZE;
|
2017-05-17 17:32:05 +01:00
|
|
|
} else if (opcode == OPS[SHIT]) {
|
2017-05-18 14:41:05 +01:00
|
|
|
DBG_INFO(("Halting.\n"));
|
2017-05-14 21:10:58 +01:00
|
|
|
finished = true;
|
2017-05-17 18:58:00 +01:00
|
|
|
} else if (opcode == OPS[NOPE]) {
|
|
|
|
regs[IP] += NOPE_SIZE;
|
2017-05-17 17:32:05 +01:00
|
|
|
} else {
|
|
|
|
DBG_ERROR(("WAT\n"));
|
2017-05-14 22:01:11 +01:00
|
|
|
finished = true;
|
2017-05-14 21:10:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|