Move opcodes and syscalls out of main virtualmachine coee
This commit is contained in:
parent
7b05862cfe
commit
2d2f8713bc
@ -7,8 +7,10 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
vm::VirtualMachine * vm = new vm::VirtualMachine(2);
|
||||
vm->LoadProgram("test.qvm");
|
||||
while(true)
|
||||
{
|
||||
vm->Call(0/*, 0, 88, 12*/);
|
||||
std::cout << "Return value: " << vm->Pop<vm::uint4_t>() << std::endl;
|
||||
//vm->Run();
|
||||
}
|
||||
}
|
||||
#endif
|
356
src/virtualmachine/Operations.cpp
Normal file
356
src/virtualmachine/Operations.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
#include "VirtualMachine.h"
|
||||
|
||||
namespace vm
|
||||
{
|
||||
#define OPDEF(n) &VirtualMachine::Op##n,
|
||||
OperationFunction VirtualMachine::operations[] =
|
||||
{
|
||||
#include "Operations.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>();
|
||||
R2.int4 = R0.int4 >> R1.int4;
|
||||
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;
|
||||
}
|
||||
}
|
33
src/virtualmachine/Syscalls.cpp
Normal file
33
src/virtualmachine/Syscalls.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "VirtualMachine.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
#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;
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ namespace vm
|
||||
delete[] hunk;
|
||||
}
|
||||
|
||||
#define crumb printf
|
||||
#define DEBUGTRACE(args...) printf(args);
|
||||
|
||||
int VirtualMachine::opcodeParameterSize(int opcode)
|
||||
{
|
||||
@ -101,16 +101,16 @@ namespace vm
|
||||
uint1_t x[4];
|
||||
word w;
|
||||
|
||||
crumb("Loading file...\n");
|
||||
DEBUGTRACE("Loading file...\n");
|
||||
qvminfo.magic = readInt(qvmfile); /* magic. */
|
||||
if (qvminfo.magic != QVM_MAGIC)
|
||||
{
|
||||
crumb("Invalid magic");
|
||||
DEBUGTRACE("Invalid magic");
|
||||
//q3vm_error("Does not appear to be a QVM file.");
|
||||
/* XXX: option to force continue. */
|
||||
return 0;
|
||||
}
|
||||
crumb("Magic OK\n");
|
||||
DEBUGTRACE("Magic OK\n");
|
||||
/* variable-length instructions mean instruction count != code length */
|
||||
qvminfo.inscount = readInt(qvmfile);
|
||||
qvminfo.codeoff = readInt(qvmfile);
|
||||
@ -122,7 +122,7 @@ namespace vm
|
||||
|
||||
/* Code segment should follow... */
|
||||
/* XXX: use fseek with SEEK_CUR? */
|
||||
crumb("Searching for .code @ %d from %d\n", qvminfo.codeoff, ftell(qvmfile));
|
||||
DEBUGTRACE("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)
|
||||
@ -141,12 +141,12 @@ namespace vm
|
||||
rom[romSize].Parameter = w;
|
||||
romSize++;
|
||||
}
|
||||
crumb("After loading code: at %d, should be %d\n", ftell(qvmfile), qvminfo.codeoff + qvminfo.codelen);
|
||||
DEBUGTRACE("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));
|
||||
DEBUGTRACE("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++)
|
||||
@ -156,9 +156,10 @@ namespace vm
|
||||
*((word*)(ram + ramSize)) = w;
|
||||
ramSize += sizeof(word);
|
||||
}
|
||||
|
||||
/* lit segment follows data segment. */
|
||||
/* Assembler should have already padded properly. */
|
||||
crumb("Loading .lit\n");
|
||||
DEBUGTRACE("Loading .lit\n");
|
||||
for (n = 0; n < (qvminfo.litlen / sizeof(uint1_t)); n++)
|
||||
{
|
||||
i = fread(&x, 1, sizeof(x), qvmfile);
|
||||
@ -167,13 +168,13 @@ namespace vm
|
||||
ramSize += sizeof(word);
|
||||
}
|
||||
/* bss segment. */
|
||||
crumb("Allocating .bss %d (%X) bytes\n", qvminfo.bsslen, qvminfo.bsslen);
|
||||
DEBUGTRACE("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);
|
||||
DEBUGTRACE("VM hunk has %d of %d bytes free (RAM = %d B).\n", hunkFree, hunkSize, ramSize);
|
||||
if (ramSize > hunkSize)
|
||||
{
|
||||
throw OutOfMemoryException();
|
||||
@ -198,13 +199,13 @@ namespace vm
|
||||
int VirtualMachine::Call(int address)
|
||||
{
|
||||
word w;
|
||||
int i, argCount = 13;
|
||||
int i, argCount = 0;
|
||||
|
||||
/* Set up call. */
|
||||
opPUSH(w);
|
||||
crumb("Starting with PC=%d, DP=%d, RP=%d to %d\n", PC, DP, RP, address);
|
||||
OpPUSH(w);
|
||||
DEBUGTRACE("Starting with PC=%d, DP=%d, RP=%d to %d\n", PC, DP, RP, address);
|
||||
w.int4 = (argCount + 2) * sizeof(word);
|
||||
opENTER(w);
|
||||
OpENTER(w);
|
||||
i = 8;
|
||||
/**w.int4 = arg0; Marshal(i, w); i += 4;
|
||||
w.int4 = arg1; Marshal(i, w); i += 4;
|
||||
@ -221,12 +222,13 @@ namespace vm
|
||||
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);
|
||||
OpCALL(w);
|
||||
DEBUGTRACE("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);
|
||||
DEBUGTRACE("At finish PC=%d, DP=%d, RP=%d\n", PC, DP, RP);
|
||||
w.int4 = (argCount + 2) * sizeof(word);
|
||||
opLEAVE(w);
|
||||
OpLEAVE(w);
|
||||
PC = romSize + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -267,7 +269,7 @@ namespace vm
|
||||
switch (trap)
|
||||
{
|
||||
#define TRAPDEF(n, f) case n: retval = trap##f(); break;
|
||||
#include "Traps.inl"
|
||||
#include "Syscalls.inl"
|
||||
#undef TRAPDEF
|
||||
}
|
||||
|
||||
@ -277,388 +279,4 @@ namespace vm
|
||||
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;
|
||||
}
|
||||
}
|
@ -93,18 +93,15 @@ namespace vm
|
||||
int cycles;
|
||||
|
||||
#define TRAPDEF(n, f) int trap##f();
|
||||
#include "Traps.inl"
|
||||
#include "Syscalls.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"
|
||||
#include "Operations.inl"
|
||||
};
|
||||
#undef OPDEF
|
||||
|
||||
@ -113,6 +110,10 @@ namespace vm
|
||||
int opcodeParameterSize(int opcode);
|
||||
int syscall(int programCounter);
|
||||
public:
|
||||
#define OPDEF(n) int Op##n(word parameter);
|
||||
#include "Operations.inl"
|
||||
#undef OPDEF
|
||||
|
||||
VirtualMachine(int hunkMbytes);
|
||||
virtual ~VirtualMachine();
|
||||
|
||||
|
Reference in New Issue
Block a user