#include "glulxe.h"
#include "opcodes.h"
const operandlist_t *fast_operandlist[0x80];
static operandlist_t list_none = { 0, 4, NULL };
static int array_S[1] = { modeform_Store };
static operandlist_t list_S = { 1, 4, array_S };
static int array_LS[2] = { modeform_Load, modeform_Store };
static operandlist_t list_LS = { 2, 4, array_LS };
static int array_LLS[3] = { modeform_Load, modeform_Load, modeform_Store };
static operandlist_t list_LLS = { 3, 4, array_LLS };
static int array_LLLS[4] = { modeform_Load, modeform_Load, modeform_Load, modeform_Store };
static operandlist_t list_LLLS = { 4, 4, array_LLLS };
static int array_LLLLS[5] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
static operandlist_t list_LLLLS = { 5, 4, array_LLLLS };
static int array_LLLLLLS[7] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
static operandlist_t list_LLLLLLS = { 7, 4, array_LLLLLLS };
static int array_LLLLLLLS[8] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
static operandlist_t list_LLLLLLLS = { 8, 4, array_LLLLLLLS };
static int array_L[1] = { modeform_Load };
static operandlist_t list_L = { 1, 4, array_L };
static int array_LL[2] = { modeform_Load, modeform_Load };
static operandlist_t list_LL = { 2, 4, array_LL };
static int array_LLL[3] = { modeform_Load, modeform_Load, modeform_Load };
static operandlist_t list_LLL = { 3, 4, array_LLL };
static operandlist_t list_2LS = { 2, 2, array_LS };
static operandlist_t list_1LS = { 2, 1, array_LS };
static int array_LLLL[4] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load };
static operandlist_t list_LLLL = { 4, 4, array_LLLL };
static int array_LLLLL[5] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load };
static operandlist_t list_LLLLL = { 5, 4, array_LLLLL };
static int array_LLLLLLL[7] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load };
static operandlist_t list_LLLLLLL = { 7, 4, array_LLLLLLL };
static int array_SL[2] = { modeform_Store, modeform_Load };
static operandlist_t list_SL = { 2, 4, array_SL };
static int array_LSS[3] = { modeform_Load, modeform_Store, modeform_Store };
static operandlist_t list_LSS = { 3, 4, array_LSS };
static int array_LLSS[4] = { modeform_Load, modeform_Load, modeform_Store, modeform_Store };
static operandlist_t list_LLSS = { 4, 4, array_LLSS };
static int array_LLLLSS[6] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store, modeform_Store };
static operandlist_t list_LLLLSS = { 6, 4, array_LLLLSS };
void init_operands()
{
int ix;
for (ix=0; ix<0x80; ix++)
fast_operandlist[ix] = lookup_operandlist(ix);
}
const operandlist_t *lookup_operandlist(glui32 opcode)
{
switch (opcode) {
case op_nop:
return &list_none;
case op_add:
case op_sub:
case op_mul:
case op_div:
case op_mod:
case op_bitand:
case op_bitor:
case op_bitxor:
case op_shiftl:
case op_sshiftr:
case op_ushiftr:
return &list_LLS;
case op_neg:
case op_bitnot:
return &list_LS;
case op_jump:
case op_jumpabs:
return &list_L;
case op_jz:
case op_jnz:
return &list_LL;
case op_jeq:
case op_jne:
case op_jlt:
case op_jge:
case op_jgt:
case op_jle:
case op_jltu:
case op_jgeu:
case op_jgtu:
case op_jleu:
return &list_LLL;
case op_call:
return &list_LLS;
case op_return:
return &list_L;
case op_catch:
return &list_SL;
case op_throw:
return &list_LL;
case op_tailcall:
return &list_LL;
case op_sexb:
case op_sexs:
return &list_LS;
case op_copy:
return &list_LS;
case op_copys:
return &list_2LS;
case op_copyb:
return &list_1LS;
case op_aload:
case op_aloads:
case op_aloadb:
case op_aloadbit:
return &list_LLS;
case op_astore:
case op_astores:
case op_astoreb:
case op_astorebit:
return &list_LLL;
case op_stkcount:
return &list_S;
case op_stkpeek:
return &list_LS;
case op_stkswap:
return &list_none;
case op_stkroll:
return &list_LL;
case op_stkcopy:
return &list_L;
case op_streamnum:
return &list_L;
case op_setiosys:
return &list_LL;
case op_verify:
return &list_S;
case op_quit:
return &list_none;
case op_gestalt:
return &list_LLS;
case op_debugtrap:
return &list_L;
case op_getmemsize:
return &list_S;
case op_setmemsize:
return &list_LS;
case op_linearsearch:
return &list_LLLLLLLS;
case op_binarysearch:
return &list_LLLLLLLS;
case op_linkedsearch:
return &list_LLLLLLS;
case op_callf:
return &list_LS;
case op_callfi:
return &list_LLS;
case op_callfii:
return &list_LLLS;
case op_callfiii:
return &list_LLLLS;
case op_mzero:
return &list_LL;
case op_mcopy:
return &list_LLL;
case op_malloc:
return &list_LS;
case op_mfree:
return &list_L;
case op_accelfunc:
case op_accelparam:
return &list_LL;
case op_numtof:
case op_ftonumz:
case op_ftonumn:
case op_ceil:
case op_floor:
case op_sqrt:
case op_exp:
case op_log:
return &list_LS;
case op_fadd:
case op_fsub:
case op_fmul:
case op_fdiv:
case op_pow:
case op_atan2:
return &list_LLS;
case op_fmod:
return &list_LLSS;
case op_sin:
case op_cos:
case op_tan:
case op_asin:
case op_acos:
case op_atan:
return &list_LS;
case op_jfeq:
case op_jfne:
return &list_LLLL;
case op_jflt:
case op_jfle:
case op_jfgt:
case op_jfge:
return &list_LLL;
case op_jisnan:
case op_jisinf:
return &list_LL;
case op_numtod:
case op_ftod:
return &list_LSS;
case op_dtonumz:
case op_dtonumn:
case op_dtof:
return &list_LLS;
case op_dceil:
case op_dfloor:
case op_dsqrt:
case op_dexp:
case op_dlog:
return &list_LLSS;
case op_dadd:
case op_dsub:
case op_dmul:
case op_ddiv:
case op_dpow:
case op_datan2:
return &list_LLLLSS;
case op_dmodr:
case op_dmodq:
return &list_LLLLSS;
case op_dsin:
case op_dcos:
case op_dtan:
case op_dasin:
case op_dacos:
case op_datan:
return &list_LLSS;
case op_jdeq:
case op_jdne:
return &list_LLLLLLL;
case op_jdlt:
case op_jdle:
case op_jdgt:
case op_jdge:
return &list_LLLLL;
case op_jdisnan:
case op_jdisinf:
return &list_LLL;
default:
return NULL;
}
}
void parse_operands(oparg_t *args, const operandlist_t *oplist)
{
int ix;
oparg_t *curarg;
int numops = oplist->num_ops;
int argsize = oplist->arg_size;
glui32 modeaddr = pc;
int modeval = 0;
pc += (numops+1) / 2;
for (ix=0, curarg=args; ix<numops; ix++, curarg++) {
int mode;
glui32 value;
glui32 addr;
curarg->desttype = 0;
if ((ix & 1) == 0) {
modeval = Mem1(modeaddr);
mode = (modeval & 0x0F);
}
else {
mode = ((modeval >> 4) & 0x0F);
modeaddr++;
}
if (oplist->formlist[ix] == modeform_Load) {
switch (mode) {
case 8:
if (stackptr < valstackbase+4) {
fatal_error("Stack underflow in operand.");
}
stackptr -= 4;
value = Stk4(stackptr);
break;
case 0:
value = 0;
break;
case 1:
value = (glsi32)(signed char)(Mem1(pc));
pc++;
break;
case 2:
value = (glsi32)(signed char)(Mem1(pc));
pc++;
value = (value << 8) | (glui32)(Mem1(pc));
pc++;
break;
case 3:
value = Mem4(pc);
pc += 4;
break;
case 15:
addr = Mem4(pc);
addr += ramstart;
pc += 4;
goto MainMemAddr;
case 14:
addr = (glui32)Mem2(pc);
addr += ramstart;
pc += 2;
goto MainMemAddr;
case 13:
addr = (glui32)(Mem1(pc));
addr += ramstart;
pc++;
goto MainMemAddr;
case 7:
addr = Mem4(pc);
pc += 4;
goto MainMemAddr;
case 6:
addr = (glui32)Mem2(pc);
pc += 2;
goto MainMemAddr;
case 5:
addr = (glui32)(Mem1(pc));
pc++;
MainMemAddr:
if (argsize == 4) {
value = Mem4(addr);
}
else if (argsize == 2) {
value = Mem2(addr);
}
else {
value = Mem1(addr);
}
break;
case 11:
addr = Mem4(pc);
pc += 4;
goto LocalsAddr;
case 10:
addr = (glui32)Mem2(pc);
pc += 2;
goto LocalsAddr;
case 9:
addr = (glui32)(Mem1(pc));
pc++;
LocalsAddr:
addr += localsbase;
if (argsize == 4) {
value = Stk4(addr);
}
else if (argsize == 2) {
value = Stk2(addr);
}
else {
value = Stk1(addr);
}
break;
default:
value = 0;
fatal_error("Unknown addressing mode in load operand.");
}
curarg->value = value;
}
else {
switch (mode) {
case 0:
curarg->desttype = 0;
curarg->value = 0;
break;
case 8:
curarg->desttype = 3;
curarg->value = 0;
break;
case 15:
addr = Mem4(pc);
addr += ramstart;
pc += 4;
goto WrMainMemAddr;
case 14:
addr = (glui32)Mem2(pc);
addr += ramstart;
pc += 2;
goto WrMainMemAddr;
case 13:
addr = (glui32)(Mem1(pc));
addr += ramstart;
pc++;
goto WrMainMemAddr;
case 7:
addr = Mem4(pc);
pc += 4;
goto WrMainMemAddr;
case 6:
addr = (glui32)Mem2(pc);
pc += 2;
goto WrMainMemAddr;
case 5:
addr = (glui32)(Mem1(pc));
pc++;
WrMainMemAddr:
curarg->desttype = 1;
curarg->value = addr;
break;
case 11:
addr = Mem4(pc);
pc += 4;
goto WrLocalsAddr;
case 10:
addr = (glui32)Mem2(pc);
pc += 2;
goto WrLocalsAddr;
case 9:
addr = (glui32)(Mem1(pc));
pc++;
WrLocalsAddr:
curarg->desttype = 2;
curarg->value = addr;
break;
case 1:
case 2:
case 3:
fatal_error("Constant addressing mode in store operand.");
default:
fatal_error("Unknown addressing mode in store operand.");
}
}
}
}
void store_operand(glui32 desttype, glui32 destaddr, glui32 storeval)
{
switch (desttype) {
case 0:
return;
case 1:
MemW4(destaddr, storeval);
return;
case 2:
destaddr += localsbase;
StkW4(destaddr, storeval);
return;
case 3:
if (stackptr+4 > stacksize) {
trap(TRAP_STACK_EXHAUSTED);
}
StkW4(stackptr, storeval);
stackptr += 4;
return;
default:
fatal_error("Unknown destination type in store operand.");
}
}
void store_operand_s(glui32 desttype, glui32 destaddr, glui32 storeval)
{
storeval &= 0xFFFF;
switch (desttype) {
case 0:
return;
case 1:
MemW2(destaddr, storeval);
return;
case 2:
destaddr += localsbase;
StkW2(destaddr, storeval);
return;
case 3:
if (stackptr+4 > stacksize) {
trap(TRAP_STACK_EXHAUSTED);
}
StkW4(stackptr, storeval);
stackptr += 4;
return;
default:
fatal_error("Unknown destination type in store operand.");
}
}
void store_operand_b(glui32 desttype, glui32 destaddr, glui32 storeval)
{
storeval &= 0xFF;
switch (desttype) {
case 0:
return;
case 1:
MemW1(destaddr, storeval);
return;
case 2:
destaddr += localsbase;
StkW1(destaddr, storeval);
return;
case 3:
if (stackptr+4 > stacksize) {
trap(TRAP_STACK_EXHAUSTED);
}
StkW4(stackptr, storeval);
stackptr += 4;
return;
default:
fatal_error("Unknown destination type in store operand.");
}
}