summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2009-07-19 03:13:17 +0000
committer R. Belmont <rb6502@users.noreply.github.com>2009-07-19 03:13:17 +0000
commit902ad0ce830ec79e2a2f0684098dd635dcc44b51 (patch)
tree98fd7cf3aef062bd54eff051b5e534408dcaa66d
parentde00e07c02c8372c5ba9ceab0610e4c9e1cb1c90 (diff)
ARM7 update
- Added ARMv5TE instructions: QADD, QDADD, QSUB, QDSUB, SMLAxy, SMLALxy, SMULxy, SMULWy, and SMLAWy - Fixed disassembly of CLZ
-rw-r--r--src/emu/cpu/arm7/arm7.c86
-rw-r--r--src/emu/cpu/arm7/arm7core.h4
-rw-r--r--src/emu/cpu/arm7/arm7dasm.c58
-rw-r--r--src/emu/cpu/arm7/arm7exec.c229
4 files changed, 350 insertions, 27 deletions
diff --git a/src/emu/cpu/arm7/arm7.c b/src/emu/cpu/arm7/arm7.c
index d8a2566428b..29be89c5741 100644
--- a/src/emu/cpu/arm7/arm7.c
+++ b/src/emu/cpu/arm7/arm7.c
@@ -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 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 0:
+ switch (cpustate->archRev)
+ {
+ case 3: // ARM6 32-bit
+ data = 0x41;
+ 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_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;
+
+ 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 6: // ARM11
- data = 0x41 | (10<< 12) | (7<<16); // v6
+ 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" ) );
diff --git a/src/emu/cpu/arm7/arm7core.h b/src/emu/cpu/arm7/arm7core.h
index 779a668d9b0..6edd511f065 100644
--- a/src/emu/cpu/arm7/arm7core.h
+++ b/src/emu/cpu/arm7/arm7core.h
@@ -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))
diff --git a/src/emu/cpu/arm7/arm7dasm.c b/src/emu/cpu/arm7/arm7dasm.c
index 15520c8c69d..18ca7bdfa02 100644
--- a/src/emu/cpu/arm7/arm7dasm.c
+++ b/src/emu/cpu/arm7/arm7dasm.c
@@ -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
{
diff --git a/src/emu/cpu/arm7/arm7exec.c b/src/emu/cpu/arm7/arm7exec.c
index 0b023f09f25..9170f813623 100644
--- a/src/emu/cpu/arm7/arm7exec.c
+++ b/src/emu/cpu/arm7/arm7exec.c
@@ -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