/******************************************************************************* ' Author: Dave Hein ' Version 0.21 ' Copyright (c) 2010, 2011 ' See end of file for terms of use. '******************************************************************************/ #include #include #include #include "conion.h" #include #include #include "interp.h" #include "spinsim.h" extern int32_t printflag; extern PasmVarsT PasmVars[8]; extern char *hubram; extern int32_t memsize; extern int32_t loopcount; extern int32_t cycleaccurate; extern int32_t propmode; extern int32_t pin_val_a; extern char lockstate[16]; extern char lockalloc[16]; extern FILE *tracefile; int32_t ExecuteMathOp(SpinVarsT *spinvars, int32_t opcode, int32_t parm1); int32_t ExecuteExtraOp(SpinVarsT *spinvars, int32_t opcode, int32_t parm1, int32_t mask); void ExecuteRegisterOp(SpinVarsT *spinvars, int32_t operand, int32_t msb, int32_t lsb); // This routine checks for the system I/O address and // maps it to the end of the memory int32_t MAP_ADDR(int32_t addr) { if ((addr & 0xfffffff0) == 0x12340000) { addr = memsize + (addr & 15); } else if (memsize == 65536) { addr &= 0xffff; } else if (((uint32_t)addr) >= memsize) { #if 0 fprintf(tracefile, "MAP_ADDR(%d): address out of bounds %8.8x\n", loopcount, addr); addr = memsize + 12; #else addr &= memsize - 1; #endif } //fprintf(tracefile, "MAP_ADDR: %8.8x %8.8x\n", addr, ((uint32_t *)hubram)[addr>>2]); return addr; } int32_t GetCnt() { int32_t cycles; if (cycleaccurate) { if (propmode >= 2) cycles = loopcount; else cycles = loopcount * 4; } else { int64_t millisec; struct timeb timebuf; ftime(&timebuf); millisec = timebuf.time; millisec = (millisec * 1000) + timebuf.millitm; millisec *= LONG(0)/1000; cycles = millisec; } return cycles; } void UpdatePins(void) { int32_t i; int32_t mask1; int32_t val = 0; int32_t mask = 0; for (i = 0; i < 8; i++) { if (PasmVars[i].state) { mask1 = PasmVars[i].mem[0x1f6]; // dira val |= mask1 & PasmVars[i].mem[0x1f4]; // outa mask |= mask1; } } pin_val_a = (~mask) | val; } int32_t GetSignedOffset(int32_t *ppcurr) { int32_t val; int32_t pcurr = *ppcurr; val = BYTE(pcurr++); if (val < 0x80) { val = (val << 25) >> 25; } else { val = (val << 8) | BYTE(pcurr++); val = (val << 17) >> 17; } *ppcurr = pcurr; return val; } int32_t GetUnsignedOffset(int32_t *ppcurr) { int32_t pcurr = *ppcurr; int32_t val; val = BYTE(pcurr++); if (val & 0x80) val = ((val & 0x7f) << 8) | BYTE(pcurr++); *ppcurr = pcurr; return val; } int32_t bitrev(int32_t val, int32_t nbits) { int32_t retval = 0; while (nbits-- > 0) { retval = (retval << 1) | (val & 1); val >>= 1; } return retval; } void StartCog(SpinVarsT *spinvars, int32_t par, int32_t cogid) { memset(spinvars, 0, sizeof(SpinVarsT)); spinvars->id = cogid; spinvars->par = par; spinvars->state = 1; spinvars->pbase = WORD(par + 2); spinvars->vbase = WORD(par + 4); spinvars->dbase = WORD(par + 6); spinvars->pcurr = WORD(par + 8); spinvars->dcurr = WORD(par + 10); spinvars->masklong = 0xffffffff; spinvars->masktop = 0x80000000; spinvars->maskwr = 0x00800000; } void ExecuteLowerOp(SpinVarsT *spinvars) { int32_t pcurr = spinvars->pcurr; int32_t dcurr = spinvars->dcurr; int32_t opcode = BYTE(pcurr++); if (opcode <= 3) // ldfrmr, ldfrm, ldfrmar, ldfrma { opcode |= spinvars->pbase; WORD(dcurr) = opcode; dcurr += 2; WORD(dcurr) = spinvars->vbase; dcurr += 2; WORD(dcurr) = spinvars->dbase; dcurr += 2; WORD(dcurr) = spinvars->dcall; spinvars->dcall = dcurr; dcurr += 2; LONG(dcurr) = 0; dcurr += 4; } else if (opcode == 0x04) // jmp { int32_t jmpoff = GetSignedOffset(&pcurr); pcurr += jmpoff; } else if (opcode >= 0x05 && opcode <= 0x07) // call, callobj, callobjx { int32_t index, pubnum; if (opcode > 0x05) { int32_t objnum = BYTE(pcurr++); if (opcode == 0x07) { dcurr -= 4; objnum += LONG(dcurr); } index = (objnum << 2) + spinvars->pbase; spinvars->pbase += WORD(index); spinvars->vbase += WORD(index+2); } pubnum = BYTE(pcurr++); spinvars->dbase = spinvars->dcall; spinvars->dcall = WORD(spinvars->dcall); WORD(spinvars->dbase) = pcurr; index = (pubnum << 2) + spinvars->pbase; pcurr = WORD(index) + spinvars->pbase; spinvars->dbase += 2; dcurr += WORD(index+2); } else if (opcode == 0x08) // tjz { int32_t jmpoff = GetSignedOffset(&pcurr); if (!LONG(dcurr-4)) { pcurr += jmpoff; dcurr -= 4; } } else if (opcode == 0x09) // djnz { int32_t jmpoff = GetSignedOffset(&pcurr); if (--LONG(dcurr-4)) { pcurr += jmpoff; } else dcurr -= 4; } else if (opcode == 0x0a) // jz { int32_t jmpoff = GetSignedOffset(&pcurr); dcurr -= 4; if (!LONG(dcurr)) { pcurr += jmpoff; } } else if (opcode == 0x0b) // jnz { int32_t jmpoff = GetSignedOffset(&pcurr); dcurr -= 4; if (LONG(dcurr)) { pcurr += jmpoff; } } else if (opcode >= 0x0c && opcode <= 0x15) { int32_t val, jmpoff, val2, val0; if (opcode == 0x0c) // casedone { dcurr -= 8; jmpoff = LONG(dcurr); pcurr = spinvars->pbase + jmpoff; } else if (opcode == 0x0d) // casevalue { jmpoff = GetSignedOffset(&pcurr); dcurr -= 4; val = LONG(dcurr); if (val == LONG(dcurr - 4)) { pcurr += jmpoff; } } else if (opcode == 0x0e) // caserange { jmpoff = GetSignedOffset(&pcurr); dcurr -= 4; val = LONG(dcurr); dcurr -= 4; val2 = LONG(dcurr); val0 = LONG(dcurr - 4); if (val <= val2) { if (val <= val0 && val0 <= val2) pcurr += jmpoff; } else { if (val2 <= val0 && val0 <= val) pcurr += jmpoff; } } else if (opcode == 0x0f) // lookdone { dcurr -= 8; LONG(dcurr - 4) = 0; } else if (opcode == 0x10) // lookupval { dcurr -= 4; val = LONG(dcurr); val0 = LONG(dcurr - 4); if (val0 < LONG(dcurr - 12)) { dcurr -= 8; pcurr = spinvars->pbase + LONG(dcurr); LONG(dcurr - 4) = 0; } else if (val0 == LONG(dcurr - 12)) { dcurr -= 8; pcurr = spinvars->pbase + LONG(dcurr); LONG(dcurr - 4) = val; } else { LONG(dcurr - 12)++; } } else if (opcode == 0x11) // lookdnval { dcurr -= 4; val = LONG(dcurr); val0 = LONG(dcurr - 4); if (val == val0) { dcurr -= 8; pcurr = spinvars->pbase + LONG(dcurr); } else { LONG(dcurr - 12)++; } } else if (opcode == 0x12) // lookuprng { int32_t num, count; dcurr -= 4; val = LONG(dcurr); dcurr -= 4; val2 = LONG(dcurr); val0 = LONG(dcurr - 4); num = val - val2; if (num < 0) num = -num; count = LONG(dcurr - 12); if (val0 < count) { dcurr -= 8; pcurr = spinvars->pbase + LONG(dcurr); LONG(dcurr - 4) = 0; } else if (val0 - num <= count) { dcurr -= 8; pcurr = spinvars->pbase + LONG(dcurr); num = val0 - count; if (val >= val2) { LONG(dcurr - 4) = val2 + num; } else { LONG(dcurr - 4) = val - num; } } else { LONG(dcurr - 12) += num + 1; } } else if (opcode == 0x13) // lookdnrng { dcurr -= 4; val = LONG(dcurr); dcurr -= 4; val2 = LONG(dcurr); if (val > val2) { val0 = val; val = val2; val2 = val0; } val0 = LONG(dcurr - 4); if (val <= val0 && val0 <= val2) { dcurr -= 8; pcurr = spinvars->pbase + LONG(dcurr); } else { LONG(dcurr - 12)++; } } else if (opcode == 0x14) // pop { dcurr -= 4; val = LONG(dcurr); dcurr -= val; } else if (opcode == 0x15) // run { spinvars->lsb = pcurr; pcurr = 0xfffc; } else fprintf(tracefile, "%4.4x %2.2x - NOT IMPLEMENTED%s", pcurr - 1, opcode, NEW_LINE); } else if (opcode >= 0x16 && opcode <= 0x23) { if (opcode == 0x16) // strsize { char *ptr = hubram; dcurr -= 4; LONG(dcurr) = strlen(ptr + LONG(dcurr)); dcurr += 4; } else if (opcode == 0x17) // strcomp { char *ptr1 = hubram; char *ptr2 = hubram; dcurr -= 4; ptr1 += LONG(dcurr); dcurr -= 4; ptr2 += LONG(dcurr); if (strcmp(ptr1, ptr2) == 0) LONG(dcurr) = -1; else LONG(dcurr) = 0; dcurr += 4; } else if (opcode == 0x18) // bytefill { int32_t val, num; char *ptr = hubram; dcurr -= 4; num = LONG(dcurr); dcurr -= 4; val = LONG(dcurr); dcurr -= 4; ptr += LONG(dcurr); memset(ptr, val, num); } else if (opcode == 0x19) // wordfill { int32_t val, num, addr; dcurr -= 4; num = LONG(dcurr); dcurr -= 4; val = LONG(dcurr); dcurr -= 4; addr = LONG(dcurr); while (num-- > 0) { WORD(addr) = val; addr += 2; } } else if (opcode == 0x1a) // longfill { int32_t val, num, addr; dcurr -= 4; num = LONG(dcurr); dcurr -= 4; val = LONG(dcurr); dcurr -= 4; addr = LONG(dcurr); while (num-- > 0) { LONG(addr) = val; addr += 4; } } else if (opcode == 0x1b) // waitpeq { dcurr -= 12; } else if (opcode >= 0x1c && opcode <= 0x1e ) // bytemove, wordmove, longmove { char *dst = hubram; char *src = hubram; int32_t num; dcurr -= 4; num = LONG(dcurr); dcurr -= 4; src += LONG(dcurr); dcurr -= 4; dst += LONG(dcurr); if (opcode == 0x1d) num <<= 1; else if (opcode == 0x1e) num <<= 2; memmove(dst, src, num); } else if (opcode == 0x1f) // waitpne { dcurr -= 12; } else if (opcode == 0x20) // clkset { int32_t clkfreq, clkmode; dcurr -= 4; clkfreq = LONG(dcurr); dcurr -= 4; clkmode = LONG(dcurr); if (clkmode & 0x80) { RebootProp(); return; } LONG(0) = clkfreq; BYTE(4) = clkmode; } else if (opcode == 0x21) // cogstop { int32_t cogid; dcurr -= 4; cogid = LONG(dcurr) & 7; PasmVars[cogid].state = 0; UpdatePins(); } else if (opcode == 0x22) // lockret { int32_t locknum; dcurr -= 4; locknum = LONG(dcurr) & 7; lockalloc[locknum] = 0; } else if (opcode == 0x23) // waitcnt { int32_t parm1; dcurr -= 4; parm1 = GetCnt() - LONG(dcurr); if (parm1 < 0 || parm1 > 20000000) { pcurr--; dcurr += 4; spinvars->state = 2; } else spinvars->state = 1; } } else if (opcode >= 0x24 && opcode <= 0x2f) { if (opcode >= 0x24 && opcode <= 0x26) // ldregx, stregx, exregx (spr) { int32_t operand; dcurr -= 4; operand = LONG(dcurr); operand = ((opcode & 3) << 5) | 0x10 | (operand & 15); spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; ExecuteRegisterOp(spinvars, operand, 31, 0); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else if (opcode == 0x27) // waitvid { dcurr -= 8; } else if (opcode == 0x28 || opcode == 0x2c) // coginitret, coginit { int32_t cogid, addr, par; dcurr -= 4; par = LONG(dcurr); dcurr -= 4; addr = LONG(dcurr); dcurr -= 4; cogid = LONG(dcurr); if (cogid < 0 || cogid > 7) { for (cogid = 0; cogid < 8; cogid++) { if (!PasmVars[cogid].state) break; } } if (cogid < 0 || cogid > 7) // || addr != 0xf004) cogid = -1; if (opcode == 0x28) { LONG(dcurr) = cogid; dcurr += 4; } if (cogid != -1) { if (addr == 0xf004) { spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; StartCog((SpinVarsT *)&PasmVars[cogid].mem[0x1e0], par, cogid); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else { StartPasmCog(&PasmVars[cogid], par, addr, cogid); } UpdatePins(); } } else if (opcode == 0x29 || opcode == 0x2d) // locknewret, locknew { int32_t locknum; for (locknum = 0; locknum < 8; locknum++) { if (!lockalloc[locknum]) { lockalloc[locknum] = 1; break; } } if (opcode == 0x29) { if (locknum == 8) locknum = -1; LONG(dcurr) = locknum; dcurr += 4; } } // locksetret, lockclrret, lockset, lockclr else if (opcode == 0x2a || opcode == 0x2b || opcode == 0x2e || opcode == 0x2f) { int32_t locknum; dcurr -= 4; locknum = LONG(dcurr) & 7; if (opcode <= 0x2b) { LONG(dcurr) = lockstate[locknum]; dcurr += 4; } lockstate[locknum] = (opcode & 1) - 1; } } else if (opcode >= 0x30 && opcode <= 0x33) // abort, abortval, ret, retval { int32_t retval, dbase, pbase; if (opcode & 1) retval = LONG(dcurr - 4); else retval = LONG(spinvars->dbase); dbase = spinvars->dbase; while (1) { dcurr = dbase - 8; pbase = WORD(dcurr); dbase = WORD(dcurr + 4); if ((opcode & 2) || (pbase & 2)) break; } spinvars->pbase = pbase & 0xfffc; spinvars->vbase = WORD(dcurr + 2); spinvars->dbase = dbase; pcurr = WORD(dcurr + 6); if (!(pbase & 1)) { LONG(dcurr) = retval; dcurr += 4; } } else if (opcode >= 0x34 && opcode < 0x3c) { if (opcode == 0x35) LONG(dcurr) = 0; // dli0 else if (opcode == 0x36) LONG(dcurr) = 1; // dli1 else if (opcode == 0x34) LONG(dcurr) = -1; // dlim1 else if (opcode == 0x37) // ldlip { int32_t val; int32_t operand = BYTE(pcurr++); int32_t rotate = operand & 31; if (rotate == 31) val = 1; else val = 2 << rotate; if (operand & 0x20) val--; if (operand & 0x40) val = ~val; LONG(dcurr) = val; } else // ldbi, ldwi, ldmi, ldli { int32_t operand = 0; while (opcode-- >= 0x38) operand = (operand << 8) | BYTE(pcurr++); LONG(dcurr) = operand; } dcurr += 4; } else if (opcode == 0x3d) // ldregbit, stregbit, exregbit { int32_t operand = BYTE(pcurr++); int32_t bitpos; dcurr -= 4; bitpos = LONG(dcurr) & 0x1f; spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; ExecuteRegisterOp(spinvars, operand, bitpos, bitpos); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else if (opcode == 0x3e) // ldregbits, stregbits, exregbits { int32_t operand = BYTE(pcurr++); int32_t msb, lsb; dcurr -= 4; lsb = LONG(dcurr) & 0x1f; dcurr -= 4; msb = LONG(dcurr) & 0x1f; spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; ExecuteRegisterOp(spinvars, operand, msb, lsb); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else if (opcode == 0x3f) // ldreg, streg, exreg { int32_t operand = BYTE(pcurr++); spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; ExecuteRegisterOp(spinvars, operand, 31, 0); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else { fprintf(tracefile, "NOT PROCESSED%s", NEW_LINE); } spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; } void ExecuteRegisterOp(SpinVarsT *spinvars, int32_t operand, int32_t msb, int32_t lsb) { int32_t opcode; int32_t parm1, parm2; int32_t pcurr = spinvars->pcurr; int32_t dcurr = spinvars->dcurr; int32_t *reg = (int32_t *)spinvars; int32_t memfunc = (operand >> 5) & 3; int32_t revflag = 0; int32_t mask, nbits; if (lsb > msb) { revflag = msb; msb = lsb; lsb = revflag; revflag = 1; } nbits = msb - lsb + 1; if (nbits >= 32) mask = -1; else mask = (1 << nbits) - 1; operand &= 0x1f; if (memfunc == 1) // store { spinvars->dcurr -= 4; if (nbits == 32 && !revflag) { reg[operand] = LONG(spinvars->dcurr); } else { parm1 = reg[operand]; parm2 = LONG(spinvars->dcurr); parm2 &= mask; if (revflag) parm2 = bitrev(parm2, nbits); reg[operand] = (parm1 & ~(mask << lsb)) | (parm2 << lsb); } if (operand == 0x14 || operand == 0x16) UpdatePins(); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else if (memfunc == 0) // load { if (operand == 0x11) // cnt = $1f1 parm1 = GetCnt(); else if (operand == 0x12) // ina = $1f2 parm1 = pin_val_a; else parm1 = reg[operand]; parm1 = (parm1 >> lsb) & mask; if (revflag) parm1 = bitrev(parm1, nbits); LONG(dcurr) = parm1; dcurr += 4; } else if (memfunc == 2) // execute { opcode = BYTE(spinvars->pcurr++); if (opcode & 0x7e) { if (operand == 0x11) // cnt = $1f1 parm1 = GetCnt(); else if (operand == 0x12) // ina = $1f2 parm1 = pin_val_a; else parm1 = reg[operand]; } else parm1 = 0; // Need to double check this parm2 = (parm1 >> lsb) & mask; if (revflag) parm2 = bitrev(parm2, nbits); parm2 = ExecuteExtraOp(spinvars, opcode, parm2, mask); parm2 &= mask; if (revflag) parm2 = bitrev(parm2, nbits); reg[operand] = (parm1 & ~(mask << lsb)) | (parm2 << lsb); if (operand == 0x14 || operand == 0x16) UpdatePins(); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else fprintf(tracefile, "Undefined register operation%s", NEW_LINE); spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; } void ExecuteMemoryOp(SpinVarsT *spinvars) { int32_t pcurr = spinvars->pcurr; int32_t dcurr = spinvars->dcurr; int32_t opcode, memfunc, memsize, membase, memaddr; opcode = BYTE(pcurr++); memfunc = opcode & 3; if (opcode < 0x80) // Compact offset { memsize = 3; memaddr = (opcode & 0x1c); membase = (opcode >> 5) & 3; } else { memsize = ((opcode >> 5) & 3) + 1; membase = (opcode & 0x0c) >> 2; // Check for index op if (opcode & 0x10) { dcurr -= 4; memaddr = LONG(dcurr) << (memsize - 1); } else memaddr = 0; if (membase) memaddr += GetUnsignedOffset(&pcurr); else { dcurr -= 4; memaddr += LONG(dcurr); } } if (membase == 1) memaddr += spinvars->pbase; else if (membase == 2) memaddr += spinvars->vbase; else if (membase == 3) memaddr += spinvars->dbase; if (memfunc == 3) // la { LONG(dcurr) = memaddr; dcurr += 4; } else if (memfunc == 0) // ld { if (memsize == 1) LONG(dcurr) = BYTE(memaddr); else if (memsize == 2) LONG(dcurr) = WORD(memaddr); else LONG(dcurr) = LONG(memaddr); dcurr += 4; } else if (memfunc == 1) // st { dcurr -= 4; if (memsize == 1) BYTE(memaddr) = LONG(dcurr); else if (memsize == 2) WORD(memaddr) = LONG(dcurr); else LONG(memaddr) = LONG(dcurr); } else // ex { int32_t parm1 = 0; opcode = BYTE(pcurr++); if (opcode & 0x7f) { if (memsize == 1) parm1 = BYTE(memaddr); else if (memsize == 2) parm1 = WORD(memaddr); else parm1 = LONG(memaddr); } spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; parm1 = ExecuteExtraOp(spinvars, opcode, parm1, -1); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; if (memsize == 1) BYTE(memaddr) = parm1; else if (memsize == 2) WORD(memaddr) = parm1; else LONG(memaddr) = parm1; } spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; } int32_t ExecuteExtraOp(SpinVarsT *spinvars, int32_t opcode, int32_t parm1, int32_t mask) { int32_t parm2; int32_t pcurr = spinvars->pcurr; int32_t dcurr = spinvars->dcurr; int32_t loadflag = opcode & 0x80; int32_t size = (opcode >> 1) & 3; if (size == 1) mask = 0xff; else if (size == 2) mask = 0xffff; else if (size == 3) mask = 0xffffffff; opcode &= 0x7f; if (opcode >= 0x40 && opcode < 0x60) // math op { parm2 = parm1 = ExecuteMathOp(spinvars, opcode, parm1); pcurr = spinvars->pcurr; dcurr = spinvars->dcurr; } else if ((opcode & 0x7e) == 0x00) // store { dcurr -= 4; parm2 = parm1 = LONG(dcurr); } else if ((opcode & 0x7a) == 0x02) // repeat, repeats { int32_t first, last, step, jmpoff; dcurr -= 4; last = LONG(dcurr); dcurr -= 4; first = LONG(dcurr); if (opcode == 0x06) { dcurr -= 4; step = LONG(dcurr); } else step = 1; jmpoff = GetSignedOffset(&pcurr); if (last >= first) { parm1 += step; if (parm1 >= first && parm1 <= last) pcurr += jmpoff; } else { parm1 -= step; if (parm1 <= first && parm1 >= last) pcurr += jmpoff; } parm2 = parm1; } else if ((opcode & 0x78) == 8) // randf, randr { uint32_t a, c, x, y, z; x = parm1; z = (opcode & 0x04) == 0; if (!x) x = 1; y = 32; a = 0x17; if (!z) a = (a >> 1) | (a << 31); while (y--) { c = x & a; while (c & 0xfffffffe) c = (c >> 1) ^ (c & 1); if (z) x = (x >> 1) | (c << 31); else x = (x << 1) | c; } parm2 = parm1 = x; } else if ((opcode & 0x7c) == 0x10) // sexb { parm2 = parm1 = (parm1 << 24) >> 24; } else if ((opcode & 0x7c) == 0x14) // sexw { parm2 = parm1 = (parm1 << 16) >> 16; } else if ((opcode & 0x7c) == 0x18) // postclr { parm2 = parm1; parm1 = 0; } else if ((opcode & 0x7c) == 0x1c) // postset { parm2 = parm1; parm1 = -1; } else if ((opcode & 0x78) == 0x20) // preinc { parm2 = ++parm1; parm2 &= mask; } else if ((opcode & 0x78) == 0x28) // postinc { parm2 = parm1++; parm2 &= mask; } else if ((opcode & 0x78) == 0x30) // predec { parm2 = --parm1; parm2 &= mask; } else if ((opcode & 0x78) == 0x38) // postdec { parm2 = parm1--; parm2 &= mask; } else { fprintf(tracefile, "NOT IMPLEMENTED%s", NEW_LINE); parm2 = 0; } if (loadflag) { LONG(dcurr) = parm2; dcurr += 4; } spinvars->pcurr = pcurr; spinvars->dcurr = dcurr; return parm1; } int32_t ExecuteMathOp(SpinVarsT *spinvars, int32_t opcode, int32_t parm1) { int32_t parm3; int32_t parm2 = 0; int32_t execflag = 0; int32_t unary; int32_t dcurr = spinvars->dcurr; unary = (0x810a02c0 >> (opcode & 0x1f)) & 1; // Get the parameters from the stack if (opcode < 0xe0) { execflag = 1; if (!unary) { if ((opcode >> 5) & 1) // Swap parms { parm2 = parm1; dcurr -= 4; parm1 = LONG(dcurr); } else { dcurr -= 4; parm2 = LONG(dcurr); } } opcode += 0xe0 - 0x40; } else { if (!unary) { dcurr -= 4; parm2 = LONG(dcurr); dcurr -= 4; parm1 = LONG(dcurr); } else { dcurr -= 4; parm1 = LONG(dcurr); } } // Execute the math op switch (opcode) { case 0xe0: // ror parm1 = (((uint32_t)parm1) >> parm2) | (parm1 << (32 - parm2)); break; case 0xe1: // rol parm1 = (((uint32_t)parm1) >> (32 - parm2)) | (parm1 << parm2); break; case 0xe2: // shr parm1 = ((uint32_t)parm1) >> parm2; break; case 0xe3: // shl parm1 <<= parm2; break; case 0xe4: // min if (parm2 > parm1) parm1 = parm2; break; case 0xe5: // max if (parm2 < parm1) parm1 = parm2; break; case 0xe6: // neg parm1 = -parm1; break; case 0xe7: // com parm1 = ~parm1; break; case 0xe8: // and parm1 &= parm2; break; case 0xe9: // abs if (parm1 < 0) parm1 = -parm1; break; case 0xea: // or parm1 |= parm2; break; case 0xeb: // xor parm1 ^= parm2; break; case 0xec: // add parm1 += parm2; break; case 0xed: // sub parm1 -= parm2; break; case 0xee: // sar parm1 >>= parm2; break; case 0xef: // rev parm1 = bitrev(parm1, parm2); break; case 0xf0: // andl parm1 = (parm1 && parm2) ? -1 : 0; break; case 0xf1: // encode for (parm2 = 32; parm2 >= 1; parm2--) { if (parm1 & 0x80000000) break; parm1 <<= 1; } parm1 = parm2; break; case 0xf4: // mul parm1 *= parm2; break; case 0xf5: // mulh { int64_t parm1a = parm1; int64_t parm2a = parm2; parm1 = (parm1a * parm2a) >> 32; } break; case 0xf2: // orl parm1 = (parm1 || parm2) ? -1 : 0; break; case 0xf3: // decode parm1 = 1 << parm1; break; case 0xf6: // div if (parm2) parm1 /= parm2; else parm1 = 0; break; case 0xf7: // mod if (parm2) parm1 %= parm2; else parm1 = 0; break; case 0xf8: // sqrt parm2 = 0; parm3 = 1 << 30; while (parm3) { parm2 |= parm3; if (parm2 <= parm1) { parm1 -= parm2; parm2 += parm3; } else parm2 -= parm3; parm2 >>= 1; parm3 >>= 2; } parm1 = parm2; break; case 0xf9: // cmplt parm1 = (parm1 < parm2) ? -1 : 0; break; case 0xfa: // cmpgt parm1 = (parm1 > parm2) ? -1 : 0; break; case 0xfb: // cmpne parm1 = (parm1 != parm2) ? -1 : 0; break; case 0xfc: // cmpeq parm1 = (parm1 == parm2) ? -1 : 0; break; case 0xfd: // cmple parm1 = (parm1 <= parm2) ? -1 : 0; break; case 0xfe: // cmpgr parm1 = (parm1 >= parm2) ? -1 : 0; break; case 0xff: // notl parm1 = parm1 ? 0 : -1; break; default: fprintf(tracefile, "NOT PROCESSED%s", NEW_LINE); } // Push the result back to the stack if (!execflag) { LONG(dcurr) = parm1; dcurr += 4; spinvars->pcurr++; } spinvars->dcurr = dcurr; return parm1; } void ExecuteOp(SpinVarsT *spinvars) { int32_t opcode; if (!spinvars->state) return; opcode = BYTE(spinvars->pcurr); if (opcode < 0x40) ExecuteLowerOp(spinvars); else if (opcode < 0xe0) ExecuteMemoryOp(spinvars); else ExecuteMathOp(spinvars, opcode, 0); } /* + -----------------------------------------------------------------------------------------------------------------------------+ | TERMS OF USE: MIT License | +------------------------------------------------------------------------------------------------------------------------------+ |Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation | |files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, | |modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software| |is furnished to do so, subject to the following conditions: | | | |The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.| | | |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | |WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | |COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | +------------------------------------------------------------------------------------------------------------------------------+ */