ARM7 update

- Added ARMv5TE instructions: QADD, QDADD, QSUB, QDSUB, SMLAxy, SMLALxy, SMULxy, SMULWy, and SMLAWy
- Fixed disassembly of CLZ
This commit is contained in:
R. Belmont 2009-07-19 03:13:17 +00:00
parent de00e07c02
commit 902ad0ce83
4 changed files with 348 additions and 25 deletions

View File

@ -73,6 +73,22 @@ INLINE arm_state *get_safe_token(const device_config *device)
return (arm_state *)device->token;
}
INLINE INT64 saturate_qbit_overflow(arm_state *cpustate, INT64 res)
{
if (res > 2147483647) // INT32_MAX
{ // overflow high? saturate and set Q
res = 2147483647;
SET_CPSR(GET_CPSR | Q_MASK);
}
else if (res < (-2147483647-1)) // INT32_MIN
{ // overflow low? saturate and set Q
res = (-2147483647-1);
SET_CPSR(GET_CPSR | Q_MASK);
}
return res;
}
/* include the arm7 core */
#include "arm7core.c"
@ -341,11 +357,12 @@ CPU_GET_INFO( arm7 )
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Steve Ellenoff, sellenoff@hotmail.com"); break;
case CPUINFO_STR_FLAGS:
sprintf(info->s, "%c%c%c%c%c%c%c %s",
sprintf(info->s, "%c%c%c%c%c%c%c%c %s",
(ARM7REG(eCPSR) & N_MASK) ? 'N' : '-',
(ARM7REG(eCPSR) & Z_MASK) ? 'Z' : '-',
(ARM7REG(eCPSR) & C_MASK) ? 'C' : '-',
(ARM7REG(eCPSR) & V_MASK) ? 'V' : '-',
(ARM7REG(eCPSR) & Q_MASK) ? 'Q' : '-',
(ARM7REG(eCPSR) & I_MASK) ? 'I' : '-',
(ARM7REG(eCPSR) & F_MASK) ? 'F' : '-',
(ARM7REG(eCPSR) & T_MASK) ? 'T' : '-',
@ -444,40 +461,57 @@ static READ32_DEVICE_HANDLER( arm7_rt_r_callback )
LOG( ( "arm7_rt_r_callback CR%d, RESERVED\n", cReg ) );
break;
case 0: // ID
switch (cpustate->archRev)
switch(op2)
{
case 3: // ARM6 32-bit
data = 0x41;
break;
case 0:
switch (cpustate->archRev)
{
case 3: // ARM6 32-bit
data = 0x41;
break;
case 4: // ARM7/SA11xx
data = 0x41 | (1 << 23) | (7 << 12);
break;
case 4: // ARM7/SA11xx
data = 0x41 | (1 << 23) | (7 << 12);
break;
case 5: // ARM9/10/XScale
data = 0x41 | (9 << 12);
if (cpustate->archFlags & eARM_ARCHFLAGS_T)
{
if (cpustate->archFlags & eARM_ARCHFLAGS_E)
case 5: // ARM9/10/XScale
data = 0x41 | (9 << 12);
if (cpustate->archFlags & eARM_ARCHFLAGS_T)
{
if (cpustate->archFlags & eARM_ARCHFLAGS_J)
if (cpustate->archFlags & eARM_ARCHFLAGS_E)
{
data |= (6<<16); // v5TEJ
if (cpustate->archFlags & eARM_ARCHFLAGS_J)
{
data |= (6<<16); // v5TEJ
}
else
{
data |= (5<<16); // v5TE
}
}
else
{
data |= (5<<16); // v5TE
data |= (4<<16); // v5T
}
}
else
{
data |= (4<<16); // v5T
}
}
break;
break;
case 6: // ARM11
data = 0x41 | (10<< 12) | (7<<16); // v6
case 6: // ARM11
data = 0x41 | (10<< 12) | (7<<16); // v6
break;
}
break;
case 1: // cache type
data = 0x0f0d2112; // HACK: value expected by ARMWrestler (probably Nintendo DS ARM9's value)
break;
case 2: // TCM type
data = 0;
break;
case 3: // TLB type
data = 0;
break;
case 4: // MPU type
data = 0;
break;
}
LOG( ( "arm7_rt_r_callback, ID\n" ) );

View File

@ -270,6 +270,7 @@ static const int sRegisterTable[ARM7_NUM_MODES][18] =
#define Z_BIT 30
#define C_BIT 29
#define V_BIT 28
#define Q_BIT 27
#define I_BIT 7
#define F_BIT 6
#define T_BIT 5 // Thumb mode
@ -278,6 +279,7 @@ static const int sRegisterTable[ARM7_NUM_MODES][18] =
#define Z_MASK ((UINT32)(1 << Z_BIT)) /* Zero flag */
#define C_MASK ((UINT32)(1 << C_BIT)) /* Carry flag */
#define V_MASK ((UINT32)(1 << V_BIT)) /* oVerflow flag */
#define Q_MASK ((UINT32)(1 << Q_BIT)) /* signed overflow for QADD, MAC */
#define I_MASK ((UINT32)(1 << I_BIT)) /* Interrupt request disable */
#define F_MASK ((UINT32)(1 << F_BIT)) /* Fast interrupt request disable */
#define T_MASK ((UINT32)(1 << T_BIT)) /* Thumb Mode flag */
@ -286,6 +288,7 @@ static const int sRegisterTable[ARM7_NUM_MODES][18] =
#define Z_IS_SET(pc) ((pc) & Z_MASK)
#define C_IS_SET(pc) ((pc) & C_MASK)
#define V_IS_SET(pc) ((pc) & V_MASK)
#define Q_IS_SET(pc) ((pc) & Q_MASK)
#define I_IS_SET(pc) ((pc) & I_MASK)
#define F_IS_SET(pc) ((pc) & F_MASK)
#define T_IS_SET(pc) ((pc) & T_MASK)
@ -294,6 +297,7 @@ static const int sRegisterTable[ARM7_NUM_MODES][18] =
#define Z_IS_CLEAR(pc) (!Z_IS_SET(pc))
#define C_IS_CLEAR(pc) (!C_IS_SET(pc))
#define V_IS_CLEAR(pc) (!V_IS_SET(pc))
#define Q_IS_CLEAR(pc) (!Q_IS_SET(pc))
#define I_IS_CLEAR(pc) (!I_IS_SET(pc))
#define F_IS_CLEAR(pc) (!F_IS_SET(pc))
#define T_IS_CLEAR(pc) (!T_IS_SET(pc))

View File

@ -233,7 +233,63 @@ UINT32 arm7_disasm( char *pBuf, UINT32 pc, UINT32 opcode )
}
else if ((opcode & 0x0ff000f0) == 0x01600010) // CLZ - v5
{
pBuf += sprintf(pBuf, "CLZ R%d, R%d", (opcode>>12)&0xf, opcode&0xf);
pBuf += sprintf(pBuf, "CLZ");
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d", (opcode>>12)&0xf, opcode&0xf);
}
else if ((opcode & 0x0ff000f0) == 0x01000050) // QADD - v5
{
pBuf += sprintf(pBuf, "QADD");
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf);
}
else if ((opcode & 0x0ff000f0) == 0x01400050) // QDADD - v5
{
pBuf += sprintf(pBuf, "QDADD");
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf);
}
else if ((opcode & 0x0ff000f0) == 0x01200050) // QSUB - v5
{
pBuf += sprintf(pBuf, "QSUB");
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf);
}
else if ((opcode & 0x0ff000f0) == 0x01600050) // QDSUB - v5
{
pBuf += sprintf(pBuf, "QDSUB");
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf);
}
else if ((opcode & 0x0ff00090) == 0x01000080) // SMLAxy - v5
{
pBuf += sprintf(pBuf, "SMLA%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B');
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d, R%d", (opcode>>16)&0xf, (opcode>>12)&0xf, opcode&0xf, (opcode>>8)&0xf);
}
else if ((opcode & 0x0ff00090) == 0x01400080) // SMLALxy - v5
{
pBuf += sprintf(pBuf, "SMLAL%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B');
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d, R%d", (opcode>>16)&0xf, (opcode>>12)&0xf, opcode&0xf, (opcode>>8)&0xf);
}
else if ((opcode & 0x0ff00090) == 0x01600080) // SMULxy - v5
{
pBuf += sprintf(pBuf, "SMUL%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B');
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>16)&0xf, opcode&0xf, (opcode>>12)&0xf);
}
else if ((opcode & 0x0ff000b0) == 0x012000a0) // SMULWy - v5
{
pBuf += sprintf(pBuf, "SMULW%c", (opcode&0x40) ? 'T' : 'B');
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>16)&0xf, opcode&0xf, (opcode>>8)&0xf);
}
else if ((opcode & 0x0ff000b0) == 0x01200080) // SMLAWy - v5
{
pBuf += sprintf(pBuf, "SMLAW%c", (opcode&0x40) ? 'T' : 'B');
pBuf = WritePadding( pBuf, pBuf0 );
pBuf += sprintf(pBuf, "R%d, R%d, R%d, R%d", (opcode>>16)&0xf, opcode&0xf, (opcode>>8)&0xf, (opcode>>12)&0xf);
}
else if( (opcode&0x0e000000)==0 && (opcode&0x80) && (opcode&0x10) ) //bits 27-25 == 000, bit 7=1, bit 4=1
{

View File

@ -1257,6 +1257,235 @@
R15 += 4;
}
else if ((insn & 0x0ff000f0) == 0x01000050) // QADD - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>16)&0xf);
INT64 res;
res = saturate_qbit_overflow(cpustate, (INT64)src1 + (INT64)src2);
SET_REGISTER(cpustate, (insn>>12)&0xf, (INT32)res);
R15 += 4;
}
else if ((insn & 0x0ff000f0) == 0x01400050) // QDADD - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>16)&0xf);
INT64 res;
// check if doubling operation will overflow
res = (INT64)src2 * 2;
saturate_qbit_overflow(cpustate, res);
src2 *= 2;
res = saturate_qbit_overflow(cpustate, (INT64)src1 + (INT64)src2);
SET_REGISTER(cpustate, (insn>>12)&0xf, (INT32)res);
R15 += 4;
}
else if ((insn & 0x0ff000f0) == 0x01200050) // QSUB - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>16)&0xf);
INT64 res;
res = saturate_qbit_overflow(cpustate, (INT64)src1 - (INT64)src2);
SET_REGISTER(cpustate, (insn>>12)&0xf, (INT32)res);
R15 += 4;
}
else if ((insn & 0x0ff000f0) == 0x01600050) // QDSUB - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>16)&0xf);
INT64 res;
// check if doubling operation will overflow
res = (INT64)src2 * 2;
saturate_qbit_overflow(cpustate, res);
src2 *= 2;
res = saturate_qbit_overflow(cpustate, (INT64)src1 - (INT64)src2);
SET_REGISTER(cpustate, (insn>>12)&0xf, (INT32)res);
R15 += 4;
}
else if ((insn & 0x0ff00090) == 0x01000080) // SMLAxy - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>8)&0xf);
INT32 res1;
// select top and bottom halves of src1/src2 and sign extend if necessary
if (insn & 0x20)
{
src1 >>= 16;
}
else
{
src1 &= 0xffff;
if (src1 & 0x8000)
{
src1 |= 0xffff;
}
}
if (insn & 0x40)
{
src2 >>= 16;
}
else
{
src2 &= 0xffff;
if (src2 & 0x8000)
{
src2 |= 0xffff;
}
}
// do the signed multiply
res1 = src1 * src2;
// and the accumulate. NOTE: only the accumulate can cause an overflow, which is why we do it this way.
saturate_qbit_overflow(cpustate, (INT64)res1 + (INT64)GET_REGISTER(cpustate, (insn>>12)&0xf));
SET_REGISTER(cpustate, (insn>>16)&0xf, res1 + GET_REGISTER(cpustate, (insn>>12)&0xf));
R15 += 4;
}
else if ((insn & 0x0ff00090) == 0x01400080) // SMLALxy - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>8)&0xf);
INT64 dst;
// select top and bottom halves of src1/src2 and sign extend if necessary
if (insn & 0x20)
{
src1 >>= 16;
}
else
{
src1 &= 0xffff;
if (src1 & 0x8000)
{
src1 |= 0xffff;
}
}
if (insn & 0x40)
{
src2 >>= 16;
}
else
{
src2 &= 0xffff;
if (src2 & 0x8000)
{
src2 |= 0xffff;
}
}
dst = (INT64)GET_REGISTER(cpustate, (insn>>12)&0xf);
dst |= (INT64)GET_REGISTER(cpustate, (insn>>16)&0xf)<<32;
// do the multiply and accumulate
dst += (INT64)src1 * (INT64)src2;
// write back the result
SET_REGISTER(cpustart, (insn>>12)&0xf, (UINT32)(dst&0xffffffff));
SET_REGISTER(cpustart, (insn>>16)&0xf, (UINT32)(dst>>32));
}
else if ((insn & 0x0ff00090) == 0x01600080) // SMULxy - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>8)&0xf);
INT32 res;
// select top and bottom halves of src1/src2 and sign extend if necessary
if (insn & 0x20)
{
src1 >>= 16;
}
else
{
src1 &= 0xffff;
if (src1 & 0x8000)
{
src1 |= 0xffff;
}
}
if (insn & 0x40)
{
src2 >>= 16;
}
else
{
src2 &= 0xffff;
if (src2 & 0x8000)
{
src2 |= 0xffff;
}
}
res = src1 * src2;
SET_REGISTER(cpustart, (insn>>16)&0xf, res);
}
else if ((insn & 0x0ff000b0) == 0x012000a0) // SMULWy - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>8)&0xf);
INT64 res;
if (insn & 0x40)
{
src2 >>= 16;
}
else
{
src2 &= 0xffff;
if (src2 & 0x8000)
{
src2 |= 0xffff;
}
}
res = (INT64)src1 * (INT64)src2;
res >>= 16;
SET_REGISTER(cpustart, (insn>>16)&0xf, (UINT32)res);
}
else if ((insn & 0x0ff000b0) == 0x01200080) // SMLAWy - v5
{
INT32 src1 = GET_REGISTER(cpustate, insn&0xf);
INT32 src2 = GET_REGISTER(cpustate, (insn>>8)&0xf);
INT32 src3 = GET_REGISTER(cpustate, (insn>>12)&0xf);
INT64 res;
if (insn & 0x40)
{
src2 >>= 16;
}
else
{
src2 &= 0xffff;
if (src2 & 0x8000)
{
src2 |= 0xffff;
}
}
res = (INT64)src1 * (INT64)src2;
res >>= 16;
// check for overflow and set the Q bit
saturate_qbit_overflow(cpustate, (INT64)src3 + res);
// do the real accumulate
src3 += (INT32)res;
// write the result back
SET_REGISTER(cpustart, (insn>>16)&0xf, (UINT32)res);
}
else
/* Multiply OR Swap OR Half Word Data Transfer */
if ((insn & 0x0e000000) == 0 && (insn & 0x80) && (insn & 0x10)) // bits 27-25=000 bit 7=1 bit 4=1