243 lines
4.5 KiB
C++
243 lines
4.5 KiB
C++
#include "vm.h"
|
|
#include "debug.h"
|
|
#include "vmas.h"
|
|
#include <string.h>
|
|
|
|
/*
|
|
DBG UTILS
|
|
*/
|
|
|
|
uint8_t *VM::reg_name(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_INFO(("VM Status:\n"));
|
|
DBG_INFO(("~~~~~~~~~~\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_INFO(("~~~~~~~~~~\n"));
|
|
#endif
|
|
return;
|
|
}
|
|
/*
|
|
CONSTRUCTORS
|
|
*/
|
|
VM::VM() {
|
|
DBG_INFO(("Creating VM without code.\n"));
|
|
as.allocate();
|
|
init_regs();
|
|
}
|
|
|
|
VM::VM(uint8_t *code, uint32_t codesize) {
|
|
DBG_INFO(("Creating VM with code.\n"));
|
|
if (as.allocate()) {
|
|
as.insCode(code, codesize);
|
|
}
|
|
init_regs();
|
|
}
|
|
|
|
void VM::init_regs(void) {
|
|
uint8_t i;
|
|
|
|
for (i = R0; i <= SP; i++) {
|
|
this->regs[i] = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
INSTRUCTIONS IMPLEMENTATIONS
|
|
*/
|
|
|
|
bool VM::exec_movi(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", reg_name(dst), imm));
|
|
if (dst == IP) {
|
|
DBG_ERROR(("Can't MOVI to IP!\n"));
|
|
return false;
|
|
}
|
|
regs[dst] = imm;
|
|
return true;
|
|
}
|
|
|
|
bool VM::exec_movr(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", reg_name(dst), reg_name(src)));
|
|
if (dst == IP || src == IP) {
|
|
DBG_ERROR(("Can't MOVR IP!\n"));
|
|
return false;
|
|
}
|
|
regs[dst] = regs[src];
|
|
return true;
|
|
}
|
|
|
|
bool VM::exec_getm(void) {
|
|
/*
|
|
GETM 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(("GETM %s, 0x%x\n", reg_name(dst), src));
|
|
regs[dst] = *((uint16_t *)&as.data[src]);
|
|
return true;
|
|
}
|
|
|
|
bool VM::exec_putm(void) {
|
|
/*
|
|
PUTM 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(("PUTM 0x%x 0x%x\n", dst, src));
|
|
*((uint16_t *)&as.data[dst]) = regs[src];
|
|
return true;
|
|
}
|
|
|
|
bool VM::exec_addi(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 0x%x 0x%x\n", dst, src));
|
|
regs[dst] += src;
|
|
return true;
|
|
}
|
|
|
|
void VM::run(void) {
|
|
uint8_t opcode;
|
|
bool finished = false;
|
|
while (!finished) {
|
|
opcode = (uint8_t)as.code[regs[IP]];
|
|
switch (opcode) {
|
|
case MOVI:
|
|
exec_movi();
|
|
regs[IP] += MOVI_SIZE;
|
|
break;
|
|
case MOVR:
|
|
exec_movr();
|
|
regs[IP] += MOVR_SIZE;
|
|
break;
|
|
case GETM:
|
|
exec_getm();
|
|
regs[IP] += GETM_SIZE;
|
|
break;
|
|
case PUTM:
|
|
exec_putm();
|
|
regs[IP] += PUTM_SIZE;
|
|
break;
|
|
case ADDI:
|
|
exec_addi();
|
|
regs[IP] += ADDI_SIZE;
|
|
break;
|
|
case HALT:
|
|
DBG_INFO(("HALT\n"));
|
|
finished = true;
|
|
break;
|
|
default:
|
|
DBG_INFO(("WAT: 0x%x\n", opcode));
|
|
finished = true;
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
} |