Virtual machine
This commit is contained in:
parent
ba822dcbd2
commit
cd6c193e81
11
src/tests/VirtualMachineTest.cpp
Normal file
11
src/tests/VirtualMachineTest.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "virtualmachine/VirtualMachine.h"
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
vm::VirtualMachine * vm = new vm::VirtualMachine(2);
|
||||||
|
vm->LoadProgram("test.qvm");
|
||||||
|
vm->Call(0/*, 0, 88, 12*/);
|
||||||
|
std::cout << "Return value: " << vm->Pop<vm::uint4_t>() << std::endl;
|
||||||
|
//vm->Run();
|
||||||
|
}
|
69
src/virtualmachine/Exceptions.h
Normal file
69
src/virtualmachine/Exceptions.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cstring>
|
||||||
|
#include "Format.h"
|
||||||
|
|
||||||
|
namespace vm
|
||||||
|
{
|
||||||
|
class RuntimeException: public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RuntimeException() {}
|
||||||
|
const char * what() const throw()
|
||||||
|
{
|
||||||
|
return "VirtualMachine runtime exception";
|
||||||
|
}
|
||||||
|
~RuntimeException() throw() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class StackOverflowException: public RuntimeException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StackOverflowException() {}
|
||||||
|
const char * what() const throw()
|
||||||
|
{
|
||||||
|
return "VirtualMachine Stack overflow";
|
||||||
|
}
|
||||||
|
~StackOverflowException() throw() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class StackUnderflowException: public RuntimeException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StackUnderflowException() {}
|
||||||
|
const char * what() const throw()
|
||||||
|
{
|
||||||
|
return "VirtualMachine Stack underflow";
|
||||||
|
}
|
||||||
|
~StackUnderflowException() throw() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class AccessViolationException: public RuntimeException
|
||||||
|
{
|
||||||
|
int address;
|
||||||
|
char * _what;
|
||||||
|
public:
|
||||||
|
AccessViolationException(int address = 0) : address(address)
|
||||||
|
{
|
||||||
|
_what = strdup(std::string("VirtualMachine Access violation at "+format::NumberToString<int>(address)).c_str());
|
||||||
|
}
|
||||||
|
const char * what() const throw()
|
||||||
|
{
|
||||||
|
if(address)
|
||||||
|
return _what;
|
||||||
|
return "VirtualMachine Access violation";
|
||||||
|
}
|
||||||
|
~AccessViolationException() throw() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class OutOfMemoryException: public RuntimeException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OutOfMemoryException() {}
|
||||||
|
const char * what() const throw()
|
||||||
|
{
|
||||||
|
return "VirtualMachine Out of memory";
|
||||||
|
}
|
||||||
|
~OutOfMemoryException() throw() {};
|
||||||
|
};
|
||||||
|
}
|
60
src/virtualmachine/OpCodes.inl
Normal file
60
src/virtualmachine/OpCodes.inl
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
OPDEF(UNDEF)
|
||||||
|
OPDEF(IGNORE) /* no-op */
|
||||||
|
OPDEF(BREAK) /* ??? */
|
||||||
|
OPDEF(ENTER) /* Begin subroutine. */
|
||||||
|
OPDEF(LEAVE) /* End subroutine. */
|
||||||
|
OPDEF(CALL) /* Call subroutine. */
|
||||||
|
OPDEF(PUSH) /* push to stack. */
|
||||||
|
OPDEF(POP) /* discard top-of-stack. */
|
||||||
|
OPDEF(CONST) /* load constant to stack. */
|
||||||
|
OPDEF(LOCAL) /* get local variable. */
|
||||||
|
OPDEF(JUMP) /* unconditional jump. */
|
||||||
|
OPDEF(EQ) /* compare integers, jump if equal. */
|
||||||
|
OPDEF(NE) /* compare integers, jump if not equal. */
|
||||||
|
OPDEF(LTI) /* compare integers, jump if less-than. */
|
||||||
|
OPDEF(LEI) /* compare integers, jump if less-than-or-equal. */
|
||||||
|
OPDEF(GTI) /* compare integers, jump if greater-than. */
|
||||||
|
OPDEF(GEI) /* compare integers, jump if greater-than-or-equal. */
|
||||||
|
OPDEF(LTU) /* compare unsigned integers, jump if less-than */
|
||||||
|
OPDEF(LEU) /* compare unsigned integers, jump if less-than-or-equal */
|
||||||
|
OPDEF(GTU) /* compare unsigned integers, jump if greater-than */
|
||||||
|
OPDEF(GEU) /* compare unsigned integers, jump if greater-than-or-equal */
|
||||||
|
OPDEF(EQF) /* compare floats, jump if equal */
|
||||||
|
OPDEF(NEF) /* compare floats, jump if not-equal */
|
||||||
|
OPDEF(LTF) /* compare floats, jump if less-than */
|
||||||
|
OPDEF(LEF) /* compare floats, jump if less-than-or-equal */
|
||||||
|
OPDEF(GTF) /* compare floats, jump if greater-than */
|
||||||
|
OPDEF(GEF) /* compare floats, jump if greater-than-or-equal */
|
||||||
|
OPDEF(LOAD1) /* load 1-byte from memory */
|
||||||
|
OPDEF(LOAD2) /* load 2-byte from memory */
|
||||||
|
OPDEF(LOAD4) /* load 4-byte from memory */
|
||||||
|
OPDEF(STORE1) /* store 1-byte to memory */
|
||||||
|
OPDEF(STORE2) /* store 2-byte to memory */
|
||||||
|
OPDEF(STORE4) /* store 4-byte to memory */
|
||||||
|
OPDEF(ARG) /* marshal argument */
|
||||||
|
OPDEF(BLOCK_COPY) /* block copy... */
|
||||||
|
OPDEF(SEX8) /* Pedophilia */
|
||||||
|
OPDEF(SEX16) /* Sign-Extend 16-bit */
|
||||||
|
OPDEF(NEGI) /* Negate integer. */
|
||||||
|
OPDEF(ADD) /* Add integers (two's complement). */
|
||||||
|
OPDEF(SUB) /* Subtract integers (two's complement). */
|
||||||
|
OPDEF(DIVI) /* Divide signed integers. */
|
||||||
|
OPDEF(DIVU) /* Divide unsigned integers. */
|
||||||
|
OPDEF(MODI) /* Modulus (signed). */
|
||||||
|
OPDEF(MODU) /* Modulus (unsigned). */
|
||||||
|
OPDEF(MULI) /* Multiply signed integers. */
|
||||||
|
OPDEF(MULU) /* Multiply unsigned integers. */
|
||||||
|
OPDEF(BAND) /* Bitwise AND */
|
||||||
|
OPDEF(BOR) /* Bitwise OR */
|
||||||
|
OPDEF(BXOR) /* Bitwise eXclusive-OR */
|
||||||
|
OPDEF(BCOM) /* Bitwise COMplement */
|
||||||
|
OPDEF(LSH) /* Left-shift */
|
||||||
|
OPDEF(RSHI) /* Right-shift (algebraic; preserve sign) */
|
||||||
|
OPDEF(RSHU) /* Right-shift (bitwise; ignore sign) */
|
||||||
|
OPDEF(NEGF) /* Negate float */
|
||||||
|
OPDEF(ADDF) /* Add floats */
|
||||||
|
OPDEF(SUBF) /* Subtract floats */
|
||||||
|
OPDEF(DIVF) /* Divide floats */
|
||||||
|
OPDEF(MULF) /* Multiply floats */
|
||||||
|
OPDEF(CVIF) /* Convert to integer from float */
|
||||||
|
OPDEF(CVFI) /* Convert to float from integer */
|
57
src/virtualmachine/Traps.inl
Normal file
57
src/virtualmachine/Traps.inl
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
TRAPDEF(-1, Print)
|
||||||
|
TRAPDEF(-2, Error)
|
||||||
|
/*MAPTRAP(-3, Milliseconds)
|
||||||
|
MAPTRAP(-4, Cvar_Register)
|
||||||
|
MAPTRAP(-5, Cvar_Update)
|
||||||
|
MAPTRAP(-6, Cvar_Set)
|
||||||
|
MAPTRAP(-7, Cvar_VariableIntegerValue)
|
||||||
|
MAPTRAP(-8, Cvar_VariableStringBuffer)
|
||||||
|
MAPTRAP(-9, Argc)
|
||||||
|
MAPTRAP(-10, Argv)
|
||||||
|
MAPTRAP(-11, FS_FOpenFile)
|
||||||
|
MAPTRAP(-12, FS_Read)
|
||||||
|
MAPTRAP(-13, FS_Write)
|
||||||
|
MAPTRAP(-14, FS_FCloseFile)
|
||||||
|
MAPTRAP(-15, SendConsoleCommand)
|
||||||
|
MAPTRAP(-16, LocateGameData)
|
||||||
|
MAPTRAP(-17, DropClient)
|
||||||
|
MAPTRAP(-18, SendServerCommand)
|
||||||
|
MAPTRAP(-19, SetConfigstring)
|
||||||
|
MAPTRAP(-20, GetConfigstring)
|
||||||
|
MAPTRAP(-21, GetUserinfo)
|
||||||
|
MAPTRAP(-22, SetUserinfo)
|
||||||
|
MAPTRAP(-23, GetServerinfo)
|
||||||
|
MAPTRAP(-24, SetBrushModel)
|
||||||
|
MAPTRAP(-25, Trace)
|
||||||
|
MAPTRAP(-26, PointContents)
|
||||||
|
MAPTRAP(-27, InPVS)
|
||||||
|
MAPTRAP(-28, InPVSIgnorePortals)
|
||||||
|
MAPTRAP(-29, AdjustAreaPortalState)
|
||||||
|
MAPTRAP(-30, AreasConnected)
|
||||||
|
MAPTRAP(-31, LinkEntity)
|
||||||
|
MAPTRAP(-32, UnlinkEntity)
|
||||||
|
MAPTRAP(-33, EntitiesInBox)
|
||||||
|
MAPTRAP(-34, EntityContact)
|
||||||
|
MAPTRAP(-35, BotAllocateClient)
|
||||||
|
MAPTRAP(-36, BotFreeClient)
|
||||||
|
MAPTRAP(-37, GetUsercmd)
|
||||||
|
MAPTRAP(-38, GetEntityToken)
|
||||||
|
MAPTRAP(-39, FS_GetFileList)
|
||||||
|
MAPTRAP(-40, DebugPolygonCreate)
|
||||||
|
MAPTRAP(-41, DebugPolygonDelete)
|
||||||
|
MAPTRAP(-42, RealTime)
|
||||||
|
MAPTRAP(-43, SnapVector)
|
||||||
|
MAPTRAP(-44, TraceCapsule)
|
||||||
|
MAPTRAP(-45, EntityContactCapsule)
|
||||||
|
MAPTRAP(-46, FS_Seek)
|
||||||
|
MAPTRAP(-101, memset)
|
||||||
|
MAPTRAP(-102, memcpy)
|
||||||
|
MAPTRAP(-103, strncpy)
|
||||||
|
MAPTRAP(-104, sin)
|
||||||
|
MAPTRAP(-105, cos)
|
||||||
|
MAPTRAP(-106, atan2)
|
||||||
|
MAPTRAP(-107, sqrt)
|
||||||
|
MAPTRAP(-111, floor)
|
||||||
|
MAPTRAP(-112, ceil)
|
||||||
|
MAPTRAP(-113, testPrintInt)
|
||||||
|
MAPTRAP(-114, testPrintFloat)*/
|
664
src/virtualmachine/VirtualMachine.cpp
Normal file
664
src/virtualmachine/VirtualMachine.cpp
Normal file
@ -0,0 +1,664 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "VirtualMachine.h"
|
||||||
|
|
||||||
|
namespace vm
|
||||||
|
{
|
||||||
|
|
||||||
|
VirtualMachine::VirtualMachine(int hunkMbytes):
|
||||||
|
bigEndian(false),
|
||||||
|
hunk(NULL),
|
||||||
|
hunkSize(1048576),
|
||||||
|
hunkFree(0),
|
||||||
|
rom(NULL),
|
||||||
|
romSize(0),
|
||||||
|
ram(NULL),
|
||||||
|
ramSize(0),
|
||||||
|
dataStack(0),
|
||||||
|
returnStack(0),
|
||||||
|
DP(0), /* Datastack pointer. */
|
||||||
|
RP(0), /* Return stack pointer. */
|
||||||
|
PC(0),
|
||||||
|
cm(0),
|
||||||
|
cycles(0)
|
||||||
|
{
|
||||||
|
hunk = new char[hunkSize];
|
||||||
|
std::fill(hunk, hunk+hunkSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualMachine::~VirtualMachine()
|
||||||
|
{
|
||||||
|
delete[] hunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define crumb printf
|
||||||
|
|
||||||
|
int VirtualMachine::opcodeParameterSize(int opcode)
|
||||||
|
{
|
||||||
|
#define OP(n) OP##n
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case OP(ENTER):
|
||||||
|
case OP(LEAVE):
|
||||||
|
case OP(LOCAL):
|
||||||
|
case OP(EQ):
|
||||||
|
case OP(NE):
|
||||||
|
case OP(LTI):
|
||||||
|
case OP(LEI):
|
||||||
|
case OP(GTI):
|
||||||
|
case OP(GEI):
|
||||||
|
case OP(LTU):
|
||||||
|
case OP(LEU):
|
||||||
|
case OP(GTU):
|
||||||
|
case OP(GEU):
|
||||||
|
case OP(EQF):
|
||||||
|
case OP(NEF):
|
||||||
|
case OP(LTF):
|
||||||
|
case OP(LEF):
|
||||||
|
case OP(GTF):
|
||||||
|
case OP(GEF):
|
||||||
|
case OP(CONST):
|
||||||
|
case OP(BLOCK_COPY):
|
||||||
|
return sizeof(uint4_t);
|
||||||
|
break;
|
||||||
|
case OP(ARG):
|
||||||
|
return sizeof(uint1_t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#undef OP
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read one octet from file. */
|
||||||
|
int VirtualMachine::readByte(FILE *qvmfile)
|
||||||
|
{
|
||||||
|
int o;
|
||||||
|
o = fgetc(qvmfile);
|
||||||
|
if (o < 0) o = 0; /* EOF (hack) */
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read little-endian 32-bit integer from file. */
|
||||||
|
int VirtualMachine::readInt(FILE *qvmfile)
|
||||||
|
{
|
||||||
|
int a, b, c, d, n;
|
||||||
|
|
||||||
|
a = readByte(qvmfile);
|
||||||
|
b = readByte(qvmfile);
|
||||||
|
c = readByte(qvmfile);
|
||||||
|
d = readByte(qvmfile);
|
||||||
|
n = (a) | (b << 8) | (c << 16) | (d << 24);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VirtualMachine::LoadProgram(char * filename)
|
||||||
|
{
|
||||||
|
FILE * qvmfile = fopen(filename, "rb");
|
||||||
|
qvm_header_t qvminfo;
|
||||||
|
int i, n;
|
||||||
|
uint1_t x[4];
|
||||||
|
word w;
|
||||||
|
|
||||||
|
crumb("Loading file...\n");
|
||||||
|
qvminfo.magic = readInt(qvmfile); /* magic. */
|
||||||
|
if (qvminfo.magic != QVM_MAGIC)
|
||||||
|
{
|
||||||
|
crumb("Invalid magic");
|
||||||
|
//q3vm_error("Does not appear to be a QVM file.");
|
||||||
|
/* XXX: option to force continue. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
crumb("Magic OK\n");
|
||||||
|
/* variable-length instructions mean instruction count != code length */
|
||||||
|
qvminfo.inscount = readInt(qvmfile);
|
||||||
|
qvminfo.codeoff = readInt(qvmfile);
|
||||||
|
qvminfo.codelen = readInt(qvmfile);
|
||||||
|
qvminfo.dataoff = readInt(qvmfile);
|
||||||
|
qvminfo.datalen = readInt(qvmfile);
|
||||||
|
qvminfo.litlen = readInt(qvmfile);
|
||||||
|
qvminfo.bsslen = readInt(qvmfile);
|
||||||
|
|
||||||
|
/* Code segment should follow... */
|
||||||
|
/* XXX: use fseek with SEEK_CUR? */
|
||||||
|
crumb("Searching for .code @ %d from %d\n", qvminfo.codeoff, ftell(qvmfile));
|
||||||
|
// rom = (q3vm_rom_t*)(hunk); /* ROM-in-hunk */
|
||||||
|
rom = (Instruction*)calloc(qvminfo.inscount, sizeof(rom[0]));
|
||||||
|
while (ftell(qvmfile) < qvminfo.codeoff)
|
||||||
|
readByte(qvmfile);
|
||||||
|
while (romSize < qvminfo.inscount)
|
||||||
|
{
|
||||||
|
n = readByte(qvmfile);
|
||||||
|
w.int4 = 0;
|
||||||
|
if ((i = opcodeParameterSize(n)))
|
||||||
|
{
|
||||||
|
x[0] = x[1] = x[2] = x[3] = 0;
|
||||||
|
fread(&x, 1, i, qvmfile);
|
||||||
|
w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
|
||||||
|
}
|
||||||
|
rom[romSize].Operation = n;
|
||||||
|
rom[romSize].Parameter = w;
|
||||||
|
romSize++;
|
||||||
|
}
|
||||||
|
crumb("After loading code: at %d, should be %d\n", ftell(qvmfile), qvminfo.codeoff + qvminfo.codelen);
|
||||||
|
|
||||||
|
/* Then data segment. */
|
||||||
|
// ram = hunk + ((romlen + 3) & ~3); /* RAM-in-hunk */
|
||||||
|
ram = hunk;
|
||||||
|
crumb("Searching for .data @ %d from %d\n", qvminfo.dataoff, ftell(qvmfile));
|
||||||
|
while (ftell(qvmfile) < qvminfo.dataoff)
|
||||||
|
readByte(qvmfile);
|
||||||
|
for (n = 0; n < (qvminfo.datalen / sizeof(uint1_t)); n++)
|
||||||
|
{
|
||||||
|
i = fread(&x, 1, sizeof(x), qvmfile);
|
||||||
|
w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
|
||||||
|
*((word*)(ram + ramSize)) = w;
|
||||||
|
ramSize += sizeof(word);
|
||||||
|
}
|
||||||
|
/* lit segment follows data segment. */
|
||||||
|
/* Assembler should have already padded properly. */
|
||||||
|
crumb("Loading .lit\n");
|
||||||
|
for (n = 0; n < (qvminfo.litlen / sizeof(uint1_t)); n++)
|
||||||
|
{
|
||||||
|
i = fread(&x, 1, sizeof(x), qvmfile);
|
||||||
|
memcpy(&(w.uint1), &x, sizeof(x)); /* no byte-swapping. */
|
||||||
|
*((word*)(ram + ramSize)) = w;
|
||||||
|
ramSize += sizeof(word);
|
||||||
|
}
|
||||||
|
/* bss segment. */
|
||||||
|
crumb("Allocating .bss %d (%X) bytes\n", qvminfo.bsslen, qvminfo.bsslen);
|
||||||
|
/* huge empty chunk. */
|
||||||
|
ramSize += qvminfo.bsslen;
|
||||||
|
|
||||||
|
hunkFree = hunkSize - ((ramSize * sizeof(uint1_t)) + 4);
|
||||||
|
|
||||||
|
crumb("VM hunk has %d of %d bytes free (RAM = %d B).\n", hunkFree, hunkSize, ramSize);
|
||||||
|
if (ramSize > hunkSize)
|
||||||
|
{
|
||||||
|
throw OutOfMemoryException();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up stack. */
|
||||||
|
{
|
||||||
|
int stacksize = 0x10000;
|
||||||
|
returnStack = ramSize;
|
||||||
|
dataStack = ramSize - (stacksize / 2);
|
||||||
|
RP = returnStack;
|
||||||
|
DP = dataStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up PC for return-to-termination. */
|
||||||
|
PC = romSize + 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VirtualMachine::Call(int address)
|
||||||
|
{
|
||||||
|
word w;
|
||||||
|
int i, argCount = 13;
|
||||||
|
|
||||||
|
/* Set up call. */
|
||||||
|
opPUSH(w);
|
||||||
|
crumb("Starting with PC=%d, DP=%d, RP=%d to %d\n", PC, DP, RP, address);
|
||||||
|
w.int4 = (argCount + 2) * sizeof(word);
|
||||||
|
opENTER(w);
|
||||||
|
i = 8;
|
||||||
|
/**w.int4 = arg0; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg1; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg2; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg3; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg4; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg5; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg6; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg7; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg8; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg9; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg10; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg11; Marshal(i, w); i += 4;
|
||||||
|
w.int4 = arg12; Marshal(i, w); i += 4;*/
|
||||||
|
w.int4 = address;
|
||||||
|
Push(w);
|
||||||
|
opCALL(w);
|
||||||
|
printf("Upon running PC=%d, DP=%d, RP=%d\n", PC, DP, RP);
|
||||||
|
Run();
|
||||||
|
printf("At finish PC=%d, DP=%d, RP=%d\n", PC, DP, RP);
|
||||||
|
w.int4 = (argCount + 2) * sizeof(word);
|
||||||
|
opLEAVE(w);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VirtualMachine::Run()
|
||||||
|
{
|
||||||
|
bool running = true;
|
||||||
|
int operation;
|
||||||
|
word parameter;
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
cycles++;
|
||||||
|
if(PC > romSize)
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (PC < 0)
|
||||||
|
{
|
||||||
|
syscall(PC);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
operation = rom[PC].Operation;
|
||||||
|
parameter = rom[PC].Parameter;
|
||||||
|
PC++;
|
||||||
|
(this->*operations[operation])(parameter);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int VirtualMachine::syscall(int trap)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
word w;
|
||||||
|
|
||||||
|
retval = 0;
|
||||||
|
switch (trap)
|
||||||
|
{
|
||||||
|
#define TRAPDEF(n, f) case n: retval = trap##f(); break;
|
||||||
|
#include "Traps.inl"
|
||||||
|
#undef TRAPDEF
|
||||||
|
}
|
||||||
|
|
||||||
|
w = Pop();
|
||||||
|
PC = w.int4;
|
||||||
|
w.int4 = retval;
|
||||||
|
Push(w);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ARG(n) (Get<int4_t>(RP + ((2 + n) * sizeof(word))))
|
||||||
|
|
||||||
|
#define TRAPDEF(f) int VirtualMachine::trap##f()
|
||||||
|
|
||||||
|
TRAPDEF(Print)
|
||||||
|
{
|
||||||
|
char *text;
|
||||||
|
|
||||||
|
//crumb("SYSCALL Print [%d]\n", ARG(0));
|
||||||
|
text = (char*)(ram) + ARG(0);
|
||||||
|
//crumb("PRINTING [%s]\n", text);
|
||||||
|
printf("%s", text);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TRAPDEF(Error)
|
||||||
|
{
|
||||||
|
char *msg;
|
||||||
|
|
||||||
|
msg = (char*)(ram) + ARG(0);
|
||||||
|
printf("%s", msg);
|
||||||
|
PC = romSize + 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPDEF(n) &VirtualMachine::op##n,
|
||||||
|
OperationFunction VirtualMachine::operations[] =
|
||||||
|
{
|
||||||
|
#include "OpCodes.inl"
|
||||||
|
};
|
||||||
|
#undef OPDEF
|
||||||
|
|
||||||
|
#define OPDEF(n) int VirtualMachine::op##n(word parameter)
|
||||||
|
|
||||||
|
#define R0 (r[0])
|
||||||
|
#define R1 (r[1])
|
||||||
|
#define R2 (r[2])
|
||||||
|
|
||||||
|
|
||||||
|
OPDEF(UNDEF)
|
||||||
|
{
|
||||||
|
/* Die horribly. */
|
||||||
|
throw RuntimeException();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(IGNORE)
|
||||||
|
{
|
||||||
|
/* NOP */
|
||||||
|
throw RuntimeException();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(BREAK)
|
||||||
|
{
|
||||||
|
/* Usage never spotted. */
|
||||||
|
/* Die horribly? */
|
||||||
|
throw RuntimeException();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Stack on entering...
|
||||||
|
|
||||||
|
no locals: ENTER 8
|
||||||
|
1 words locals: ENTER 16
|
||||||
|
2 words locals: ENTER 20
|
||||||
|
3 words locals: ENTER 24
|
||||||
|
etc.
|
||||||
|
|
||||||
|
address of argument:
|
||||||
|
ADDRFP4 v => OP_LOCAL (16 + currentLocals + currentArgs + v)
|
||||||
|
address of local:
|
||||||
|
ADDRLP4 v => OP_LOCAL (8 + currentArgs + v)
|
||||||
|
|
||||||
|
RP [ ] ??? (oldPC?)
|
||||||
|
[ ] ???
|
||||||
|
[ ] \
|
||||||
|
... > locals (args marshalling)
|
||||||
|
[ ] /
|
||||||
|
[ ] \
|
||||||
|
... > locals
|
||||||
|
[ ] / (ADDRLP4 v => OP_LOCAL (8 + currentArgs + v))
|
||||||
|
(oldRP?) [ ] ???
|
||||||
|
[ ] ???
|
||||||
|
[ ] (my args?)
|
||||||
|
...
|
||||||
|
[ ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
OPDEF(ENTER) /* ??? */
|
||||||
|
{
|
||||||
|
while (parameter.int4 > (2 * sizeof(word)))
|
||||||
|
{
|
||||||
|
RPush<int4_t>(0); /* init zero */
|
||||||
|
parameter.int4 -= sizeof(word);
|
||||||
|
}
|
||||||
|
RPush(Pop()); //Program Counter
|
||||||
|
RPush<int4_t>(0); //Unknown
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(LEAVE) /* ??? */
|
||||||
|
{
|
||||||
|
RPop(); //Unknown
|
||||||
|
parameter.int4 -= sizeof(word);
|
||||||
|
PC = RPop<int4_t>(); //Program counter
|
||||||
|
parameter.int4 -= sizeof(word);
|
||||||
|
while (parameter.int4 > 0)
|
||||||
|
{
|
||||||
|
RPop();
|
||||||
|
parameter.int4 -= sizeof(word);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(CALL) /* Call subroutine. */
|
||||||
|
{
|
||||||
|
R0 = Pop();
|
||||||
|
Push<int4_t>(PC);
|
||||||
|
PC = R0.int4;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(PUSH) /* [DP] <- 0; DP++ */
|
||||||
|
{
|
||||||
|
Push(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(POP) /* DP-- */
|
||||||
|
{
|
||||||
|
Pop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(CONST) /* [DP] <- parm; DP++ */
|
||||||
|
{
|
||||||
|
Push(parameter);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(LOCAL) /* [DP] <- [RP-n] */
|
||||||
|
{
|
||||||
|
Push<int4_t>(RP + parameter.int4);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(JUMP) /* PC <- [DP] */
|
||||||
|
{
|
||||||
|
PC = Pop<int4_t>();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CMP(type, op) \
|
||||||
|
{ \
|
||||||
|
R0 = Pop(); \
|
||||||
|
cm = (Pop<type##_t>() op R0.type); \
|
||||||
|
if (cm) \
|
||||||
|
PC = parameter.uint4; \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(EQ) /* if [DP] == [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(int4, ==)
|
||||||
|
|
||||||
|
OPDEF(NE) /* if [DP] == [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(int4, !=)
|
||||||
|
|
||||||
|
OPDEF(LTI) /* if [DP] < [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(int4, <)
|
||||||
|
|
||||||
|
OPDEF(LEI) /* if [DP] <= [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(int4, <=)
|
||||||
|
|
||||||
|
OPDEF(GTI) /* if [DP] > [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(int4, >)
|
||||||
|
|
||||||
|
OPDEF(GEI) /* if [DP] >= [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(int4, >=)
|
||||||
|
|
||||||
|
OPDEF(LTU) /* if [DP] < [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(uint4, <)
|
||||||
|
|
||||||
|
OPDEF(LEU) /* if [DP] <= [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(uint4, <=)
|
||||||
|
|
||||||
|
OPDEF(GTU) /* if [DP] > [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(uint4, >)
|
||||||
|
|
||||||
|
OPDEF(GEU) /* if [DP] >= [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(uint4, >=)
|
||||||
|
|
||||||
|
OPDEF(EQF) /* if [DP] == [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(float4, ==)
|
||||||
|
|
||||||
|
OPDEF(NEF) /* if [DP] != [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(float4, !=)
|
||||||
|
|
||||||
|
OPDEF(LTF) /* if [DP] < [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(float4, <)
|
||||||
|
|
||||||
|
OPDEF(LEF) /* if [DP] <= [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(float4, <=)
|
||||||
|
|
||||||
|
OPDEF(GTF) /* if [DP] > [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(float4, >)
|
||||||
|
|
||||||
|
OPDEF(GEF) /* if [DP] >= [DP-1] then PC <- parm; DP <- DP-2 */
|
||||||
|
CMP(float4, >=)
|
||||||
|
|
||||||
|
|
||||||
|
OPDEF(LOAD1) /* [DP] <- [[DP]] */
|
||||||
|
{
|
||||||
|
Push<uint1_t>(Get<uint1_t>(Pop<uint4_t>()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(LOAD2) /* [DP] <- [[DP]] */
|
||||||
|
{
|
||||||
|
Push<uint2_t>(Get<uint2_t>(Pop<uint4_t>()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(LOAD4) /* [DP] <- [[DP]] */
|
||||||
|
{
|
||||||
|
Push<uint4_t>(Get<uint4_t>(Pop<uint4_t>()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(STORE1) /* [DP-1] <- [DP]; DP <- DP-2 */
|
||||||
|
{
|
||||||
|
Set<uint1_t>(Pop<uint4_t>(), Pop<uint1_t>());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(STORE2) /* [DP-1] <- [DP]; DP <- DP-2 */
|
||||||
|
{
|
||||||
|
Set<uint2_t>(Pop<uint4_t>(), Pop<uint2_t>());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(STORE4) /* [DP-1] <- [DP]; DP <- DP-2 */
|
||||||
|
{
|
||||||
|
Set<uint4_t>(Pop<uint4_t>(), Pop<uint4_t>());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(ARG) /* Marshal TOS to to-call argument list */
|
||||||
|
{
|
||||||
|
Marshal(parameter.int4, Pop());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(BLOCK_COPY) /* XXX */
|
||||||
|
{
|
||||||
|
R1 = Pop();
|
||||||
|
R0 = Pop();
|
||||||
|
if(R0.int4 >= 0 && R0.int4 + parameter.int4 < ramSize && R1.int4 >= 0 && R1.int4 + parameter.int4 < ramSize)
|
||||||
|
memcpy(ram + R0.int4, ram + R1.int4, parameter.int4);
|
||||||
|
else
|
||||||
|
throw AccessViolationException();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(SEX8) /* Sign-extend 8-bit */
|
||||||
|
{
|
||||||
|
R0 = Pop();
|
||||||
|
if(R0.uint4 & 0x80)
|
||||||
|
R0.uint4 |= 0xFFFFFF80;
|
||||||
|
Push(R0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(SEX16) /* Sign-extend 16-bit */
|
||||||
|
{
|
||||||
|
R0 = Pop();
|
||||||
|
if(R0.uint4 & 0x8000)
|
||||||
|
R0.uint4 |= 0xFFFF8000;
|
||||||
|
Push(R0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNOP(type, op) \
|
||||||
|
{ \
|
||||||
|
Push<type##_t>(op Pop<type##_t>()); \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BINOP(type, op) \
|
||||||
|
{ \
|
||||||
|
R0 = Pop(); \
|
||||||
|
Push<type##_t>(Pop<type##_t>() op R0.type); \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(NEGI) /* [DP] <- -[DP] */
|
||||||
|
UNOP(int4, -)
|
||||||
|
|
||||||
|
OPDEF(ADD) /* [DP-1] <- [DP-1] + [DP]; DP <- DP-1 */
|
||||||
|
BINOP(int4, +)
|
||||||
|
|
||||||
|
OPDEF(SUB) /* [DP-1] <- [DP-1] - [DP]; DP <- DP-1 */
|
||||||
|
BINOP(int4, -)
|
||||||
|
|
||||||
|
OPDEF(DIVI) /* [DP-1] <- [DP-1] / [DP]; DP <- DP-1 */
|
||||||
|
BINOP(int4, /)
|
||||||
|
|
||||||
|
OPDEF(DIVU) /* [DP-1] <- [DP-1] / [DP]; DP <- DP-1 */
|
||||||
|
BINOP(uint4, /)
|
||||||
|
|
||||||
|
OPDEF(MODI) /* [DP-1] <- [DP-1] % [DP]; DP <- DP-1 */
|
||||||
|
BINOP(int4, %)
|
||||||
|
|
||||||
|
OPDEF(MODU) /* [DP-1] <- [DP-1] % [DP]; DP <- DP-1 */
|
||||||
|
BINOP(uint4, %)
|
||||||
|
|
||||||
|
OPDEF(MULI) /* [DP-1] <- [DP-1] * [DP]; DP <- DP-1 */
|
||||||
|
BINOP(int4, *)
|
||||||
|
|
||||||
|
OPDEF(MULU) /* [DP-1] <- [DP-1] * [DP]; DP <- OP-1 */
|
||||||
|
BINOP(uint4, *)
|
||||||
|
|
||||||
|
OPDEF(BAND) /* [DP-1] <- [DP-1] & [DP]; DP <- DP-1 */
|
||||||
|
BINOP(uint4, &)
|
||||||
|
|
||||||
|
OPDEF(BOR) /* [DP-1] <- [DP-1] | [DP]; DP <- DP-1 */
|
||||||
|
BINOP(uint4, |)
|
||||||
|
|
||||||
|
OPDEF(BXOR) /* [DP-1] <- [DP-1] ^ [DP]; DP <- DP-1 */
|
||||||
|
BINOP(uint4, ^)
|
||||||
|
|
||||||
|
OPDEF(BCOM) /* [DP] <- ~[DP] */
|
||||||
|
UNOP(uint4, ~)
|
||||||
|
|
||||||
|
OPDEF(LSH) /* [DP-1] <- [DP-1] << [DP]; DP <- DP-1 */
|
||||||
|
BINOP(uint4, <<)
|
||||||
|
|
||||||
|
OPDEF(RSHI) /* [DP-1] <- [DP-1] >> [DP]; DP <- DP-1 */
|
||||||
|
{
|
||||||
|
R1.int4 = Pop<int4_t>();
|
||||||
|
R0.int4 = Pop<int4_t>();
|
||||||
|
#if 0
|
||||||
|
while (R1.int4-- > 0)
|
||||||
|
R0.int4 /= 2;
|
||||||
|
R2 = R0;
|
||||||
|
#else
|
||||||
|
R2.int4 = R0.int4 >> R1.int4;
|
||||||
|
#endif
|
||||||
|
Push(R2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(RSHU) /* [DP-1] <- [DP-1] >> [DP]; DP <- DP-1 */
|
||||||
|
BINOP(uint4, >>)
|
||||||
|
|
||||||
|
OPDEF(NEGF) /* [DP] <- -[DP] */
|
||||||
|
UNOP(float4, -)
|
||||||
|
|
||||||
|
OPDEF(ADDF) /* [DP-1] <- [DP-1] + [DP]; DP <- DP-1 */
|
||||||
|
BINOP(float4, +)
|
||||||
|
|
||||||
|
OPDEF(SUBF) /* [DP-1] <- [DP-1] - [DP]; DP <- DP-1 */
|
||||||
|
BINOP(float4, -)
|
||||||
|
|
||||||
|
OPDEF(DIVF) /* [DP-1] <- [DP-1] / [DP]; DP <- DP-1 */
|
||||||
|
BINOP(float4, /)
|
||||||
|
|
||||||
|
OPDEF(MULF) /* [DP-1] <- [DP-1] / [DP]; DP <- DP-1 */
|
||||||
|
BINOP(float4, *)
|
||||||
|
|
||||||
|
OPDEF(CVIF) /* [DP] <- [DP] */
|
||||||
|
{
|
||||||
|
Push<float4_t>(Pop<int4_t>());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPDEF(CVFI) /* [DP] <- [DP] */
|
||||||
|
{
|
||||||
|
Push<int4_t>(Pop<float4_t>());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
243
src/virtualmachine/VirtualMachine.h
Normal file
243
src/virtualmachine/VirtualMachine.h
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Exceptions.h"
|
||||||
|
|
||||||
|
namespace vm
|
||||||
|
{
|
||||||
|
|
||||||
|
class VirtualMachine;
|
||||||
|
|
||||||
|
typedef char ram_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef unsigned int uint4_t;
|
||||||
|
typedef signed int int4_t;
|
||||||
|
|
||||||
|
typedef unsigned short uint2_t;
|
||||||
|
typedef signed short int2_t;
|
||||||
|
|
||||||
|
typedef unsigned char uint1_t;
|
||||||
|
typedef signed char int1_t;
|
||||||
|
|
||||||
|
typedef float float4_t;
|
||||||
|
|
||||||
|
union word
|
||||||
|
{
|
||||||
|
uint4_t uint4;
|
||||||
|
int4_t int4;
|
||||||
|
uint2_t uint2;
|
||||||
|
int2_t int2;
|
||||||
|
uint1_t uint1;
|
||||||
|
int1_t int1;
|
||||||
|
float4_t float4;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (VirtualMachine::*OperationFunction)(word parameter);
|
||||||
|
|
||||||
|
struct Instruction
|
||||||
|
{
|
||||||
|
int Operation;
|
||||||
|
word Parameter;
|
||||||
|
//opfunc opfunc;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
QVM_MAGIC = 0x12721444,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qvm_header_t
|
||||||
|
{
|
||||||
|
int magic;
|
||||||
|
/* not-entirely-RISC ISA, so instruction count != codelen */
|
||||||
|
int inscount; /* instruction count. */
|
||||||
|
int codeoff; /* file offset of code segment. */
|
||||||
|
int codelen; /* length of code segment, in octets. */
|
||||||
|
int dataoff; /* file offset of data segment. */
|
||||||
|
int datalen; /* length of data segment, in octets. */
|
||||||
|
int litlen; /* length of lit segment (which is embedded in data segment). */
|
||||||
|
int bsslen; /* length of bss segment. */
|
||||||
|
};
|
||||||
|
|
||||||
|
class VirtualMachine
|
||||||
|
{
|
||||||
|
bool bigEndian; /* host is big-endian (requires byte-swapping). */
|
||||||
|
|
||||||
|
/* Memory spaces. */
|
||||||
|
char * hunk; /* hunk space (malloc'd). */
|
||||||
|
int hunkSize; /* total hunk size. */
|
||||||
|
int hunkFree; /* free pointer. */
|
||||||
|
|
||||||
|
/* Read-Only Memory (code). */
|
||||||
|
Instruction * rom;
|
||||||
|
int romSize;
|
||||||
|
|
||||||
|
/* Random-Access Memory (data). */
|
||||||
|
ram_t *ram;
|
||||||
|
int ramSize;
|
||||||
|
|
||||||
|
int dataStack;
|
||||||
|
int returnStack;
|
||||||
|
|
||||||
|
word r[4]; /* registers. */
|
||||||
|
int DP; /* Datastack pointer. */
|
||||||
|
int RP; /* Return stack pointer. */
|
||||||
|
int PC; /* Program Counter. */
|
||||||
|
// int AP; /* Argument pointer. (hrm...) */
|
||||||
|
|
||||||
|
/* various flags. */
|
||||||
|
int cm:1;
|
||||||
|
|
||||||
|
/* Execution time */
|
||||||
|
int cycles;
|
||||||
|
|
||||||
|
#define TRAPDEF(n, f) int trap##f();
|
||||||
|
#include "Traps.inl"
|
||||||
|
#undef TRAPDEF
|
||||||
|
|
||||||
|
static OperationFunction operations[];
|
||||||
|
|
||||||
|
#define OPDEF(n) int op##n(word parameter);
|
||||||
|
#include "OpCodes.inl"
|
||||||
|
#undef OPDEF
|
||||||
|
|
||||||
|
#define OPDEF(n) OP##n,
|
||||||
|
enum {
|
||||||
|
#include "OpCodes.inl"
|
||||||
|
};
|
||||||
|
#undef OPDEF
|
||||||
|
|
||||||
|
int readByte(FILE *qvmfile);
|
||||||
|
int readInt(FILE *qvmfile);
|
||||||
|
int opcodeParameterSize(int opcode);
|
||||||
|
int syscall(int programCounter);
|
||||||
|
public:
|
||||||
|
VirtualMachine(int hunkMbytes);
|
||||||
|
virtual ~VirtualMachine();
|
||||||
|
|
||||||
|
int LoadProgram(char * filename);
|
||||||
|
int Run();
|
||||||
|
int Call(int address);
|
||||||
|
void Marshal(int address, word element)
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+RP+address;
|
||||||
|
if(ptr < ram || ptr > ram+ramSize - sizeof(word))
|
||||||
|
throw AccessViolationException(RP+address);
|
||||||
|
*((word*)ptr) = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T Get(int address)
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+address;
|
||||||
|
if(ptr < ram || ptr > ram+ramSize - sizeof(word))
|
||||||
|
throw AccessViolationException(address);
|
||||||
|
return *((T*)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void Set(int address, T value)
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+address;
|
||||||
|
if(ptr < ram || ptr > ram+ramSize - sizeof(word))
|
||||||
|
throw AccessViolationException(address);
|
||||||
|
*((T*)ptr) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T Pop ()
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+DP;
|
||||||
|
if(DP + sizeof(word) < hunkSize)
|
||||||
|
DP += sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackUnderflowException();
|
||||||
|
return *((T*)ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> T RPop ()
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+RP;
|
||||||
|
if(RP + sizeof(word) < hunkSize)
|
||||||
|
RP += sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackUnderflowException();
|
||||||
|
return *((T*)ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> void Push(T value)
|
||||||
|
{
|
||||||
|
if(DP - sizeof(word) >= 0)
|
||||||
|
DP -= sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackOverflowException();
|
||||||
|
ram_t * ptr = ram+DP;
|
||||||
|
*((T*)ptr) = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> void RPush(T value)
|
||||||
|
{
|
||||||
|
if(RP - sizeof(word) >= 0)
|
||||||
|
RP -= sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackOverflowException();
|
||||||
|
ram_t * ptr = ram+RP;
|
||||||
|
*((T*)ptr) = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
word Get(int address)
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+address;
|
||||||
|
if(ptr < ram || ptr > ram+ramSize - sizeof(word))
|
||||||
|
throw AccessViolationException(address);
|
||||||
|
return *((word*)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(int address, word value)
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+address;
|
||||||
|
if(ptr < ram || ptr > ram+ramSize - sizeof(word))
|
||||||
|
throw AccessViolationException(address);
|
||||||
|
*((word*)ptr) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
word Pop()
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+DP;
|
||||||
|
if(DP + sizeof(word) < hunkSize)
|
||||||
|
DP += sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackUnderflowException();
|
||||||
|
return *((word*)ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Push(word value)
|
||||||
|
{
|
||||||
|
if(DP - sizeof(word) >= 0)
|
||||||
|
DP -= sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackOverflowException();
|
||||||
|
ram_t * ptr = ram+DP;
|
||||||
|
*((word*)ptr) = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
word RPop()
|
||||||
|
{
|
||||||
|
ram_t * ptr = ram+RP;
|
||||||
|
if(RP + sizeof(word) < hunkSize)
|
||||||
|
RP += sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackUnderflowException();
|
||||||
|
return *((word*)ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
void RPush(word value)
|
||||||
|
{
|
||||||
|
if(RP - sizeof(word) >= 0)
|
||||||
|
RP -= sizeof(word);
|
||||||
|
else
|
||||||
|
throw StackOverflowException();
|
||||||
|
ram_t * ptr = ram+RP;
|
||||||
|
*((word*)ptr) = value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user