1131 lines
29 KiB
PHP
1131 lines
29 KiB
PHP
![]() |
/* V810 Emulator
|
||
|
*
|
||
|
* Copyright (C) 2006 David Tucker
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*/
|
||
|
|
||
|
|
||
|
// Macro test taken from http://gcc.gnu.org/viewcvs/trunk/gcc/testsuite/gcc.dg/20020919-1.c?view=markup&pathrev=142696
|
||
|
//#if defined (__powerpc__) || defined (__PPC__) || defined (__ppc__) || defined (__POWERPC__) || defined (PPC) || defined (_IBMR2)
|
||
|
// register v810_timestamp_t timestamp_rl asm("15") = v810_timestamp;
|
||
|
//#elif defined(__x86_64__)
|
||
|
// register v810_timestamp_t timestamp_rl asm("r11") = v810_timestamp;
|
||
|
//#else
|
||
|
register v810_timestamp_t timestamp_rl = v810_timestamp;
|
||
|
//#endif
|
||
|
|
||
|
uint32 opcode;
|
||
|
uint32 tmp2;
|
||
|
int val = 0;
|
||
|
|
||
|
|
||
|
#define ADDCLOCK(__n) { timestamp += __n; }
|
||
|
|
||
|
#define CHECK_HALTED(); { if(Halted && timestamp < next_event_ts) { timestamp = next_event_ts; } }
|
||
|
|
||
|
while(Running)
|
||
|
{
|
||
|
#ifdef RB_DEBUGMODE
|
||
|
uint32 old_PC = RB_GETPC();
|
||
|
#endif
|
||
|
uint32 tmpop;
|
||
|
|
||
|
assert(timestamp_rl <= next_event_ts);
|
||
|
|
||
|
if(!IPendingCache)
|
||
|
{
|
||
|
if(Halted)
|
||
|
{
|
||
|
timestamp_rl = next_event_ts;
|
||
|
}
|
||
|
else if(in_bstr)
|
||
|
{
|
||
|
tmpop = in_bstr_to;
|
||
|
opcode = tmpop >> 9;
|
||
|
goto op_BSTR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while(timestamp_rl < next_event_ts)
|
||
|
{
|
||
|
#ifdef RB_DEBUGMODE
|
||
|
old_PC = RB_GETPC();
|
||
|
#endif
|
||
|
|
||
|
P_REG[0] = 0; //Zero the Zero Reg!!!
|
||
|
|
||
|
RB_CPUHOOK(RB_GETPC());
|
||
|
|
||
|
{
|
||
|
//printf("%08x\n", RB_GETPC());
|
||
|
{
|
||
|
v810_timestamp_t timestamp = timestamp_rl;
|
||
|
|
||
|
tmpop = RB_RDOP(0, 0);
|
||
|
|
||
|
timestamp_rl = timestamp;
|
||
|
}
|
||
|
|
||
|
opcode = (tmpop >> 9) | IPendingCache;
|
||
|
|
||
|
//printf("%02x\n", opcode >> 1);
|
||
|
#if HAVE_COMPUTED_GOTO
|
||
|
#define CGBEGIN static const void *const op_goto_table[256] = {
|
||
|
#define CGE(l) &&l,
|
||
|
#define CGEND }; goto *op_goto_table[opcode];
|
||
|
#else
|
||
|
/* (uint8) cast for cheaper alternative to generated branch+compare bounds check instructions, but still more
|
||
|
expensive than computed goto which needs no masking nor bounds checking.
|
||
|
*/
|
||
|
#define CGBEGIN { enum { CGESB = 1 + __COUNTER__ }; switch((uint8)opcode) {
|
||
|
#define CGE(l) case __COUNTER__ - CGESB: goto l;
|
||
|
#define CGEND } }
|
||
|
#endif
|
||
|
|
||
|
CGBEGIN
|
||
|
CGE(op_MOV) CGE(op_MOV) CGE(op_ADD) CGE(op_ADD) CGE(op_SUB) CGE(op_SUB) CGE(op_CMP) CGE(op_CMP)
|
||
|
CGE(op_SHL) CGE(op_SHL) CGE(op_SHR) CGE(op_SHR) CGE(op_JMP) CGE(op_JMP) CGE(op_SAR) CGE(op_SAR)
|
||
|
CGE(op_MUL) CGE(op_MUL) CGE(op_DIV) CGE(op_DIV) CGE(op_MULU) CGE(op_MULU) CGE(op_DIVU) CGE(op_DIVU)
|
||
|
CGE(op_OR) CGE(op_OR) CGE(op_AND) CGE(op_AND) CGE(op_XOR) CGE(op_XOR) CGE(op_NOT) CGE(op_NOT)
|
||
|
CGE(op_MOV_I) CGE(op_MOV_I) CGE(op_ADD_I) CGE(op_ADD_I) CGE(op_SETF) CGE(op_SETF) CGE(op_CMP_I) CGE(op_CMP_I)
|
||
|
CGE(op_SHL_I) CGE(op_SHL_I) CGE(op_SHR_I) CGE(op_SHR_I) CGE(op_EI) CGE(op_EI) CGE(op_SAR_I) CGE(op_SAR_I)
|
||
|
CGE(op_TRAP) CGE(op_TRAP) CGE(op_RETI) CGE(op_RETI) CGE(op_HALT) CGE(op_HALT) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_LDSR) CGE(op_LDSR) CGE(op_STSR) CGE(op_STSR) CGE(op_DI) CGE(op_DI) CGE(op_BSTR) CGE(op_BSTR)
|
||
|
CGE(op_BV) CGE(op_BL) CGE(op_BE) CGE(op_BNH) CGE(op_BN) CGE(op_BR) CGE(op_BLT) CGE(op_BLE)
|
||
|
CGE(op_BNV) CGE(op_BNL) CGE(op_BNE) CGE(op_BH) CGE(op_BP) CGE(op_NOP) CGE(op_BGE) CGE(op_BGT)
|
||
|
CGE(op_MOVEA) CGE(op_MOVEA) CGE(op_ADDI) CGE(op_ADDI) CGE(op_JR) CGE(op_JR) CGE(op_JAL) CGE(op_JAL)
|
||
|
CGE(op_ORI) CGE(op_ORI) CGE(op_ANDI) CGE(op_ANDI) CGE(op_XORI) CGE(op_XORI) CGE(op_MOVHI) CGE(op_MOVHI)
|
||
|
CGE(op_LD_B) CGE(op_LD_B) CGE(op_LD_H) CGE(op_LD_H) CGE(op_INVALID) CGE(op_INVALID) CGE(op_LD_W) CGE(op_LD_W)
|
||
|
CGE(op_ST_B) CGE(op_ST_B) CGE(op_ST_H) CGE(op_ST_H) CGE(op_INVALID) CGE(op_INVALID) CGE(op_ST_W) CGE(op_ST_W)
|
||
|
CGE(op_IN_B) CGE(op_IN_B) CGE(op_IN_H) CGE(op_IN_H) CGE(op_CAXI) CGE(op_CAXI) CGE(op_IN_W) CGE(op_IN_W)
|
||
|
CGE(op_OUT_B) CGE(op_OUT_B) CGE(op_OUT_H) CGE(op_OUT_H) CGE(op_FPP) CGE(op_FPP) CGE(op_OUT_W) CGE(op_OUT_W)
|
||
|
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID)
|
||
|
CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INVALID) CGE(op_INT_HANDLER)
|
||
|
CGEND
|
||
|
|
||
|
// Bit string subopcodes
|
||
|
#define DO_AM_BSTR() \
|
||
|
const uint32 arg1 = (tmpop >> 5) & 0x1F; \
|
||
|
const uint32 arg2 = (tmpop & 0x1F); \
|
||
|
RB_INCPCBY2();
|
||
|
|
||
|
|
||
|
#define DO_AM_FPP() \
|
||
|
const uint32 arg1 = (tmpop >> 5) & 0x1F; \
|
||
|
const uint32 arg2 = (tmpop & 0x1F); \
|
||
|
const uint32 arg3 = ((RB_RDOP(2) >> 10)&0x3F); \
|
||
|
RB_INCPCBY4();
|
||
|
|
||
|
|
||
|
#define DO_AM_UDEF() \
|
||
|
RB_INCPCBY2();
|
||
|
|
||
|
#define DO_AM_I() \
|
||
|
const uint32 arg1 = tmpop & 0x1F; \
|
||
|
const uint32 arg2 = (tmpop >> 5) & 0x1F; \
|
||
|
RB_INCPCBY2();
|
||
|
|
||
|
#define DO_AM_II() DO_AM_I();
|
||
|
|
||
|
|
||
|
#define DO_AM_IV() \
|
||
|
const uint32 arg1 = ((tmpop & 0x000003FF) << 16) | RB_RDOP(2); \
|
||
|
|
||
|
|
||
|
#define DO_AM_V() \
|
||
|
const uint32 arg3 = (tmpop >> 5) & 0x1F; \
|
||
|
const uint32 arg2 = tmpop & 0x1F; \
|
||
|
const uint32 arg1 = RB_RDOP(2); \
|
||
|
RB_INCPCBY4();
|
||
|
|
||
|
|
||
|
#define DO_AM_VIa() \
|
||
|
const uint32 arg1 = RB_RDOP(2); \
|
||
|
const uint32 arg2 = tmpop & 0x1F; \
|
||
|
const uint32 arg3 = (tmpop >> 5) & 0x1F; \
|
||
|
RB_INCPCBY4(); \
|
||
|
|
||
|
|
||
|
#define DO_AM_VIb() \
|
||
|
const uint32 arg1 = (tmpop >> 5) & 0x1F; \
|
||
|
const uint32 arg2 = RB_RDOP(2); \
|
||
|
const uint32 arg3 = (tmpop & 0x1F); \
|
||
|
RB_INCPCBY4(); \
|
||
|
|
||
|
#define DO_AM_IX() \
|
||
|
const uint32 arg1 = (tmpop & 0x1); \
|
||
|
RB_INCPCBY2(); \
|
||
|
|
||
|
#define DO_AM_III() \
|
||
|
const uint32 arg1 = tmpop & 0x1FE;
|
||
|
|
||
|
#include "v810_do_am.h"
|
||
|
|
||
|
#define BEGIN_OP(meowtmpop) { op_##meowtmpop: v810_timestamp_t timestamp = timestamp_rl; DO_##meowtmpop ##_AM();
|
||
|
#define END_OP() timestamp_rl = timestamp; goto OpFinished; }
|
||
|
#define END_OP_SKIPLO() timestamp_rl = timestamp; goto OpFinishedSkipLO; }
|
||
|
|
||
|
BEGIN_OP(MOV);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg2, P_REG[arg1]);
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
BEGIN_OP(ADD);
|
||
|
ADDCLOCK(1);
|
||
|
uint32 temp = P_REG[arg2] + P_REG[arg1];
|
||
|
|
||
|
SetFlag(PSW_OV, ((P_REG[arg2]^(~P_REG[arg1]))&(P_REG[arg2]^temp))&0x80000000);
|
||
|
SetFlag(PSW_CY, temp < P_REG[arg2]);
|
||
|
|
||
|
SetPREG(arg2, temp);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
BEGIN_OP(SUB);
|
||
|
ADDCLOCK(1);
|
||
|
uint32 temp = P_REG[arg2] - P_REG[arg1];
|
||
|
|
||
|
SetFlag(PSW_OV, ((P_REG[arg2]^P_REG[arg1])&(P_REG[arg2]^temp))&0x80000000);
|
||
|
SetFlag(PSW_CY, temp > P_REG[arg2]);
|
||
|
|
||
|
SetPREG(arg2, temp);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
BEGIN_OP(CMP);
|
||
|
ADDCLOCK(1);
|
||
|
uint32 temp = P_REG[arg2] - P_REG[arg1];
|
||
|
|
||
|
SetSZ(temp);
|
||
|
SetFlag(PSW_OV, ((P_REG[arg2]^P_REG[arg1])&(P_REG[arg2]^temp))&0x80000000);
|
||
|
SetFlag(PSW_CY, temp > P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
BEGIN_OP(SHL);
|
||
|
ADDCLOCK(1);
|
||
|
val = P_REG[arg1] & 0x1F;
|
||
|
|
||
|
// set CY before we destroy the regisrer info....
|
||
|
SetFlag(PSW_CY, (val != 0) && ((P_REG[arg2] >> (32 - val))&0x01) );
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetPREG(arg2, P_REG[arg2] << val);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(SHR);
|
||
|
ADDCLOCK(1);
|
||
|
val = P_REG[arg1] & 0x1F;
|
||
|
// set CY before we destroy the regisrer info....
|
||
|
SetFlag(PSW_CY, (val) && ((P_REG[arg2] >> (val-1))&0x01));
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetPREG(arg2, P_REG[arg2] >> val);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(JMP);
|
||
|
|
||
|
(void)arg2; // arg2 is unused.
|
||
|
|
||
|
ADDCLOCK(3);
|
||
|
RB_SETPC((P_REG[arg1] & 0xFFFFFFFE));
|
||
|
if(RB_AccurateMode)
|
||
|
{
|
||
|
BRANCH_ALIGN_CHECK(PC);
|
||
|
}
|
||
|
RB_ADDBT(old_PC, RB_GETPC(), 0);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(SAR);
|
||
|
ADDCLOCK(1);
|
||
|
val = P_REG[arg1] & 0x1F;
|
||
|
|
||
|
SetFlag(PSW_CY, (val) && ((P_REG[arg2]>>(val-1))&0x01) );
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
|
||
|
SetPREG(arg2, (uint32) ((int32)P_REG[arg2] >> val));
|
||
|
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(OR);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg2, P_REG[arg1] | P_REG[arg2]);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(AND);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg2, P_REG[arg1] & P_REG[arg2]);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(XOR);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg2, P_REG[arg1] ^ P_REG[arg2]);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(NOT);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg2, ~P_REG[arg1]);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(MOV_I);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg2,sign_5(arg1));
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(ADD_I);
|
||
|
ADDCLOCK(1);
|
||
|
uint32 temp = P_REG[arg2] + sign_5(arg1);
|
||
|
|
||
|
SetFlag(PSW_OV, ((P_REG[arg2]^(~sign_5(arg1)))&(P_REG[arg2]^temp))&0x80000000);
|
||
|
SetFlag(PSW_CY, (uint32)temp < P_REG[arg2]);
|
||
|
|
||
|
SetPREG(arg2, (uint32)temp);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
BEGIN_OP(SETF);
|
||
|
ADDCLOCK(1);
|
||
|
|
||
|
P_REG[arg2] = 0;
|
||
|
|
||
|
switch (arg1 & 0x0F)
|
||
|
{
|
||
|
case COND_V:
|
||
|
if (TESTCOND_V) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_C:
|
||
|
if (TESTCOND_C) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_Z:
|
||
|
if (TESTCOND_Z) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_NH:
|
||
|
if (TESTCOND_NH) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_S:
|
||
|
if (TESTCOND_S) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_T:
|
||
|
P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_LT:
|
||
|
if (TESTCOND_LT) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_LE:
|
||
|
if (TESTCOND_LE) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_NV:
|
||
|
if (TESTCOND_NV) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_NC:
|
||
|
if (TESTCOND_NC) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_NZ:
|
||
|
if (TESTCOND_NZ) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_H:
|
||
|
if (TESTCOND_H) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_NS:
|
||
|
if (TESTCOND_NS) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_F:
|
||
|
//always false! do nothing more
|
||
|
break;
|
||
|
case COND_GE:
|
||
|
if (TESTCOND_GE) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
case COND_GT:
|
||
|
if (TESTCOND_GT) P_REG[arg2] = 1;
|
||
|
break;
|
||
|
}
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(CMP_I);
|
||
|
ADDCLOCK(1);
|
||
|
uint32 temp = P_REG[arg2] - sign_5(arg1);
|
||
|
|
||
|
SetSZ(temp);
|
||
|
SetFlag(PSW_OV, ((P_REG[arg2]^(sign_5(arg1)))&(P_REG[arg2]^temp))&0x80000000);
|
||
|
SetFlag(PSW_CY, temp > P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(SHR_I);
|
||
|
ADDCLOCK(1);
|
||
|
SetFlag(PSW_CY, arg1 && ((P_REG[arg2] >> (arg1-1))&0x01) );
|
||
|
// set CY before we destroy the regisrer info....
|
||
|
SetPREG(arg2, P_REG[arg2] >> arg1);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(SHL_I);
|
||
|
ADDCLOCK(1);
|
||
|
SetFlag(PSW_CY, arg1 && ((P_REG[arg2] >> (32 - arg1))&0x01) );
|
||
|
// set CY before we destroy the regisrer info....
|
||
|
|
||
|
SetPREG(arg2, P_REG[arg2] << arg1);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(SAR_I);
|
||
|
ADDCLOCK(1);
|
||
|
SetFlag(PSW_CY, arg1 && ((P_REG[arg2]>>(arg1-1))&0x01) );
|
||
|
|
||
|
SetPREG(arg2, (uint32) ((int32)P_REG[arg2] >> arg1));
|
||
|
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(LDSR); // Loads a Sys Reg with the value in specified PR
|
||
|
ADDCLOCK(1); // ?
|
||
|
|
||
|
SetSREG(timestamp, arg1 & 0x1F, P_REG[arg2 & 0x1F]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(STSR); // Loads a PR with the value in specified Sys Reg
|
||
|
ADDCLOCK(1); // ?
|
||
|
P_REG[arg2 & 0x1F] = GetSREG(arg1 & 0x1F);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(EI);
|
||
|
(void)arg1; // arg1 is unused.
|
||
|
(void)arg2; // arg2 is unused.
|
||
|
|
||
|
if(VBMode)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
S_REG[PSW] = S_REG[PSW] &~ PSW_ID;
|
||
|
RecalcIPendingCache();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
RB_DECPCBY2();
|
||
|
Exception(INVALID_OP_HANDLER_ADDR, ECODE_INVALID_OP);
|
||
|
CHECK_HALTED();
|
||
|
}
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(DI);
|
||
|
(void)arg1; // arg1 is unused.
|
||
|
(void)arg2; // arg2 is unused.
|
||
|
|
||
|
if(VBMode)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
S_REG[PSW] |= PSW_ID;
|
||
|
IPendingCache = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
RB_DECPCBY2();
|
||
|
Exception(INVALID_OP_HANDLER_ADDR, ECODE_INVALID_OP);
|
||
|
CHECK_HALTED();
|
||
|
}
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
#define COND_BRANCH(cond) \
|
||
|
if(cond) \
|
||
|
{ \
|
||
|
ADDCLOCK(3); \
|
||
|
RB_PCRELCHANGE(sign_9(arg1) & 0xFFFFFFFE); \
|
||
|
if(RB_AccurateMode) \
|
||
|
{ \
|
||
|
BRANCH_ALIGN_CHECK(PC); \
|
||
|
} \
|
||
|
RB_ADDBT(old_PC, RB_GETPC(), 0); \
|
||
|
} \
|
||
|
else \
|
||
|
{ \
|
||
|
ADDCLOCK(1); \
|
||
|
RB_INCPCBY2(); \
|
||
|
}
|
||
|
|
||
|
BEGIN_OP(BV);
|
||
|
COND_BRANCH(TESTCOND_V);
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
BEGIN_OP(BL);
|
||
|
COND_BRANCH(TESTCOND_L);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BE);
|
||
|
COND_BRANCH(TESTCOND_E);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BNH);
|
||
|
COND_BRANCH(TESTCOND_NH);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BN);
|
||
|
COND_BRANCH(TESTCOND_N);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BR);
|
||
|
COND_BRANCH(TRUE);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BLT);
|
||
|
COND_BRANCH(TESTCOND_LT);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BLE);
|
||
|
COND_BRANCH(TESTCOND_LE);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BNV);
|
||
|
COND_BRANCH(TESTCOND_NV);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BNL);
|
||
|
COND_BRANCH(TESTCOND_NL);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BNE);
|
||
|
COND_BRANCH(TESTCOND_NE);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BH);
|
||
|
COND_BRANCH(TESTCOND_H);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BP);
|
||
|
COND_BRANCH(TESTCOND_P);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BGE);
|
||
|
COND_BRANCH(TESTCOND_GE);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(BGT);
|
||
|
COND_BRANCH(TESTCOND_GT);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(JR);
|
||
|
ADDCLOCK(3);
|
||
|
RB_PCRELCHANGE(sign_26(arg1) & 0xFFFFFFFE);
|
||
|
if(RB_AccurateMode)
|
||
|
{
|
||
|
BRANCH_ALIGN_CHECK(PC);
|
||
|
}
|
||
|
RB_ADDBT(old_PC, RB_GETPC(), 0);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(JAL);
|
||
|
ADDCLOCK(3);
|
||
|
P_REG[31] = RB_GETPC() + 4;
|
||
|
RB_PCRELCHANGE(sign_26(arg1) & 0xFFFFFFFE);
|
||
|
if(RB_AccurateMode)
|
||
|
{
|
||
|
BRANCH_ALIGN_CHECK(PC);
|
||
|
}
|
||
|
RB_ADDBT(old_PC, RB_GETPC(), 0);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(MOVEA);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg3, P_REG[arg2] + sign_16(arg1));
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(ADDI);
|
||
|
ADDCLOCK(1);
|
||
|
uint32 temp = P_REG[arg2] + sign_16(arg1);
|
||
|
|
||
|
SetFlag(PSW_OV, ((P_REG[arg2]^(~sign_16(arg1)))&(P_REG[arg2]^temp))&0x80000000);
|
||
|
SetFlag(PSW_CY, (uint32)temp < P_REG[arg2]);
|
||
|
|
||
|
SetPREG(arg3, (uint32)temp);
|
||
|
SetSZ(P_REG[arg3]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(ORI);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg3, arg1 | P_REG[arg2]);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg3]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(ANDI);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg3, (arg1 & P_REG[arg2]));
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg3]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(XORI);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg3, arg1 ^ P_REG[arg2]);
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(P_REG[arg3]);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(MOVHI);
|
||
|
ADDCLOCK(1);
|
||
|
SetPREG(arg3, (arg1 << 16) + P_REG[arg2]);
|
||
|
END_OP();
|
||
|
|
||
|
// LD.B
|
||
|
BEGIN_OP(LD_B);
|
||
|
ADDCLOCK(1);
|
||
|
tmp2 = (sign_16(arg1)+P_REG[arg2])&0xFFFFFFFF;
|
||
|
|
||
|
SetPREG(arg3, sign_8(MemRead8(timestamp, tmp2)));
|
||
|
|
||
|
//should be 3 clocks when executed alone, 2 when precedes another LD, or 1
|
||
|
//when precedes an instruction with many clocks (I'm guessing FP, MUL, DIV, etc)
|
||
|
if(lastop >= 0)
|
||
|
{
|
||
|
if(lastop == LASTOP_LD)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(2);
|
||
|
}
|
||
|
}
|
||
|
lastop = LASTOP_LD;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
// LD.H
|
||
|
BEGIN_OP(LD_H);
|
||
|
ADDCLOCK(1);
|
||
|
tmp2 = (sign_16(arg1)+P_REG[arg2]) & 0xFFFFFFFE;
|
||
|
SetPREG(arg3, sign_16(MemRead16(timestamp, tmp2)));
|
||
|
|
||
|
if(lastop >= 0)
|
||
|
{
|
||
|
if(lastop == LASTOP_LD)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(2);
|
||
|
}
|
||
|
}
|
||
|
lastop = LASTOP_LD;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
|
||
|
// LD.W
|
||
|
BEGIN_OP(LD_W);
|
||
|
ADDCLOCK(1);
|
||
|
|
||
|
tmp2 = (sign_16(arg1)+P_REG[arg2]) & 0xFFFFFFFC;
|
||
|
|
||
|
if(MemReadBus32[tmp2 >> 24])
|
||
|
{
|
||
|
SetPREG(arg3, MemRead32(timestamp, tmp2));
|
||
|
|
||
|
if(lastop >= 0)
|
||
|
{
|
||
|
if(lastop == LASTOP_LD)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32 rv;
|
||
|
|
||
|
rv = MemRead16(timestamp, tmp2);
|
||
|
rv |= MemRead16(timestamp, tmp2 | 2) << 16;
|
||
|
|
||
|
SetPREG(arg3, rv);
|
||
|
|
||
|
if(lastop >= 0)
|
||
|
{
|
||
|
if(lastop == LASTOP_LD)
|
||
|
{
|
||
|
ADDCLOCK(3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(4);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
lastop = LASTOP_LD;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
// ST.B
|
||
|
BEGIN_OP(ST_B);
|
||
|
ADDCLOCK(1);
|
||
|
MemWrite8(timestamp, sign_16(arg2)+P_REG[arg3], P_REG[arg1] & 0xFF);
|
||
|
|
||
|
if(lastop == LASTOP_ST)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
lastop = LASTOP_ST;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
// ST.H
|
||
|
BEGIN_OP(ST_H);
|
||
|
ADDCLOCK(1);
|
||
|
|
||
|
MemWrite16(timestamp, (sign_16(arg2)+P_REG[arg3])&0xFFFFFFFE, P_REG[arg1] & 0xFFFF);
|
||
|
|
||
|
if(lastop == LASTOP_ST)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
lastop = LASTOP_ST;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
// ST.W
|
||
|
BEGIN_OP(ST_W);
|
||
|
ADDCLOCK(1);
|
||
|
tmp2 = (sign_16(arg2)+P_REG[arg3]) & 0xFFFFFFFC;
|
||
|
|
||
|
if(MemWriteBus32[tmp2 >> 24])
|
||
|
{
|
||
|
MemWrite32(timestamp, tmp2, P_REG[arg1]);
|
||
|
|
||
|
if(lastop == LASTOP_ST)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MemWrite16(timestamp, tmp2, P_REG[arg1] & 0xFFFF);
|
||
|
MemWrite16(timestamp, tmp2 | 2, P_REG[arg1] >> 16);
|
||
|
|
||
|
if(lastop == LASTOP_ST)
|
||
|
{
|
||
|
ADDCLOCK(3);
|
||
|
}
|
||
|
}
|
||
|
lastop = LASTOP_ST;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
// IN.B
|
||
|
BEGIN_OP(IN_B);
|
||
|
{
|
||
|
ADDCLOCK(3);
|
||
|
SetPREG(arg3, IORead8(timestamp, sign_16(arg1)+P_REG[arg2]));
|
||
|
}
|
||
|
lastop = LASTOP_IN;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
|
||
|
// IN.H
|
||
|
BEGIN_OP(IN_H);
|
||
|
{
|
||
|
ADDCLOCK(3);
|
||
|
SetPREG(arg3, IORead16(timestamp, (sign_16(arg1)+P_REG[arg2]) & 0xFFFFFFFE));
|
||
|
}
|
||
|
lastop = LASTOP_IN;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
|
||
|
// IN.W
|
||
|
BEGIN_OP(IN_W);
|
||
|
if(IORead32)
|
||
|
{
|
||
|
ADDCLOCK(3);
|
||
|
SetPREG(arg3, IORead32(timestamp, (sign_16(arg1)+P_REG[arg2]) & 0xFFFFFFFC));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32 eff_addr = (sign_16(arg1) + P_REG[arg2]) & 0xFFFFFFFC;
|
||
|
uint32 rv;
|
||
|
|
||
|
ADDCLOCK(5);
|
||
|
|
||
|
rv = IORead16(timestamp, eff_addr);
|
||
|
rv |= IORead16(timestamp, eff_addr | 2) << 16;
|
||
|
|
||
|
SetPREG(arg3, rv);
|
||
|
}
|
||
|
lastop = LASTOP_IN;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
|
||
|
// OUT.B
|
||
|
BEGIN_OP(OUT_B);
|
||
|
ADDCLOCK(1);
|
||
|
IOWrite8(timestamp, sign_16(arg2)+P_REG[arg3],P_REG[arg1]&0xFF);
|
||
|
|
||
|
if(lastop == LASTOP_OUT)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
lastop = LASTOP_OUT;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
|
||
|
// OUT.H
|
||
|
BEGIN_OP(OUT_H);
|
||
|
ADDCLOCK(1);
|
||
|
IOWrite16(timestamp, (sign_16(arg2)+P_REG[arg3])&0xFFFFFFFE,P_REG[arg1]&0xFFFF);
|
||
|
|
||
|
if(lastop == LASTOP_OUT)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
lastop = LASTOP_OUT;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
|
||
|
// OUT.W
|
||
|
BEGIN_OP(OUT_W);
|
||
|
ADDCLOCK(1);
|
||
|
|
||
|
if(IOWrite32)
|
||
|
IOWrite32(timestamp, (sign_16(arg2)+P_REG[arg3])&0xFFFFFFFC,P_REG[arg1]);
|
||
|
else
|
||
|
{
|
||
|
uint32 eff_addr = (sign_16(arg2)+P_REG[arg3])&0xFFFFFFFC;
|
||
|
IOWrite16(timestamp, eff_addr, P_REG[arg1] & 0xFFFF);
|
||
|
IOWrite16(timestamp, eff_addr | 2, P_REG[arg1] >> 16);
|
||
|
}
|
||
|
|
||
|
if(lastop == LASTOP_OUT)
|
||
|
{
|
||
|
if(IOWrite32)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(3);
|
||
|
}
|
||
|
}
|
||
|
lastop = LASTOP_OUT;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
BEGIN_OP(NOP);
|
||
|
(void)arg1; // arg1 is unused.
|
||
|
|
||
|
ADDCLOCK(1);
|
||
|
RB_INCPCBY2();
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(RETI);
|
||
|
(void)arg1; // arg1 is unused.
|
||
|
|
||
|
ADDCLOCK(10);
|
||
|
|
||
|
//Return from Trap/Interupt
|
||
|
if(S_REG[PSW] & PSW_NP) { // Read the FE Reg
|
||
|
RB_SETPC(S_REG[FEPC] & 0xFFFFFFFE);
|
||
|
S_REG[PSW] = S_REG[FEPSW];
|
||
|
} else { //Read the EI Reg Interupt
|
||
|
RB_SETPC(S_REG[EIPC] & 0xFFFFFFFE);
|
||
|
S_REG[PSW] = S_REG[EIPSW];
|
||
|
}
|
||
|
RecalcIPendingCache();
|
||
|
|
||
|
RB_ADDBT(old_PC, RB_GETPC(), 0);
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(MUL);
|
||
|
ADDCLOCK(13);
|
||
|
|
||
|
uint64 temp = (int64)(int32)P_REG[arg1] * (int32)P_REG[arg2];
|
||
|
|
||
|
SetPREG(30, (uint32)(temp >> 32));
|
||
|
SetPREG(arg2, temp);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
SetFlag(PSW_OV, temp != (uint64)(int64)(int32)(uint32)temp);
|
||
|
lastop = -1;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
BEGIN_OP(MULU);
|
||
|
ADDCLOCK(13);
|
||
|
uint64 temp = (uint64)P_REG[arg1] * (uint64)P_REG[arg2];
|
||
|
|
||
|
SetPREG(30, (uint32)(temp >> 32));
|
||
|
SetPREG(arg2, (uint32)temp);
|
||
|
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
SetFlag(PSW_OV, temp != (uint32)temp);
|
||
|
lastop = -1;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
BEGIN_OP(DIVU);
|
||
|
ADDCLOCK(36);
|
||
|
if(P_REG[arg1] == 0) // Divide by zero!
|
||
|
{
|
||
|
RB_DECPCBY2();
|
||
|
Exception(ZERO_DIV_HANDLER_ADDR, ECODE_ZERO_DIV);
|
||
|
CHECK_HALTED();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Careful here, since arg2 can be == 30
|
||
|
uint32 quotient = (uint32)P_REG[arg2] / (uint32)P_REG[arg1];
|
||
|
uint32 remainder = (uint32)P_REG[arg2] % (uint32)P_REG[arg1];
|
||
|
|
||
|
SetPREG(30, remainder);
|
||
|
SetPREG(arg2, quotient);
|
||
|
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(quotient);
|
||
|
}
|
||
|
lastop = -1;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
BEGIN_OP(DIV);
|
||
|
//if(P_REG[arg1] & P_REG[arg2] & 0x80000000)
|
||
|
//{
|
||
|
// printf("Div: %08x %08x\n", P_REG[arg1], P_REG[arg2]);
|
||
|
//}
|
||
|
|
||
|
ADDCLOCK(38);
|
||
|
if((uint32)P_REG[arg1] == 0) // Divide by zero!
|
||
|
{
|
||
|
RB_DECPCBY2();
|
||
|
Exception(ZERO_DIV_HANDLER_ADDR, ECODE_ZERO_DIV);
|
||
|
CHECK_HALTED();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if((P_REG[arg2]==0x80000000)&&(P_REG[arg1]==0xFFFFFFFF))
|
||
|
{
|
||
|
SetFlag(PSW_OV, TRUE);
|
||
|
P_REG[30]=0;
|
||
|
SetPREG(arg2, 0x80000000);
|
||
|
SetSZ(P_REG[arg2]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Careful here, since arg2 can be == 30
|
||
|
uint32 quotient = (int32)P_REG[arg2] / (int32)P_REG[arg1];
|
||
|
uint32 remainder = (int32)P_REG[arg2] % (int32)P_REG[arg1];
|
||
|
|
||
|
SetPREG(30, remainder);
|
||
|
SetPREG(arg2, quotient);
|
||
|
|
||
|
SetFlag(PSW_OV, FALSE);
|
||
|
SetSZ(quotient);
|
||
|
}
|
||
|
}
|
||
|
lastop = -1;
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
BEGIN_OP(FPP);
|
||
|
ADDCLOCK(1);
|
||
|
fpu_subop(timestamp, arg3, arg1, arg2);
|
||
|
lastop = -1;
|
||
|
CHECK_HALTED();
|
||
|
END_OP_SKIPLO();
|
||
|
|
||
|
BEGIN_OP(BSTR);
|
||
|
if(!in_bstr)
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
}
|
||
|
|
||
|
if(bstr_subop(timestamp, arg2, arg1))
|
||
|
{
|
||
|
RB_DECPCBY2();
|
||
|
in_bstr = TRUE;
|
||
|
in_bstr_to = tmpop;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
in_bstr = FALSE;
|
||
|
have_src_cache = have_dst_cache = FALSE;
|
||
|
}
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(HALT);
|
||
|
(void)arg1; // arg1 is unused.
|
||
|
|
||
|
ADDCLOCK(1);
|
||
|
Halted = HALT_HALT;
|
||
|
//printf("Untested opcode: HALT\n");
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(TRAP);
|
||
|
(void)arg2; // arg2 is unused.
|
||
|
|
||
|
ADDCLOCK(15);
|
||
|
|
||
|
Exception(TRAP_HANDLER_BASE + (arg1 & 0x10), ECODE_TRAP_BASE + (arg1 & 0x1F));
|
||
|
CHECK_HALTED();
|
||
|
END_OP();
|
||
|
|
||
|
BEGIN_OP(CAXI);
|
||
|
//printf("Untested opcode: caxi\n");
|
||
|
|
||
|
// Lock bus(N/A)
|
||
|
|
||
|
ADDCLOCK(26);
|
||
|
|
||
|
{
|
||
|
uint32 addr, tmp, compare_temp;
|
||
|
uint32 to_write;
|
||
|
|
||
|
addr = sign_16(arg1) + P_REG[arg2];
|
||
|
addr &= ~3;
|
||
|
|
||
|
if(MemReadBus32[addr >> 24])
|
||
|
tmp = MemRead32(timestamp, addr);
|
||
|
else
|
||
|
{
|
||
|
tmp = MemRead16(timestamp, addr);
|
||
|
tmp |= MemRead16(timestamp, addr | 2) << 16;
|
||
|
}
|
||
|
|
||
|
compare_temp = P_REG[arg3] - tmp;
|
||
|
|
||
|
SetSZ(compare_temp);
|
||
|
SetFlag(PSW_OV, ((P_REG[arg3]^tmp)&(P_REG[arg3]^compare_temp))&0x80000000);
|
||
|
SetFlag(PSW_CY, compare_temp > P_REG[arg3]);
|
||
|
|
||
|
if(!compare_temp) // If they're equal...
|
||
|
to_write = P_REG[30];
|
||
|
else
|
||
|
to_write = tmp;
|
||
|
|
||
|
if(MemWriteBus32[addr >> 24])
|
||
|
MemWrite32(timestamp, addr, to_write);
|
||
|
else
|
||
|
{
|
||
|
MemWrite16(timestamp, addr, to_write & 0xFFFF);
|
||
|
MemWrite16(timestamp, addr | 2, to_write >> 16);
|
||
|
}
|
||
|
P_REG[arg3] = tmp;
|
||
|
}
|
||
|
|
||
|
// Unlock bus(N/A)
|
||
|
|
||
|
END_OP();
|
||
|
|
||
|
|
||
|
|
||
|
op_INT_HANDLER:
|
||
|
{
|
||
|
int iNum = ilevel;
|
||
|
|
||
|
S_REG[EIPC] = GetPC();
|
||
|
S_REG[EIPSW] = S_REG[PSW];
|
||
|
|
||
|
SetPC(0xFFFFFE00 | (iNum << 4));
|
||
|
|
||
|
RB_ADDBT(old_PC, RB_GETPC(), 0xFE00 | (iNum << 4));
|
||
|
|
||
|
S_REG[ECR] = 0xFE00 | (iNum << 4);
|
||
|
|
||
|
S_REG[PSW] |= PSW_EP;
|
||
|
S_REG[PSW] |= PSW_ID;
|
||
|
S_REG[PSW] &= ~PSW_AE;
|
||
|
|
||
|
// Now, set need to set the interrupt enable level to he level that is being processed + 1,
|
||
|
// saturating at 15.
|
||
|
iNum++;
|
||
|
|
||
|
if(iNum > 0x0F)
|
||
|
iNum = 0x0F;
|
||
|
|
||
|
S_REG[PSW] &= ~PSW_IA;
|
||
|
S_REG[PSW] |= iNum << 16;
|
||
|
|
||
|
// Accepting an interrupt takes us out of normal HALT status, of course!
|
||
|
Halted = HALT_NONE;
|
||
|
|
||
|
// Invalidate our bitstring state(forces the instruction to be re-read, and the r/w buffers reloaded).
|
||
|
in_bstr = FALSE;
|
||
|
have_src_cache = FALSE;
|
||
|
have_dst_cache = FALSE;
|
||
|
|
||
|
IPendingCache = 0;
|
||
|
|
||
|
goto OpFinished;
|
||
|
}
|
||
|
|
||
|
|
||
|
BEGIN_OP(INVALID);
|
||
|
RB_DECPCBY2();
|
||
|
if(!RB_AccurateMode)
|
||
|
{
|
||
|
RB_SETPC(RB_GETPC());
|
||
|
if((uint32)(RB_RDOP(0, 0) >> 9) != opcode)
|
||
|
{
|
||
|
//printf("Trampoline: %08x %02x\n", RB_GETPC(), opcode >> 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
Exception(INVALID_OP_HANDLER_ADDR, ECODE_INVALID_OP);
|
||
|
CHECK_HALTED();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADDCLOCK(1);
|
||
|
Exception(INVALID_OP_HANDLER_ADDR, ECODE_INVALID_OP);
|
||
|
CHECK_HALTED();
|
||
|
}
|
||
|
END_OP();
|
||
|
|
||
|
}
|
||
|
|
||
|
OpFinished: ;
|
||
|
lastop = opcode;
|
||
|
OpFinishedSkipLO: ;
|
||
|
} // end while(timestamp_rl < next_event_ts)
|
||
|
next_event_ts = event_handler(timestamp_rl);
|
||
|
//printf("Next: %d, Cur: %d\n", next_event_ts, timestamp);
|
||
|
}
|
||
|
|
||
|
v810_timestamp = timestamp_rl;
|