mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-25 21:19:54 +00:00
Add support for XScale's coprocessor access check register.
Fix formatting.
This commit is contained in:
parent
25263aad5c
commit
ff44f8e352
@ -1,3 +1,22 @@
|
||||
2001-10-18 Nick Clifton <nickc@cambridge.redhat.com>
|
||||
|
||||
* armemu.h (CP_ACCESS_ALLOWED): New macro.
|
||||
Fix formatting.
|
||||
* armcopro.c (read_cp14_reg): Make static.
|
||||
(write_cp14_reg): Make static.
|
||||
(check_cp13_access): Use CP_ACCESS_ALLOWED macro.
|
||||
Fix formatting.
|
||||
* armsupp.c (ARMul_LDC): Check CP_ACCESS_ALLOWED.
|
||||
(ARMul_STC): Check CP_ACCESS_ALLOWED.
|
||||
(ARMul_MCR): Check CP_ACCESS_ALLOWED.
|
||||
(ARMul_MRC): Check CP_ACCESS_ALLOWED.
|
||||
(ARMul_CDP): Check CP_ACCESS_ALLOWED.
|
||||
Fix formatting.
|
||||
* armemu.c (MCRR): Check CP_ACCESS_ALLOWED. Test Rd and Rn not
|
||||
equal to 15.
|
||||
(MRRC): Check CP_ACCESS_ALLOWED. Test Rd and Rn not equal to 15.
|
||||
Fix formatting.
|
||||
|
||||
2001-05-11 Nick Clifton <nickc@cambridge.redhat.com>
|
||||
|
||||
* armemu.c (ARMul_Emulate32): Fix handling of XScale LDRD and STRD
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
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. */
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "armdefs.h"
|
||||
#include "armos.h"
|
||||
@ -51,6 +51,8 @@ NoCoPro4W (ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
/* The XScale Co-processors. */
|
||||
|
||||
/* Coprocessor 15: System Control. */
|
||||
static void write_cp14_reg (unsigned, ARMword);
|
||||
static ARMword read_cp14_reg (unsigned);
|
||||
|
||||
/* There are two sets of registers for copro 15.
|
||||
One set is available when opcode_2 is 0 and
|
||||
@ -83,7 +85,7 @@ XScale_cp15_init (ARMul_State * state ATTRIBUTE_UNUSED)
|
||||
|
||||
/* Initialise the ARM Control Register. */
|
||||
XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Check an access to a register. */
|
||||
@ -102,7 +104,7 @@ check_cp15_access (ARMul_State * state,
|
||||
/* Opcode_1should be zero. */
|
||||
if (opcode_1 != 0)
|
||||
return ARMul_CANT;
|
||||
|
||||
|
||||
/* Different register have different access requirements. */
|
||||
switch (reg)
|
||||
{
|
||||
@ -149,7 +151,7 @@ check_cp15_access (ARMul_State * state,
|
||||
case 0: if ((CRm < 5) || (CRm > 7)) return ARMul_CANT; break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 8:
|
||||
/* Permissable combinations:
|
||||
Opcode_2 CRm
|
||||
@ -205,14 +207,18 @@ check_cp15_access (ARMul_State * state,
|
||||
/* Should never happen. */
|
||||
return ARMul_CANT;
|
||||
}
|
||||
|
||||
|
||||
return ARMul_DONE;
|
||||
}
|
||||
|
||||
/* Store a value into one of coprocessor 15's registers. */
|
||||
|
||||
void
|
||||
write_cp15_reg (ARMul_State * state, unsigned reg, unsigned opcode_2, unsigned CRm, ARMword value)
|
||||
static void
|
||||
write_cp15_reg (ARMul_State * state,
|
||||
unsigned reg,
|
||||
unsigned opcode_2,
|
||||
unsigned CRm,
|
||||
ARMword value)
|
||||
{
|
||||
if (opcode_2)
|
||||
{
|
||||
@ -226,11 +232,11 @@ write_cp15_reg (ARMul_State * state, unsigned reg, unsigned opcode_2, unsigned C
|
||||
/* Only BITS (5, 4) and BITS (1, 0) can be written. */
|
||||
value &= 0x33;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
XScale_cp15_opcode_2_is_not_0_Regs [reg] = value;
|
||||
}
|
||||
else
|
||||
@ -261,11 +267,11 @@ write_cp15_reg (ARMul_State * state, unsigned reg, unsigned opcode_2, unsigned C
|
||||
/* Only BITS (31, 14) can be written. */
|
||||
value &= 0xffffc000;
|
||||
break;
|
||||
|
||||
|
||||
case 3: /* Domain Access Control. */
|
||||
/* All bits writable. */
|
||||
break;
|
||||
|
||||
|
||||
case 5: /* Fault Status Register. */
|
||||
/* BITS (10, 9) and BITS (7, 0) can be written. */
|
||||
value &= 0x000006ff;
|
||||
@ -319,18 +325,18 @@ write_cp15_reg (ARMul_State * state, unsigned reg, unsigned opcode_2, unsigned C
|
||||
/* Access is only valid if CRm == 1. */
|
||||
if (CRm != 1)
|
||||
return;
|
||||
|
||||
|
||||
/* Only BITS (13, 0) may be written. */
|
||||
value &= 0x00003fff;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
XScale_cp15_opcode_2_is_0_Regs [reg] = value;
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -356,7 +362,7 @@ read_cp15_reg (unsigned reg, unsigned opcode_2, unsigned CRm)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return XScale_cp15_opcode_2_is_0_Regs [reg];
|
||||
}
|
||||
else
|
||||
@ -372,7 +378,7 @@ XScale_cp15_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data
|
||||
unsigned result;
|
||||
|
||||
result = check_cp15_access (state, reg, 0, 0, 0);
|
||||
|
||||
|
||||
if (result == ARMul_DONE && type == ARMul_DATA)
|
||||
write_cp15_reg (state, reg, 0, 0, data);
|
||||
|
||||
@ -384,80 +390,79 @@ XScale_cp15_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * da
|
||||
{
|
||||
unsigned reg = BITS (12, 15);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp15_access (state, reg, 0, 0, 0);
|
||||
|
||||
|
||||
if (result == ARMul_DONE && type == ARMul_DATA)
|
||||
* data = read_cp15_reg (reg, 0, 0);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp15_MRC (ARMul_State * state,
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword * value)
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword * value)
|
||||
{
|
||||
unsigned opcode_2 = BITS (5, 7);
|
||||
unsigned CRm = BITS (0, 3);
|
||||
unsigned reg = BITS (16, 19);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp15_access (state, reg, CRm, BITS (21, 23), opcode_2);
|
||||
|
||||
|
||||
if (result == ARMul_DONE)
|
||||
* value = read_cp15_reg (reg, opcode_2, CRm);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp15_MCR (ARMul_State * state,
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword value)
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword value)
|
||||
{
|
||||
unsigned opcode_2 = BITS (5, 7);
|
||||
unsigned CRm = BITS (0, 3);
|
||||
unsigned reg = BITS (16, 19);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp15_access (state, reg, CRm, BITS (21, 23), opcode_2);
|
||||
|
||||
|
||||
if (result == ARMul_DONE)
|
||||
write_cp15_reg (state, reg, opcode_2, CRm, value);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp15_read_reg (ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
unsigned reg,
|
||||
ARMword * value)
|
||||
unsigned reg,
|
||||
ARMword * value)
|
||||
{
|
||||
/* FIXME: Not sure what to do about the alternative register set
|
||||
here. For now default to just accessing CRm == 0 registers. */
|
||||
* value = read_cp15_reg (reg, 0, 0);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp15_write_reg (ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
unsigned reg,
|
||||
ARMword value)
|
||||
unsigned reg,
|
||||
ARMword value)
|
||||
{
|
||||
/* FIXME: Not sure what to do about the alternative register set
|
||||
here. For now default to just accessing CRm == 0 registers. */
|
||||
write_cp15_reg (state, reg, 0, 0, value);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Check for special XScale memory access features *
|
||||
\***************************************************************************/
|
||||
/* Check for special XScale memory access features. */
|
||||
|
||||
void
|
||||
XScale_check_memacc (ARMul_State * state, ARMword * address, int store)
|
||||
{
|
||||
@ -515,11 +520,10 @@ XScale_check_memacc (ARMul_State * state, ARMword * address, int store)
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Check set
|
||||
\***************************************************************************/
|
||||
/* Check set. */
|
||||
|
||||
void
|
||||
XScale_set_fsr_far(ARMul_State * state, ARMword fsr, ARMword far)
|
||||
XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword far)
|
||||
{
|
||||
if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0)
|
||||
return;
|
||||
@ -529,6 +533,7 @@ XScale_set_fsr_far(ARMul_State * state, ARMword fsr, ARMword far)
|
||||
}
|
||||
|
||||
/* Set the XScale debug `method of entry' if it is enabled. */
|
||||
|
||||
int
|
||||
XScale_debug_moe (ARMul_State * state, int moe)
|
||||
{
|
||||
@ -589,12 +594,12 @@ check_cp13_access (ARMul_State * state,
|
||||
/* The opcodes should be zero. */
|
||||
if ((opcode_1 != 0) || (opcode_2 != 0))
|
||||
return ARMul_CANT;
|
||||
|
||||
/* Do not allow access to these register if bit 13 of coprocessor
|
||||
15's register 15 is zero. */
|
||||
if ((XScale_cp15_opcode_2_is_0_Regs[15] & (1 << 13)) == 0)
|
||||
|
||||
/* Do not allow access to these register if bit
|
||||
13 of coprocessor 15's register 15 is zero. */
|
||||
if (! CP_ACCESS_ALLOWED (state, 13))
|
||||
return ARMul_CANT;
|
||||
|
||||
|
||||
/* Registers 0, 4 and 8 are defined when CRm == 0.
|
||||
Registers 0, 4, 5, 6, 7, 8 are defined when CRm == 1.
|
||||
For all other CRm values undefined behaviour results. */
|
||||
@ -626,21 +631,21 @@ write_cp13_reg (unsigned reg, unsigned CRm, ARMword value)
|
||||
/* Only BITS (3:0) can be written. */
|
||||
value &= 0xf;
|
||||
break;
|
||||
|
||||
|
||||
case 4: /* INTSRC */
|
||||
/* No bits may be written. */
|
||||
return;
|
||||
|
||||
|
||||
case 8: /* INTSTR */
|
||||
/* Only BITS (1:0) can be written. */
|
||||
value &= 0x3;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* Should not happen. Ignore any writes to unimplemented registers. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
XScale_cp13_CR0_Regs [reg] = value;
|
||||
break;
|
||||
|
||||
@ -653,7 +658,7 @@ write_cp13_reg (unsigned reg, unsigned CRm, ARMword value)
|
||||
value &= 0x7000000f;
|
||||
value |= XScale_cp13_CR1_Regs[0] & (1UL << 31);
|
||||
break;
|
||||
|
||||
|
||||
case 4: /* ELOG0 */
|
||||
case 5: /* ELOG1 */
|
||||
case 6: /* ECAR0 */
|
||||
@ -665,12 +670,12 @@ write_cp13_reg (unsigned reg, unsigned CRm, ARMword value)
|
||||
/* Only BITS (7:0) can be written. */
|
||||
value &= 0xff;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* Should not happen. Ignore any writes to unimplemented registers. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
XScale_cp13_CR1_Regs [reg] = value;
|
||||
break;
|
||||
|
||||
@ -678,7 +683,7 @@ write_cp13_reg (unsigned reg, unsigned CRm, ARMword value)
|
||||
/* Should not happen. */
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -700,9 +705,9 @@ XScale_cp13_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data
|
||||
{
|
||||
unsigned reg = BITS (12, 15);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp13_access (state, reg, 0, 0, 0);
|
||||
|
||||
|
||||
if (result == ARMul_DONE && type == ARMul_DATA)
|
||||
write_cp13_reg (reg, 0, data);
|
||||
|
||||
@ -714,78 +719,72 @@ XScale_cp13_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * da
|
||||
{
|
||||
unsigned reg = BITS (12, 15);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp13_access (state, reg, 0, 0, 0);
|
||||
|
||||
|
||||
if (result == ARMul_DONE && type == ARMul_DATA)
|
||||
* data = read_cp13_reg (reg, 0);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp13_MRC (ARMul_State * state,
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword * value)
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword * value)
|
||||
{
|
||||
unsigned CRm = BITS (0, 3);
|
||||
unsigned reg = BITS (16, 19);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp13_access (state, reg, CRm, BITS (21, 23), BITS (5, 7));
|
||||
|
||||
|
||||
if (result == ARMul_DONE)
|
||||
* value = read_cp13_reg (reg, CRm);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp13_MCR (ARMul_State * state,
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword value)
|
||||
unsigned type ATTRIBUTE_UNUSED,
|
||||
ARMword instr,
|
||||
ARMword value)
|
||||
{
|
||||
unsigned CRm = BITS (0, 3);
|
||||
unsigned reg = BITS (16, 19);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp13_access (state, reg, CRm, BITS (21, 23), BITS (5, 7));
|
||||
|
||||
|
||||
if (result == ARMul_DONE)
|
||||
write_cp13_reg (reg, CRm, value);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp13_read_reg
|
||||
(
|
||||
ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
unsigned reg,
|
||||
ARMword * value
|
||||
)
|
||||
XScale_cp13_read_reg (ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
unsigned reg,
|
||||
ARMword * value)
|
||||
{
|
||||
/* FIXME: Not sure what to do about the alternative register set
|
||||
here. For now default to just accessing CRm == 0 registers. */
|
||||
* value = read_cp13_reg (reg, 0);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
XScale_cp13_write_reg
|
||||
(
|
||||
ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
unsigned reg,
|
||||
ARMword value
|
||||
)
|
||||
XScale_cp13_write_reg (ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
unsigned reg,
|
||||
ARMword value)
|
||||
{
|
||||
/* FIXME: Not sure what to do about the alternative register set
|
||||
here. For now default to just accessing CRm == 0 registers. */
|
||||
write_cp13_reg (reg, 0, value);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -823,7 +822,7 @@ check_cp14_access (ARMul_State * state,
|
||||
/* OPcodes should be zero. */
|
||||
if (opcode1 != 0 || opcode2 != 0)
|
||||
return ARMul_CANT;
|
||||
|
||||
|
||||
/* Accessing registers 4 or 5 has unpredicatable results. */
|
||||
if (reg >= 4 && reg <= 5)
|
||||
return ARMul_CANT;
|
||||
@ -833,7 +832,7 @@ check_cp14_access (ARMul_State * state,
|
||||
|
||||
/* Store a value into one of coprocessor 14's registers. */
|
||||
|
||||
void
|
||||
static void
|
||||
write_cp14_reg (unsigned reg, ARMword value)
|
||||
{
|
||||
switch (reg)
|
||||
@ -853,7 +852,7 @@ write_cp14_reg (unsigned reg, ARMword value)
|
||||
can bypass the normal checks though, so it could happen. */
|
||||
value = 0;
|
||||
break;
|
||||
|
||||
|
||||
case 6: /* CCLKCFG */
|
||||
/* Only BITS (3:0) can be written. */
|
||||
value &= 0xf;
|
||||
@ -864,7 +863,7 @@ write_cp14_reg (unsigned reg, ARMword value)
|
||||
have the side effect of putting the processor to sleep. Thus in
|
||||
order for the register to be read again, it would have to go into
|
||||
ACTIVE mode, which means that any read will see these bits as zero.
|
||||
|
||||
|
||||
Rather than trying to implement complex reset-to-zero-upon-read logic
|
||||
we just override the write value with zero. */
|
||||
value = 0;
|
||||
@ -880,12 +879,12 @@ write_cp14_reg (unsigned reg, ARMword value)
|
||||
/* No writes are permitted. */
|
||||
value = 0;
|
||||
break;
|
||||
|
||||
|
||||
case 14: /* TXRXCTRL */
|
||||
/* Only BITS (31:30) can be written. */
|
||||
value &= 0xc0000000;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* All bits can be written. */
|
||||
break;
|
||||
@ -908,9 +907,9 @@ XScale_cp14_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data
|
||||
{
|
||||
unsigned reg = BITS (12, 15);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp14_access (state, reg, 0, 0, 0);
|
||||
|
||||
|
||||
if (result == ARMul_DONE && type == ARMul_DATA)
|
||||
write_cp14_reg (reg, data);
|
||||
|
||||
@ -922,12 +921,12 @@ XScale_cp14_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * da
|
||||
{
|
||||
unsigned reg = BITS (12, 15);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp14_access (state, reg, 0, 0, 0);
|
||||
|
||||
|
||||
if (result == ARMul_DONE && type == ARMul_DATA)
|
||||
* data = read_cp14_reg (reg);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -942,12 +941,12 @@ XScale_cp14_MRC
|
||||
{
|
||||
unsigned reg = BITS (16, 19);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp14_access (state, reg, BITS (0, 3), BITS (21, 23), BITS (5, 7));
|
||||
|
||||
|
||||
if (result == ARMul_DONE)
|
||||
* value = read_cp14_reg (reg);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -962,12 +961,12 @@ XScale_cp14_MCR
|
||||
{
|
||||
unsigned reg = BITS (16, 19);
|
||||
unsigned result;
|
||||
|
||||
|
||||
result = check_cp14_access (state, reg, BITS (0, 3), BITS (21, 23), BITS (5, 7));
|
||||
|
||||
|
||||
if (result == ARMul_DONE)
|
||||
write_cp14_reg (reg, value);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -980,7 +979,7 @@ XScale_cp14_read_reg
|
||||
)
|
||||
{
|
||||
* value = read_cp14_reg (reg);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -993,7 +992,7 @@ XScale_cp14_write_reg
|
||||
)
|
||||
{
|
||||
write_cp14_reg (reg, value);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -1052,7 +1051,7 @@ MMUMCR (ARMul_State * state,
|
||||
d = state->data32Sig;
|
||||
l = state->lateabtSig;
|
||||
b = state->bigendSig;
|
||||
|
||||
|
||||
state->prog32Sig = value >> 4 & 1;
|
||||
state->data32Sig = value >> 5 & 1;
|
||||
state->lateabtSig = value >> 6 & 1;
|
||||
@ -1094,12 +1093,12 @@ MMUWrite (ARMul_State * state, unsigned reg, ARMword value)
|
||||
d = state->data32Sig;
|
||||
l = state->lateabtSig;
|
||||
b = state->bigendSig;
|
||||
|
||||
|
||||
state->prog32Sig = value >> 4 & 1;
|
||||
state->data32Sig = value >> 5 & 1;
|
||||
state->lateabtSig = value >> 6 & 1;
|
||||
state->bigendSig = value >> 7 & 1;
|
||||
|
||||
|
||||
if ( p != state->prog32Sig
|
||||
|| d != state->data32Sig
|
||||
|| l != state->lateabtSig
|
||||
@ -1144,7 +1143,7 @@ ValLDC (ARMul_State * state ATTRIBUTE_UNUSED,
|
||||
if (words++ != 4)
|
||||
return ARMul_INC;
|
||||
}
|
||||
|
||||
|
||||
return ARMul_DONE;
|
||||
}
|
||||
|
||||
@ -1204,12 +1203,12 @@ ValCDP (ARMul_State * state, unsigned type, ARMword instr)
|
||||
if (type == ARMul_FIRST)
|
||||
{
|
||||
ARMword howlong;
|
||||
|
||||
|
||||
howlong = ValReg[BITS (0, 3)];
|
||||
|
||||
|
||||
/* First cycle of a busy wait. */
|
||||
finish = ARMul_Time (state) + howlong;
|
||||
|
||||
|
||||
return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
|
||||
}
|
||||
else if (type == ARMul_BUSY)
|
||||
@ -1219,7 +1218,7 @@ ValCDP (ARMul_State * state, unsigned type, ARMword instr)
|
||||
else
|
||||
return ARMul_BUSY;
|
||||
}
|
||||
|
||||
|
||||
return ARMul_CANT;
|
||||
}
|
||||
|
||||
@ -1265,42 +1264,40 @@ IntCDP (ARMul_State * state, unsigned type, ARMword instr)
|
||||
return ARMul_BUSY;
|
||||
}
|
||||
return ARMul_DONE;
|
||||
|
||||
|
||||
case 1:
|
||||
if (howlong == 0)
|
||||
ARMul_Abort (state, ARMul_FIQV);
|
||||
else
|
||||
ARMul_ScheduleEvent (state, howlong, DoAFIQ);
|
||||
return ARMul_DONE;
|
||||
|
||||
|
||||
case 2:
|
||||
if (howlong == 0)
|
||||
ARMul_Abort (state, ARMul_IRQV);
|
||||
else
|
||||
ARMul_ScheduleEvent (state, howlong, DoAIRQ);
|
||||
return ARMul_DONE;
|
||||
|
||||
|
||||
case 3:
|
||||
state->NfiqSig = HIGH;
|
||||
state->Exception--;
|
||||
return ARMul_DONE;
|
||||
|
||||
|
||||
case 4:
|
||||
state->NirqSig = HIGH;
|
||||
state->Exception--;
|
||||
return ARMul_DONE;
|
||||
|
||||
|
||||
case 5:
|
||||
ValReg[BITS (0, 3)] = ARMul_Time (state);
|
||||
return ARMul_DONE;
|
||||
}
|
||||
|
||||
|
||||
return ARMul_CANT;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Install co-processor instruction handlers in this routine *
|
||||
\***************************************************************************/
|
||||
/* Install co-processor instruction handlers in this routine. */
|
||||
|
||||
unsigned
|
||||
ARMul_CoProInit (ARMul_State * state)
|
||||
@ -1332,12 +1329,12 @@ ARMul_CoProInit (ARMul_State * state)
|
||||
XScale_cp13_LDC, XScale_cp13_STC, XScale_cp13_MRC,
|
||||
XScale_cp13_MCR, NULL, XScale_cp13_read_reg,
|
||||
XScale_cp13_write_reg);
|
||||
|
||||
|
||||
ARMul_CoProAttach (state, 14, XScale_cp14_init, NULL,
|
||||
XScale_cp14_LDC, XScale_cp14_STC, XScale_cp14_MRC,
|
||||
XScale_cp14_MCR, NULL, XScale_cp14_read_reg,
|
||||
XScale_cp14_write_reg);
|
||||
|
||||
|
||||
ARMul_CoProAttach (state, 15, XScale_cp15_init, NULL,
|
||||
NULL, NULL, XScale_cp15_MRC, XScale_cp15_MCR,
|
||||
NULL, XScale_cp15_read_reg, XScale_cp15_write_reg);
|
||||
@ -1352,9 +1349,7 @@ ARMul_CoProInit (ARMul_State * state)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Install co-processor finalisation routines in this routine *
|
||||
\***************************************************************************/
|
||||
/* Install co-processor finalisation routines in this routine. */
|
||||
|
||||
void
|
||||
ARMul_CoProExit (ARMul_State * state)
|
||||
@ -1369,9 +1364,7 @@ ARMul_CoProExit (ARMul_State * state)
|
||||
ARMul_CoProDetach (state, i);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Routines to hook Co-processors into ARMulator *
|
||||
\***************************************************************************/
|
||||
/* Routines to hook Co-processors into ARMulator. */
|
||||
|
||||
void
|
||||
ARMul_CoProAttach (ARMul_State * state,
|
||||
|
881
sim/arm/armemu.c
881
sim/arm/armemu.c
File diff suppressed because it is too large
Load Diff
407
sim/arm/armemu.h
407
sim/arm/armemu.h
@ -17,10 +17,7 @@
|
||||
|
||||
extern ARMword isize;
|
||||
|
||||
/***************************************************************************\
|
||||
* Condition code values *
|
||||
\***************************************************************************/
|
||||
|
||||
/* Condition code values. */
|
||||
#define EQ 0
|
||||
#define NE 1
|
||||
#define CS 2
|
||||
@ -38,19 +35,13 @@ extern ARMword isize;
|
||||
#define AL 14
|
||||
#define NV 15
|
||||
|
||||
/***************************************************************************\
|
||||
* Shift Opcodes *
|
||||
\***************************************************************************/
|
||||
|
||||
/* Shift Opcodes. */
|
||||
#define LSL 0
|
||||
#define LSR 1
|
||||
#define ASR 2
|
||||
#define ROR 3
|
||||
|
||||
/***************************************************************************\
|
||||
* Macros to twiddle the status flags and mode *
|
||||
\***************************************************************************/
|
||||
|
||||
/* Macros to twiddle the status flags and mode. */
|
||||
#define NBIT ((unsigned)1L << 31)
|
||||
#define ZBIT (1L << 30)
|
||||
#define CBIT (1L << 29)
|
||||
@ -66,7 +57,7 @@ extern ARMword isize;
|
||||
#define POS(i) ( (~(i)) >> 31 )
|
||||
#define NEG(i) ( (i) >> 31 )
|
||||
|
||||
#ifdef MODET /* Thumb support */
|
||||
#ifdef MODET /* Thumb support. */
|
||||
/* ??? This bit is actually in the low order bit of the PC in the hardware.
|
||||
It isn't clear if the simulator needs to model that or not. */
|
||||
#define TBIT (1L << 5)
|
||||
@ -181,95 +172,130 @@ extern ARMword isize;
|
||||
#define SETPSR_S(d,s) d = ((d) & ~PSR_SBITS) | ((s) & PSR_SBITS)
|
||||
#define SETPSR_X(d,s) d = ((d) & ~PSR_XBITS) | ((s) & PSR_XBITS)
|
||||
#define SETPSR_C(d,s) d = ((d) & ~PSR_CBITS) | ((s) & PSR_CBITS)
|
||||
#define SETR15PSR(s) if (state->Mode == USER26MODE) { \
|
||||
state->Reg[15] = ((s) & CCBITS) | R15PC | ER15INT | EMODE ; \
|
||||
ASSIGNN((state->Reg[15] & NBIT) != 0) ; \
|
||||
ASSIGNZ((state->Reg[15] & ZBIT) != 0) ; \
|
||||
ASSIGNC((state->Reg[15] & CBIT) != 0) ; \
|
||||
ASSIGNV((state->Reg[15] & VBIT) != 0) ; \
|
||||
} \
|
||||
else { \
|
||||
state->Reg[15] = R15PC | ((s) & (CCBITS | R15INTBITS | R15MODEBITS)) ; \
|
||||
ARMul_R15Altered (state) ; \
|
||||
}
|
||||
#define SETABORT(i,m,d) do { \
|
||||
int SETABORT_mode = (m); \
|
||||
ARMul_SetSPSR (state, SETABORT_mode, ARMul_GetCPSR (state)); \
|
||||
ARMul_SetCPSR (state, ((ARMul_GetCPSR (state) & ~(EMODE | TBIT)) \
|
||||
| (i) | SETABORT_mode)); \
|
||||
state->Reg[14] = temp - (d); \
|
||||
} while (0)
|
||||
|
||||
#define SETR15PSR(s) \
|
||||
do \
|
||||
{ \
|
||||
if (state->Mode == USER26MODE) \
|
||||
{ \
|
||||
state->Reg[15] = ((s) & CCBITS) | R15PC | ER15INT | EMODE; \
|
||||
ASSIGNN ((state->Reg[15] & NBIT) != 0); \
|
||||
ASSIGNZ ((state->Reg[15] & ZBIT) != 0); \
|
||||
ASSIGNC ((state->Reg[15] & CBIT) != 0); \
|
||||
ASSIGNV ((state->Reg[15] & VBIT) != 0); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
state->Reg[15] = R15PC | ((s) & (CCBITS | R15INTBITS | R15MODEBITS)); \
|
||||
ARMul_R15Altered (state); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define SETABORT(i, m, d) \
|
||||
do \
|
||||
{ \
|
||||
int SETABORT_mode = (m); \
|
||||
\
|
||||
ARMul_SetSPSR (state, SETABORT_mode, ARMul_GetCPSR (state)); \
|
||||
ARMul_SetCPSR (state, ((ARMul_GetCPSR (state) & ~(EMODE | TBIT)) \
|
||||
| (i) | SETABORT_mode)); \
|
||||
state->Reg[14] = temp - (d); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#ifndef MODE32
|
||||
#define VECTORS 0x20
|
||||
#define LEGALADDR 0x03ffffff
|
||||
#define VECTORACCESS(address) (address < VECTORS && ARMul_MODE26BIT && state->prog32Sig)
|
||||
#define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig)
|
||||
#define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig)
|
||||
#endif
|
||||
|
||||
#define INTERNALABORT(address) if (address < VECTORS) \
|
||||
state->Aborted = ARMul_DataAbortV ; \
|
||||
else \
|
||||
state->Aborted = ARMul_AddrExceptnV ;
|
||||
#define INTERNALABORT(address) \
|
||||
do \
|
||||
{ \
|
||||
if (address < VECTORS) \
|
||||
state->Aborted = ARMul_DataAbortV; \
|
||||
else \
|
||||
state->Aborted = ARMul_AddrExceptnV; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#ifdef MODE32
|
||||
#define TAKEABORT ARMul_Abort(state,ARMul_DataAbortV)
|
||||
#define TAKEABORT ARMul_Abort (state, ARMul_DataAbortV)
|
||||
#else
|
||||
#define TAKEABORT if (state->Aborted == ARMul_AddrExceptnV) \
|
||||
ARMul_Abort(state,ARMul_AddrExceptnV) ; \
|
||||
else \
|
||||
ARMul_Abort(state,ARMul_DataAbortV)
|
||||
#define TAKEABORT \
|
||||
do \
|
||||
{ \
|
||||
if (state->Aborted == ARMul_AddrExceptnV) \
|
||||
ARMul_Abort (state, ARMul_AddrExceptnV); \
|
||||
else \
|
||||
ARMul_Abort (state, ARMul_DataAbortV); \
|
||||
} \
|
||||
while (0)
|
||||
#endif
|
||||
#define CPTAKEABORT if (!state->Aborted) \
|
||||
ARMul_Abort(state,ARMul_UndefinedInstrV) ; \
|
||||
else if (state->Aborted == ARMul_AddrExceptnV) \
|
||||
ARMul_Abort(state,ARMul_AddrExceptnV) ; \
|
||||
else \
|
||||
ARMul_Abort(state,ARMul_DataAbortV)
|
||||
|
||||
#define CPTAKEABORT \
|
||||
do \
|
||||
{ \
|
||||
if (!state->Aborted) \
|
||||
ARMul_Abort (state, ARMul_UndefinedInstrV); \
|
||||
else if (state->Aborted == ARMul_AddrExceptnV) \
|
||||
ARMul_Abort (state, ARMul_AddrExceptnV); \
|
||||
else \
|
||||
ARMul_Abort (state, ARMul_DataAbortV); \
|
||||
} \
|
||||
while (0);
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* Different ways to start the next instruction *
|
||||
\***************************************************************************/
|
||||
|
||||
#define SEQ 0
|
||||
#define NONSEQ 1
|
||||
#define PCINCEDSEQ 2
|
||||
/* Different ways to start the next instruction. */
|
||||
#define SEQ 0
|
||||
#define NONSEQ 1
|
||||
#define PCINCEDSEQ 2
|
||||
#define PCINCEDNONSEQ 3
|
||||
#define PRIMEPIPE 4
|
||||
#define RESUME 8
|
||||
#define PRIMEPIPE 4
|
||||
#define RESUME 8
|
||||
|
||||
#define NORMALCYCLE state->NextInstr = 0
|
||||
#define BUSUSEDN state->NextInstr |= 1 /* The next fetch will be an N cycle. */
|
||||
#define BUSUSEDINCPCS \
|
||||
do \
|
||||
{ \
|
||||
if (! state->is_v4) \
|
||||
{ \
|
||||
state->Reg[15] += isize ; /* A standard PC inc and an S cycle. */ \
|
||||
state->NextInstr = (state->NextInstr & 0xff) | 2; \
|
||||
} \
|
||||
} \
|
||||
#define BUSUSEDINCPCS \
|
||||
do \
|
||||
{ \
|
||||
if (! state->is_v4) \
|
||||
{ \
|
||||
/* A standard PC inc and an S cycle. */ \
|
||||
state->Reg[15] += isize; \
|
||||
state->NextInstr = (state->NextInstr & 0xff) | 2; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#define BUSUSEDINCPCN \
|
||||
do \
|
||||
{ \
|
||||
if (state->is_v4) \
|
||||
BUSUSEDN; \
|
||||
else \
|
||||
{ \
|
||||
state->Reg[15] += isize ; /* A standard PC inc and an N cycle. */ \
|
||||
state->NextInstr |= 3; \
|
||||
} \
|
||||
} \
|
||||
|
||||
#define BUSUSEDINCPCN \
|
||||
do \
|
||||
{ \
|
||||
if (state->is_v4) \
|
||||
BUSUSEDN; \
|
||||
else \
|
||||
{ \
|
||||
/* A standard PC inc and an N cycle. */ \
|
||||
state->Reg[15] += isize; \
|
||||
state->NextInstr |= 3; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#define INCPC state->Reg[15] += isize ; /* a standard PC inc */ \
|
||||
state->NextInstr |= 2
|
||||
|
||||
#define INCPC \
|
||||
do \
|
||||
{ \
|
||||
/* A standard PC inc. */ \
|
||||
state->Reg[15] += isize; \
|
||||
state->NextInstr |= 2; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define FLUSHPIPE state->NextInstr |= PRIMEPIPE
|
||||
|
||||
/***************************************************************************\
|
||||
* Cycle based emulation *
|
||||
\***************************************************************************/
|
||||
/* Cycle based emulation. */
|
||||
|
||||
#define OUTPUTCP(i,a,b)
|
||||
#define NCYCLE
|
||||
@ -278,15 +304,7 @@ extern ARMword isize;
|
||||
#define CCYCLE
|
||||
#define NEXTCYCLE(c)
|
||||
|
||||
/***************************************************************************\
|
||||
* States of the cycle based state machine *
|
||||
\***************************************************************************/
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* Macros to extract parts of instructions *
|
||||
\***************************************************************************/
|
||||
|
||||
/* Macros to extract parts of instructions. */
|
||||
#define DESTReg (BITS(12,15))
|
||||
#define LHSReg (BITS(16,19))
|
||||
#define RHSReg (BITS(0,3))
|
||||
@ -300,77 +318,78 @@ extern ARMword isize;
|
||||
#define LHS (state->Reg[LHSReg])
|
||||
#endif
|
||||
#else
|
||||
#define LHS ((LHSReg == 15) ? R15PC : (state->Reg[LHSReg]) )
|
||||
#define LHS ((LHSReg == 15) ? R15PC : (state->Reg[LHSReg]))
|
||||
#endif
|
||||
|
||||
#define MULDESTReg (BITS(16,19))
|
||||
#define MULLHSReg (BITS(0,3))
|
||||
#define MULRHSReg (BITS(8,11))
|
||||
#define MULACCReg (BITS(12,15))
|
||||
#define MULDESTReg (BITS (16, 19))
|
||||
#define MULLHSReg (BITS ( 0, 3))
|
||||
#define MULRHSReg (BITS ( 8, 11))
|
||||
#define MULACCReg (BITS (12, 15))
|
||||
|
||||
#define DPImmRHS (ARMul_ImmedTable[BITS(0,11)])
|
||||
#define DPImmRHS (ARMul_ImmedTable[BITS(0, 11)])
|
||||
#define DPSImmRHS temp = BITS(0,11) ; \
|
||||
rhs = ARMul_ImmedTable[temp] ; \
|
||||
if (temp > 255) /* there was a shift */ \
|
||||
ASSIGNC(rhs >> 31) ;
|
||||
if (temp > 255) /* There was a shift. */ \
|
||||
ASSIGNC (rhs >> 31) ;
|
||||
|
||||
#ifdef MODE32
|
||||
#define DPRegRHS ((BITS(4,11)==0) ? state->Reg[RHSReg] \
|
||||
: GetDPRegRHS(state, instr))
|
||||
#define DPSRegRHS ((BITS(4,11)==0) ? state->Reg[RHSReg] \
|
||||
: GetDPSRegRHS(state, instr))
|
||||
#define DPRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \
|
||||
: GetDPRegRHS (state, instr))
|
||||
#define DPSRegRHS ((BITS (4,11) == 0) ? state->Reg[RHSReg] \
|
||||
: GetDPSRegRHS (state, instr))
|
||||
#else
|
||||
#define DPRegRHS ((BITS(0,11)<15) ? state->Reg[RHSReg] \
|
||||
: GetDPRegRHS(state, instr))
|
||||
#define DPSRegRHS ((BITS(0,11)<15) ? state->Reg[RHSReg] \
|
||||
: GetDPSRegRHS(state, instr))
|
||||
#define DPRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \
|
||||
: GetDPRegRHS (state, instr))
|
||||
#define DPSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \
|
||||
: GetDPSRegRHS (state, instr))
|
||||
#endif
|
||||
|
||||
#define LSBase state->Reg[LHSReg]
|
||||
#define LSImmRHS (BITS(0,11))
|
||||
|
||||
#ifdef MODE32
|
||||
#define LSRegRHS ((BITS(4,11)==0) ? state->Reg[RHSReg] \
|
||||
: GetLSRegRHS(state, instr))
|
||||
#define LSRegRHS ((BITS (4, 11) == 0) ? state->Reg[RHSReg] \
|
||||
: GetLSRegRHS (state, instr))
|
||||
#else
|
||||
#define LSRegRHS ((BITS(0,11)<15) ? state->Reg[RHSReg] \
|
||||
: GetLSRegRHS(state, instr))
|
||||
#define LSRegRHS ((BITS (0, 11) < 15) ? state->Reg[RHSReg] \
|
||||
: GetLSRegRHS (state, instr))
|
||||
#endif
|
||||
|
||||
#define LSMNumRegs ((ARMword)ARMul_BitList[BITS(0,7)] + \
|
||||
(ARMword)ARMul_BitList[BITS(8,15)] )
|
||||
#define LSMBaseFirst ((LHSReg == 0 && BIT(0)) || \
|
||||
(BIT(LHSReg) && BITS(0,LHSReg-1) == 0))
|
||||
#define LSMNumRegs ((ARMword) ARMul_BitList[BITS (0, 7)] + \
|
||||
(ARMword) ARMul_BitList[BITS (8, 15)] )
|
||||
#define LSMBaseFirst ((LHSReg == 0 && BIT (0)) || \
|
||||
(BIT (LHSReg) && BITS (0, LHSReg - 1) == 0))
|
||||
|
||||
#define SWAPSRC (state->Reg[RHSReg])
|
||||
|
||||
#define LSCOff (BITS(0,7) << 2)
|
||||
#define CPNum BITS(8,11)
|
||||
#define LSCOff (BITS (0, 7) << 2)
|
||||
#define CPNum BITS (8, 11)
|
||||
|
||||
/***************************************************************************\
|
||||
* Macro to rotate n right by b bits *
|
||||
\***************************************************************************/
|
||||
/* Determine if access to coprocessor CP is permitted.
|
||||
The XScale has a register in CP15 which controls access to CP0 - CP13. */
|
||||
#define CP_ACCESS_ALLOWED(STATE, CP) \
|
||||
( ((CP) >= 14) \
|
||||
|| (! (STATE)->is_XScale) \
|
||||
|| (read_cp15_reg (15, 0, 1) & (1 << (CP))))
|
||||
|
||||
#define ROTATER(n,b) (((n)>>(b))|((n)<<(32-(b))))
|
||||
/* Macro to rotate n right by b bits. */
|
||||
#define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b))))
|
||||
|
||||
/***************************************************************************\
|
||||
* Macros to store results of instructions *
|
||||
\***************************************************************************/
|
||||
|
||||
#define WRITEDEST(d) if (DESTReg==15) \
|
||||
WriteR15(state, d) ; \
|
||||
/* Macros to store results of instructions. */
|
||||
#define WRITEDEST(d) if (DESTReg == 15) \
|
||||
WriteR15 (state, d) ; \
|
||||
else \
|
||||
DEST = d
|
||||
|
||||
#define WRITESDEST(d) if (DESTReg == 15) \
|
||||
WriteSR15(state, d) ; \
|
||||
WriteSR15 (state, d) ; \
|
||||
else { \
|
||||
DEST = d ; \
|
||||
ARMul_NegZero(state, d) ; \
|
||||
ARMul_NegZero (state, d) ; \
|
||||
}
|
||||
|
||||
#define WRITEDESTB(d) if (DESTReg == 15) \
|
||||
WriteR15Branch(state, d) ; \
|
||||
WriteR15Branch (state, d) ; \
|
||||
else \
|
||||
DEST = d
|
||||
|
||||
@ -378,87 +397,46 @@ extern ARMword isize;
|
||||
((data & 0xff) << 8) | \
|
||||
((data & 0xff) << 16) | \
|
||||
((data & 0xff) << 24))
|
||||
#define BUSTOBYTE(address,data) \
|
||||
|
||||
#define BUSTOBYTE(address, data) \
|
||||
if (state->bigendSig) \
|
||||
temp = (data >> (((address ^ 3) & 3) << 3)) & 0xff ; \
|
||||
else \
|
||||
temp = (data >> ((address & 3) << 3)) & 0xff
|
||||
|
||||
#define LOADMULT(instr,address,wb) LoadMult(state,instr,address,wb)
|
||||
#define LOADSMULT(instr,address,wb) LoadSMult(state,instr,address,wb)
|
||||
#define STOREMULT(instr,address,wb) StoreMult(state,instr,address,wb)
|
||||
#define STORESMULT(instr,address,wb) StoreSMult(state,instr,address,wb)
|
||||
#define LOADMULT(instr, address, wb) LoadMult (state, instr, address, wb)
|
||||
#define LOADSMULT(instr, address, wb) LoadSMult (state, instr, address, wb)
|
||||
#define STOREMULT(instr, address, wb) StoreMult (state, instr, address, wb)
|
||||
#define STORESMULT(instr, address, wb) StoreSMult (state, instr, address, wb)
|
||||
|
||||
#define POSBRANCH ((instr & 0x7fffff) << 2)
|
||||
#define NEGBRANCH ((0xff000000 |(instr & 0xffffff)) << 2)
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* Values for Emulate *
|
||||
\***************************************************************************/
|
||||
/* Values for Emulate. */
|
||||
|
||||
#define STOP 0 /* stop */
|
||||
#define CHANGEMODE 1 /* change mode */
|
||||
#define ONCE 2 /* execute just one interation */
|
||||
#define RUN 3 /* continuous execution */
|
||||
|
||||
/***************************************************************************\
|
||||
* Stuff that is shared across modes *
|
||||
\***************************************************************************/
|
||||
/* Stuff that is shared across modes. */
|
||||
extern unsigned ARMul_MultTable[]; /* Number of I cycles for a mult. */
|
||||
extern ARMword ARMul_ImmedTable[]; /* Immediate DP LHS values. */
|
||||
extern char ARMul_BitList[]; /* Number of bits in a byte table. */
|
||||
|
||||
extern ARMword ARMul_Emulate26 (ARMul_State * state);
|
||||
extern ARMword ARMul_Emulate32 (ARMul_State * state);
|
||||
extern unsigned ARMul_MultTable[]; /* Number of I cycles for a mult */
|
||||
extern ARMword ARMul_ImmedTable[]; /* immediate DP LHS values */
|
||||
extern char ARMul_BitList[]; /* number of bits in a byte table */
|
||||
extern void ARMul_Abort26 (ARMul_State * state, ARMword);
|
||||
extern void ARMul_Abort32 (ARMul_State * state, ARMword);
|
||||
extern unsigned ARMul_NthReg (ARMword instr, unsigned number);
|
||||
extern void ARMul_MSRCpsr (ARMul_State * state, ARMword instr, ARMword rhs);
|
||||
extern void ARMul_NegZero (ARMul_State * state, ARMword result);
|
||||
extern void ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
extern int AddOverflow (ARMword a, ARMword b, ARMword result);
|
||||
extern int SubOverflow (ARMword a, ARMword b, ARMword result);
|
||||
extern void ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
extern void ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
extern void ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
extern void ARMul_CPSRAltered (ARMul_State * state);
|
||||
extern void ARMul_R15Altered (ARMul_State * state);
|
||||
extern ARMword ARMul_SwitchMode (ARMul_State * state, ARMword oldmode,
|
||||
ARMword newmode);
|
||||
extern unsigned ARMul_NthReg (ARMword instr, unsigned number);
|
||||
extern void ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address);
|
||||
extern void ARMul_STC (ARMul_State * state, ARMword instr, ARMword address);
|
||||
extern void ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source);
|
||||
extern ARMword ARMul_MRC (ARMul_State * state, ARMword instr);
|
||||
extern void ARMul_CDP (ARMul_State * state, ARMword instr);
|
||||
extern unsigned IntPending (ARMul_State * state);
|
||||
extern ARMword ARMul_Align (ARMul_State * state, ARMword address,
|
||||
ARMword data);
|
||||
#define EVENTLISTSIZE 1024L
|
||||
|
||||
/* Thumb support: */
|
||||
|
||||
/* Thumb support. */
|
||||
typedef enum
|
||||
{
|
||||
t_undefined, /* undefined Thumb instruction */
|
||||
t_decoded, /* instruction decoded to ARM equivalent */
|
||||
t_branch /* Thumb branch (already processed) */
|
||||
t_undefined, /* Undefined Thumb instruction. */
|
||||
t_decoded, /* Instruction decoded to ARM equivalent. */
|
||||
t_branch /* Thumb branch (already processed). */
|
||||
}
|
||||
tdstate;
|
||||
|
||||
extern tdstate ARMul_ThumbDecode (ARMul_State * state, ARMword pc,
|
||||
ARMword tinstr, ARMword * ainstr);
|
||||
|
||||
/***************************************************************************\
|
||||
* Macros to scrutinize instructions *
|
||||
\***************************************************************************/
|
||||
|
||||
|
||||
/* Macros to scrutinize instructions. */
|
||||
#define UNDEF_Test
|
||||
#define UNDEF_Shift
|
||||
#define UNDEF_MSRPC
|
||||
@ -484,13 +462,52 @@ extern tdstate ARMul_ThumbDecode (ARMul_State * state, ARMword pc,
|
||||
#define UNDEF_Prog32SigChange
|
||||
#define UNDEF_Data32SigChange
|
||||
|
||||
/* Prototypes for exported functions. */
|
||||
extern unsigned ARMul_NthReg (ARMword, unsigned);
|
||||
extern int AddOverflow (ARMword, ARMword, ARMword);
|
||||
extern int SubOverflow (ARMword, ARMword, ARMword);
|
||||
extern ARMword ARMul_Emulate26 (ARMul_State *);
|
||||
extern ARMword ARMul_Emulate32 (ARMul_State *);
|
||||
extern unsigned IntPending (ARMul_State *);
|
||||
extern void ARMul_CPSRAltered (ARMul_State *);
|
||||
extern void ARMul_R15Altered (ARMul_State *);
|
||||
extern ARMword ARMul_GetPC (ARMul_State *);
|
||||
extern ARMword ARMul_GetNextPC (ARMul_State *);
|
||||
extern ARMword ARMul_GetR15 (ARMul_State *);
|
||||
extern ARMword ARMul_GetCPSR (ARMul_State *);
|
||||
extern void ARMul_EnvokeEvent (ARMul_State *);
|
||||
extern unsigned long ARMul_Time (ARMul_State *);
|
||||
extern void ARMul_NegZero (ARMul_State *, ARMword);
|
||||
extern void ARMul_SetPC (ARMul_State *, ARMword);
|
||||
extern void ARMul_SetR15 (ARMul_State *, ARMword);
|
||||
extern void ARMul_SetCPSR (ARMul_State *, ARMword);
|
||||
extern ARMword ARMul_GetSPSR (ARMul_State *, ARMword);
|
||||
extern void ARMul_Abort26 (ARMul_State *, ARMword);
|
||||
extern void ARMul_Abort32 (ARMul_State *, ARMword);
|
||||
extern ARMword ARMul_MRC (ARMul_State *, ARMword);
|
||||
extern void ARMul_CDP (ARMul_State *, ARMword);
|
||||
extern void ARMul_LDC (ARMul_State *, ARMword, ARMword);
|
||||
extern void ARMul_STC (ARMul_State *, ARMword, ARMword);
|
||||
extern void ARMul_MCR (ARMul_State *, ARMword, ARMword);
|
||||
extern void ARMul_SetSPSR (ARMul_State *, ARMword, ARMword);
|
||||
extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword);
|
||||
extern ARMword ARMul_Align (ARMul_State *, ARMword, ARMword);
|
||||
extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword);
|
||||
extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword);
|
||||
extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword);
|
||||
extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword);
|
||||
extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword);
|
||||
extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword);
|
||||
extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *);
|
||||
extern ARMword ARMul_GetReg (ARMul_State *, unsigned, unsigned);
|
||||
extern void ARMul_SetReg (ARMul_State *, unsigned, unsigned, ARMword);
|
||||
extern void ARMul_ScheduleEvent (ARMul_State *, unsigned long, unsigned (*) (ARMul_State *));
|
||||
/* Coprocessor support functions. */
|
||||
extern unsigned ARMul_CoProInit (ARMul_State *);
|
||||
extern void ARMul_CoProExit (ARMul_State *);
|
||||
extern void ARMul_CoProAttach (ARMul_State *, unsigned, ARMul_CPInits *, ARMul_CPExits *,
|
||||
ARMul_LDCs *, ARMul_STCs *, ARMul_MRCs *, ARMul_MCRs *,
|
||||
ARMul_CDPs *, ARMul_CPReads *, ARMul_CPWrites *);
|
||||
extern void ARMul_CoProDetach (ARMul_State *, unsigned);
|
||||
extern void write_cp15_reg (ARMul_State *, unsigned, unsigned, unsigned, ARMword);
|
||||
extern void write_cp14_reg (unsigned, ARMword);
|
||||
extern ARMword read_cp14_reg (unsigned);
|
||||
extern unsigned ARMul_CoProInit (ARMul_State *);
|
||||
extern void ARMul_CoProExit (ARMul_State *);
|
||||
extern void ARMul_CoProAttach (ARMul_State *, unsigned, ARMul_CPInits *, ARMul_CPExits *,
|
||||
ARMul_LDCs *, ARMul_STCs *, ARMul_MRCs *, ARMul_MCRs *,
|
||||
ARMul_CDPs *, ARMul_CPReads *, ARMul_CPWrites *);
|
||||
extern void ARMul_CoProDetach (ARMul_State *, unsigned);
|
||||
extern ARMword read_cp15_reg (unsigned, unsigned, unsigned);
|
||||
|
||||
|
@ -19,68 +19,18 @@
|
||||
#include "armemu.h"
|
||||
#include "ansidecl.h"
|
||||
|
||||
/***************************************************************************\
|
||||
* Definitions for the support routines *
|
||||
\***************************************************************************/
|
||||
/* Definitions for the support routines. */
|
||||
|
||||
ARMword ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg);
|
||||
void ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg,
|
||||
ARMword value);
|
||||
ARMword ARMul_GetPC (ARMul_State * state);
|
||||
ARMword ARMul_GetNextPC (ARMul_State * state);
|
||||
void ARMul_SetPC (ARMul_State * state, ARMword value);
|
||||
ARMword ARMul_GetR15 (ARMul_State * state);
|
||||
void ARMul_SetR15 (ARMul_State * state, ARMword value);
|
||||
|
||||
ARMword ARMul_GetCPSR (ARMul_State * state);
|
||||
void ARMul_SetCPSR (ARMul_State * state, ARMword value);
|
||||
ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode);
|
||||
void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value);
|
||||
|
||||
void ARMul_CPSRAltered (ARMul_State * state);
|
||||
void ARMul_R15Altered (ARMul_State * state);
|
||||
|
||||
ARMword ARMul_SwitchMode (ARMul_State * state, ARMword oldmode,
|
||||
ARMword newmode);
|
||||
static ARMword ModeToBank (ARMword mode);
|
||||
|
||||
unsigned ARMul_NthReg (ARMword instr, unsigned number);
|
||||
|
||||
void ARMul_NegZero (ARMul_State * state, ARMword result);
|
||||
void ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
void ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
void ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
void ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b,
|
||||
ARMword result);
|
||||
|
||||
void ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address);
|
||||
void ARMul_STC (ARMul_State * state, ARMword instr, ARMword address);
|
||||
void ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source);
|
||||
ARMword ARMul_MRC (ARMul_State * state, ARMword instr);
|
||||
void ARMul_CDP (ARMul_State * state, ARMword instr);
|
||||
unsigned IntPending (ARMul_State * state);
|
||||
|
||||
ARMword ARMul_Align (ARMul_State * state, ARMword address, ARMword data);
|
||||
|
||||
void ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
|
||||
unsigned (*what) ());
|
||||
void ARMul_EnvokeEvent (ARMul_State * state);
|
||||
unsigned long ARMul_Time (ARMul_State * state);
|
||||
static void EnvokeList (ARMul_State * state, unsigned long from,
|
||||
unsigned long to);
|
||||
static ARMword ModeToBank (ARMword);
|
||||
static void EnvokeList (ARMul_State *, unsigned long, unsigned long);
|
||||
|
||||
struct EventNode
|
||||
{ /* An event list node */
|
||||
unsigned (*func) (); /* The function to call */
|
||||
{ /* An event list node. */
|
||||
unsigned (*func) (ARMul_State *); /* The function to call. */
|
||||
struct EventNode *next;
|
||||
};
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine returns the value of a register from a mode. *
|
||||
\***************************************************************************/
|
||||
/* This routine returns the value of a register from a mode. */
|
||||
|
||||
ARMword
|
||||
ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
|
||||
@ -92,9 +42,7 @@ ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
|
||||
return (state->Reg[reg]);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine sets the value of a register for a mode. *
|
||||
\***************************************************************************/
|
||||
/* This routine sets the value of a register for a mode. */
|
||||
|
||||
void
|
||||
ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
|
||||
@ -106,35 +54,29 @@ ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
|
||||
state->Reg[reg] = value;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine returns the value of the PC, mode independently. *
|
||||
\***************************************************************************/
|
||||
/* This routine returns the value of the PC, mode independently. */
|
||||
|
||||
ARMword
|
||||
ARMul_GetPC (ARMul_State * state)
|
||||
{
|
||||
if (state->Mode > SVC26MODE)
|
||||
return (state->Reg[15]);
|
||||
return state->Reg[15];
|
||||
else
|
||||
return (R15PC);
|
||||
return R15PC;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine returns the value of the PC, mode independently. *
|
||||
\***************************************************************************/
|
||||
/* This routine returns the value of the PC, mode independently. */
|
||||
|
||||
ARMword
|
||||
ARMul_GetNextPC (ARMul_State * state)
|
||||
{
|
||||
if (state->Mode > SVC26MODE)
|
||||
return (state->Reg[15] + isize);
|
||||
return state->Reg[15] + isize;
|
||||
else
|
||||
return ((state->Reg[15] + isize) & R15PCBITS);
|
||||
return (state->Reg[15] + isize) & R15PCBITS;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine sets the value of the PC. *
|
||||
\***************************************************************************/
|
||||
/* This routine sets the value of the PC. */
|
||||
|
||||
void
|
||||
ARMul_SetPC (ARMul_State * state, ARMword value)
|
||||
@ -146,9 +88,7 @@ ARMul_SetPC (ARMul_State * state, ARMword value)
|
||||
FLUSHPIPE;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine returns the value of register 15, mode independently. *
|
||||
\***************************************************************************/
|
||||
/* This routine returns the value of register 15, mode independently. */
|
||||
|
||||
ARMword
|
||||
ARMul_GetR15 (ARMul_State * state)
|
||||
@ -159,9 +99,7 @@ ARMul_GetR15 (ARMul_State * state)
|
||||
return (R15PC | ECC | ER15INT | EMODE);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine sets the value of Register 15. *
|
||||
\***************************************************************************/
|
||||
/* This routine sets the value of Register 15. */
|
||||
|
||||
void
|
||||
ARMul_SetR15 (ARMul_State * state, ARMword value)
|
||||
@ -176,9 +114,7 @@ ARMul_SetR15 (ARMul_State * state, ARMword value)
|
||||
FLUSHPIPE;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine returns the value of the CPSR *
|
||||
\***************************************************************************/
|
||||
/* This routine returns the value of the CPSR. */
|
||||
|
||||
ARMword
|
||||
ARMul_GetCPSR (ARMul_State * state)
|
||||
@ -186,9 +122,7 @@ ARMul_GetCPSR (ARMul_State * state)
|
||||
return (CPSR | state->Cpsr);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine sets the value of the CPSR *
|
||||
\***************************************************************************/
|
||||
/* This routine sets the value of the CPSR. */
|
||||
|
||||
void
|
||||
ARMul_SetCPSR (ARMul_State * state, ARMword value)
|
||||
@ -197,10 +131,8 @@ ARMul_SetCPSR (ARMul_State * state, ARMword value)
|
||||
ARMul_CPSRAltered (state);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine does all the nasty bits involved in a write to the CPSR, *
|
||||
* including updating the register bank, given a MSR instruction. *
|
||||
\***************************************************************************/
|
||||
/* This routine does all the nasty bits involved in a write to the CPSR,
|
||||
including updating the register bank, given a MSR instruction. */
|
||||
|
||||
void
|
||||
ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
|
||||
@ -208,7 +140,8 @@ ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
|
||||
state->Cpsr = ARMul_GetCPSR (state);
|
||||
if (state->Mode != USER26MODE
|
||||
&& state->Mode != USER32MODE)
|
||||
{ /* In user mode, only write flags */
|
||||
{
|
||||
/* In user mode, only write flags. */
|
||||
if (BIT (16))
|
||||
SETPSR_C (state->Cpsr, rhs);
|
||||
if (BIT (17))
|
||||
@ -221,9 +154,7 @@ ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
|
||||
ARMul_CPSRAltered (state);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Get an SPSR from the specified mode *
|
||||
\***************************************************************************/
|
||||
/* Get an SPSR from the specified mode. */
|
||||
|
||||
ARMword
|
||||
ARMul_GetSPSR (ARMul_State * state, ARMword mode)
|
||||
@ -236,9 +167,7 @@ ARMul_GetSPSR (ARMul_State * state, ARMword mode)
|
||||
return state->Spsr[bank];
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine does a write to an SPSR *
|
||||
\***************************************************************************/
|
||||
/* This routine does a write to an SPSR. */
|
||||
|
||||
void
|
||||
ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
|
||||
@ -249,9 +178,7 @@ ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
|
||||
state->Spsr[bank] = value;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine does a write to the current SPSR, given an MSR instruction *
|
||||
\***************************************************************************/
|
||||
/* This routine does a write to the current SPSR, given an MSR instruction. */
|
||||
|
||||
void
|
||||
ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
|
||||
@ -269,10 +196,8 @@ ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine updates the state of the emulator after the Cpsr has been *
|
||||
* changed. Both the processor flags and register bank are updated. *
|
||||
\***************************************************************************/
|
||||
/* This routine updates the state of the emulator after the Cpsr has been
|
||||
changed. Both the processor flags and register bank are updated. */
|
||||
|
||||
void
|
||||
ARMul_CPSRAltered (ARMul_State * state)
|
||||
@ -330,11 +255,9 @@ ARMul_CPSRAltered (ARMul_State * state)
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine updates the state of the emulator after register 15 has *
|
||||
* been changed. Both the processor flags and register bank are updated. *
|
||||
* This routine should only be called from a 26 bit mode. *
|
||||
\***************************************************************************/
|
||||
/* This routine updates the state of the emulator after register 15 has
|
||||
been changed. Both the processor flags and register bank are updated.
|
||||
This routine should only be called from a 26 bit mode. */
|
||||
|
||||
void
|
||||
ARMul_R15Altered (ARMul_State * state)
|
||||
@ -344,22 +267,23 @@ ARMul_R15Altered (ARMul_State * state)
|
||||
state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
|
||||
state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
|
||||
}
|
||||
|
||||
if (state->Mode > SVC26MODE)
|
||||
state->Emulate = CHANGEMODE;
|
||||
|
||||
ASSIGNR15INT (R15INT);
|
||||
|
||||
ASSIGNN ((state->Reg[15] & NBIT) != 0);
|
||||
ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
|
||||
ASSIGNC ((state->Reg[15] & CBIT) != 0);
|
||||
ASSIGNV ((state->Reg[15] & VBIT) != 0);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine controls the saving and restoring of registers across mode *
|
||||
* changes. The regbank matrix is largely unused, only rows 13 and 14 are *
|
||||
* used across all modes, 8 to 14 are used for FIQ, all others use the USER *
|
||||
* column. It's easier this way. old and new parameter are modes numbers. *
|
||||
* Notice the side effect of changing the Bank variable. *
|
||||
\***************************************************************************/
|
||||
/* This routine controls the saving and restoring of registers across mode
|
||||
changes. The regbank matrix is largely unused, only rows 13 and 14 are
|
||||
used across all modes, 8 to 14 are used for FIQ, all others use the USER
|
||||
column. It's easier this way. old and new parameter are modes numbers.
|
||||
Notice the side effect of changing the Bank variable. */
|
||||
|
||||
ARMword
|
||||
ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
|
||||
@ -371,10 +295,12 @@ ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
|
||||
oldbank = ModeToBank (oldmode);
|
||||
newbank = state->Bank = ModeToBank (newmode);
|
||||
|
||||
/* Do we really need to do it? */
|
||||
if (oldbank != newbank)
|
||||
{ /* really need to do it */
|
||||
{
|
||||
/* Save away the old registers. */
|
||||
switch (oldbank)
|
||||
{ /* save away the old registers */
|
||||
{
|
||||
case USERBANK:
|
||||
case IRQBANK:
|
||||
case SVCBANK:
|
||||
@ -398,8 +324,9 @@ ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Restore the new registers. */
|
||||
switch (newbank)
|
||||
{ /* restore the new registers */
|
||||
{
|
||||
case USERBANK:
|
||||
case IRQBANK:
|
||||
case SVCBANK:
|
||||
@ -421,16 +348,14 @@ ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
} /* switch */
|
||||
} /* if */
|
||||
}
|
||||
}
|
||||
|
||||
return newmode;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Given a processor mode, this routine returns the register bank that *
|
||||
* will be accessed in that mode. *
|
||||
\***************************************************************************/
|
||||
/* Given a processor mode, this routine returns the
|
||||
register bank that will be accessed in that mode. */
|
||||
|
||||
static ARMword
|
||||
ModeToBank (ARMword mode)
|
||||
@ -453,24 +378,21 @@ ModeToBank (ARMword mode)
|
||||
return bankofmode[mode];
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Returns the register number of the nth register in a reg list. *
|
||||
\***************************************************************************/
|
||||
/* Returns the register number of the nth register in a reg list. */
|
||||
|
||||
unsigned
|
||||
ARMul_NthReg (ARMword instr, unsigned number)
|
||||
{
|
||||
unsigned bit, upto;
|
||||
|
||||
for (bit = 0, upto = 0; upto <= number; bit++)
|
||||
for (bit = 0, upto = 0; upto <= number; bit ++)
|
||||
if (BIT (bit))
|
||||
upto++;
|
||||
upto ++;
|
||||
|
||||
return (bit - 1);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Assigns the N and Z flags depending on the value of result *
|
||||
\***************************************************************************/
|
||||
/* Assigns the N and Z flags depending on the value of result. */
|
||||
|
||||
void
|
||||
ARMul_NegZero (ARMul_State * state, ARMword result)
|
||||
@ -489,10 +411,11 @@ ARMul_NegZero (ARMul_State * state, ARMword result)
|
||||
{
|
||||
CLEARN;
|
||||
CLEARZ;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute whether an addition of A and B, giving RESULT, overflowed. */
|
||||
|
||||
int
|
||||
AddOverflow (ARMword a, ARMword b, ARMword result)
|
||||
{
|
||||
@ -501,6 +424,7 @@ AddOverflow (ARMword a, ARMword b, ARMword result)
|
||||
}
|
||||
|
||||
/* Compute whether a subtraction of A and B, giving RESULT, overflowed. */
|
||||
|
||||
int
|
||||
SubOverflow (ARMword a, ARMword b, ARMword result)
|
||||
{
|
||||
@ -508,9 +432,7 @@ SubOverflow (ARMword a, ARMword b, ARMword result)
|
||||
|| (POS (a) && NEG (b) && NEG (result)));
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Assigns the C flag after an addition of a and b to give result *
|
||||
\***************************************************************************/
|
||||
/* Assigns the C flag after an addition of a and b to give result. */
|
||||
|
||||
void
|
||||
ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
@ -519,9 +441,7 @@ ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
(NEG (a) && POS (result)) || (NEG (b) && POS (result)));
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Assigns the V flag after an addition of a and b to give result *
|
||||
\***************************************************************************/
|
||||
/* Assigns the V flag after an addition of a and b to give result. */
|
||||
|
||||
void
|
||||
ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
@ -529,9 +449,7 @@ ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
ASSIGNV (AddOverflow (a, b, result));
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Assigns the C flag after an subtraction of a and b to give result *
|
||||
\***************************************************************************/
|
||||
/* Assigns the C flag after an subtraction of a and b to give result. */
|
||||
|
||||
void
|
||||
ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
@ -540,9 +458,7 @@ ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
(NEG (a) && POS (result)) || (POS (b) && POS (result)));
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Assigns the V flag after an subtraction of a and b to give result *
|
||||
\***************************************************************************/
|
||||
/* Assigns the V flag after an subtraction of a and b to give result. */
|
||||
|
||||
void
|
||||
ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
@ -550,12 +466,10 @@ ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
|
||||
ASSIGNV (SubOverflow (a, b, result));
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This function does the work of generating the addresses used in an *
|
||||
* LDC instruction. The code here is always post-indexed, it's up to the *
|
||||
* caller to get the input address correct and to handle base register *
|
||||
* modification. It also handles the Busy-Waiting. *
|
||||
\***************************************************************************/
|
||||
/* This function does the work of generating the addresses used in an
|
||||
LDC instruction. The code here is always post-indexed, it's up to the
|
||||
caller to get the input address correct and to handle base register
|
||||
modification. It also handles the Busy-Waiting. */
|
||||
|
||||
void
|
||||
ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
|
||||
@ -564,14 +478,21 @@ ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
|
||||
ARMword data;
|
||||
|
||||
UNDEF_LSCPCBaseWb;
|
||||
if (ADDREXCEPT (address))
|
||||
|
||||
if (! CP_ACCESS_ALLOWED (state, CPNum))
|
||||
{
|
||||
INTERNALABORT (address);
|
||||
ARMul_UndefInstr (state, instr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ADDREXCEPT (address))
|
||||
INTERNALABORT (address);
|
||||
|
||||
cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
|
||||
while (cpab == ARMul_BUSY)
|
||||
{
|
||||
ARMul_Icycles (state, 1, 0);
|
||||
|
||||
if (IntPending (state))
|
||||
{
|
||||
cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
|
||||
@ -585,30 +506,30 @@ ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
|
||||
CPTAKEABORT;
|
||||
return;
|
||||
}
|
||||
|
||||
cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
|
||||
data = ARMul_LoadWordN (state, address);
|
||||
BUSUSEDINCPCN;
|
||||
|
||||
if (BIT (21))
|
||||
LSBase = state->Base;
|
||||
cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
|
||||
|
||||
while (cpab == ARMul_INC)
|
||||
{
|
||||
address += 4;
|
||||
data = ARMul_LoadWordN (state, address);
|
||||
cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
|
||||
}
|
||||
|
||||
if (state->abortSig || state->Aborted)
|
||||
{
|
||||
TAKEABORT;
|
||||
}
|
||||
TAKEABORT;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This function does the work of generating the addresses used in an *
|
||||
* STC instruction. The code here is always post-indexed, it's up to the *
|
||||
* caller to get the input address correct and to handle base register *
|
||||
* modification. It also handles the Busy-Waiting. *
|
||||
\***************************************************************************/
|
||||
/* This function does the work of generating the addresses used in an
|
||||
STC instruction. The code here is always post-indexed, it's up to the
|
||||
caller to get the input address correct and to handle base register
|
||||
modification. It also handles the Busy-Waiting. */
|
||||
|
||||
void
|
||||
ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
|
||||
@ -617,10 +538,16 @@ ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
|
||||
ARMword data;
|
||||
|
||||
UNDEF_LSCPCBaseWb;
|
||||
if (ADDREXCEPT (address) || VECTORACCESS (address))
|
||||
|
||||
if (! CP_ACCESS_ALLOWED (state, CPNum))
|
||||
{
|
||||
INTERNALABORT (address);
|
||||
ARMul_UndefInstr (state, instr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ADDREXCEPT (address) || VECTORACCESS (address))
|
||||
INTERNALABORT (address);
|
||||
|
||||
cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
|
||||
while (cpab == ARMul_BUSY)
|
||||
{
|
||||
@ -633,6 +560,7 @@ ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
|
||||
else
|
||||
cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
|
||||
}
|
||||
|
||||
if (cpab == ARMul_CANT)
|
||||
{
|
||||
CPTAKEABORT;
|
||||
@ -640,36 +568,39 @@ ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
|
||||
}
|
||||
#ifndef MODE32
|
||||
if (ADDREXCEPT (address) || VECTORACCESS (address))
|
||||
{
|
||||
INTERNALABORT (address);
|
||||
}
|
||||
INTERNALABORT (address);
|
||||
|
||||
#endif
|
||||
BUSUSEDINCPCN;
|
||||
if (BIT (21))
|
||||
LSBase = state->Base;
|
||||
cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
|
||||
ARMul_StoreWordN (state, address, data);
|
||||
|
||||
while (cpab == ARMul_INC)
|
||||
{
|
||||
address += 4;
|
||||
cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
|
||||
ARMul_StoreWordN (state, address, data);
|
||||
}
|
||||
|
||||
if (state->abortSig || state->Aborted)
|
||||
{
|
||||
TAKEABORT;
|
||||
}
|
||||
TAKEABORT;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This function does the Busy-Waiting for an MCR instruction. *
|
||||
\***************************************************************************/
|
||||
/* This function does the Busy-Waiting for an MCR instruction. */
|
||||
|
||||
void
|
||||
ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
|
||||
{
|
||||
unsigned cpab;
|
||||
|
||||
if (! CP_ACCESS_ALLOWED (state, CPNum))
|
||||
{
|
||||
ARMul_UndefInstr (state, instr);
|
||||
return;
|
||||
}
|
||||
|
||||
cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
|
||||
|
||||
while (cpab == ARMul_BUSY)
|
||||
@ -694,9 +625,7 @@ ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This function does the Busy-Waiting for an MRC instruction. *
|
||||
\***************************************************************************/
|
||||
/* This function does the Busy-Waiting for an MRC instruction. */
|
||||
|
||||
ARMword
|
||||
ARMul_MRC (ARMul_State * state, ARMword instr)
|
||||
@ -704,6 +633,12 @@ ARMul_MRC (ARMul_State * state, ARMword instr)
|
||||
unsigned cpab;
|
||||
ARMword result = 0;
|
||||
|
||||
if (! CP_ACCESS_ALLOWED (state, CPNum))
|
||||
{
|
||||
ARMul_UndefInstr (state, instr);
|
||||
return;
|
||||
}
|
||||
|
||||
cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
|
||||
while (cpab == ARMul_BUSY)
|
||||
{
|
||||
@ -719,7 +654,8 @@ ARMul_MRC (ARMul_State * state, ARMword instr)
|
||||
if (cpab == ARMul_CANT)
|
||||
{
|
||||
ARMul_Abort (state, ARMul_UndefinedInstrV);
|
||||
result = ECC; /* Parent will destroy the flags otherwise */
|
||||
/* Parent will destroy the flags otherwise. */
|
||||
result = ECC;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -727,18 +663,23 @@ ARMul_MRC (ARMul_State * state, ARMword instr)
|
||||
ARMul_Ccycles (state, 1, 0);
|
||||
ARMul_Icycles (state, 1, 0);
|
||||
}
|
||||
return (result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This function does the Busy-Waiting for an CDP instruction. *
|
||||
\***************************************************************************/
|
||||
/* This function does the Busy-Waiting for an CDP instruction. */
|
||||
|
||||
void
|
||||
ARMul_CDP (ARMul_State * state, ARMword instr)
|
||||
{
|
||||
unsigned cpab;
|
||||
|
||||
if (! CP_ACCESS_ALLOWED (state, CPNum))
|
||||
{
|
||||
ARMul_UndefInstr (state, instr);
|
||||
return;
|
||||
}
|
||||
|
||||
cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
|
||||
while (cpab == ARMul_BUSY)
|
||||
{
|
||||
@ -757,9 +698,7 @@ ARMul_CDP (ARMul_State * state, ARMword instr)
|
||||
BUSUSEDN;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This function handles Undefined instructions, as CP isntruction *
|
||||
\***************************************************************************/
|
||||
/* This function handles Undefined instructions, as CP isntruction. */
|
||||
|
||||
void
|
||||
ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
|
||||
@ -767,37 +706,35 @@ ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
|
||||
ARMul_Abort (state, ARMul_UndefinedInstrV);
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Return TRUE if an interrupt is pending, FALSE otherwise. *
|
||||
\***************************************************************************/
|
||||
/* Return TRUE if an interrupt is pending, FALSE otherwise. */
|
||||
|
||||
unsigned
|
||||
IntPending (ARMul_State * state)
|
||||
{
|
||||
if (state->Exception)
|
||||
{ /* Any exceptions */
|
||||
{
|
||||
/* Any exceptions. */
|
||||
if (state->NresetSig == LOW)
|
||||
{
|
||||
ARMul_Abort (state, ARMul_ResetV);
|
||||
return (TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
else if (!state->NfiqSig && !FFLAG)
|
||||
{
|
||||
ARMul_Abort (state, ARMul_FIQV);
|
||||
return (TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
else if (!state->NirqSig && !IFLAG)
|
||||
{
|
||||
ARMul_Abort (state, ARMul_IRQV);
|
||||
return (TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return (FALSE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* Align a word access to a non word boundary *
|
||||
\***************************************************************************/
|
||||
/* Align a word access to a non word boundary. */
|
||||
|
||||
ARMword
|
||||
ARMul_Align (state, address, data)
|
||||
@ -808,20 +745,18 @@ ARMul_Align (state, address, data)
|
||||
/* This code assumes the address is really unaligned,
|
||||
as a shift by 32 is undefined in C. */
|
||||
|
||||
address = (address & 3) << 3; /* get the word address */
|
||||
address = (address & 3) << 3; /* Get the word address. */
|
||||
return ((data >> address) | (data << (32 - address))); /* rot right */
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine is used to call another routine after a certain number of *
|
||||
* cycles have been executed. The first parameter is the number of cycles *
|
||||
* delay before the function is called, the second argument is a pointer *
|
||||
* to the function. A delay of zero doesn't work, just call the function. *
|
||||
\***************************************************************************/
|
||||
/* This routine is used to call another routine after a certain number of
|
||||
cycles have been executed. The first parameter is the number of cycles
|
||||
delay before the function is called, the second argument is a pointer
|
||||
to the function. A delay of zero doesn't work, just call the function. */
|
||||
|
||||
void
|
||||
ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
|
||||
unsigned (*what) ())
|
||||
unsigned (*what) (ARMul_State *))
|
||||
{
|
||||
unsigned long when;
|
||||
struct EventNode *event;
|
||||
@ -835,10 +770,8 @@ ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
|
||||
*(state->EventPtr + when) = event;
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine is called at the beginning of every cycle, to envoke *
|
||||
* scheduled events. *
|
||||
\***************************************************************************/
|
||||
/* This routine is called at the beginning of
|
||||
every cycle, to envoke scheduled events. */
|
||||
|
||||
void
|
||||
ARMul_EnvokeEvent (ARMul_State * state)
|
||||
@ -847,23 +780,26 @@ ARMul_EnvokeEvent (ARMul_State * state)
|
||||
|
||||
then = state->Now;
|
||||
state->Now = ARMul_Time (state) % EVENTLISTSIZE;
|
||||
if (then < state->Now) /* schedule events */
|
||||
if (then < state->Now)
|
||||
/* Schedule events. */
|
||||
EnvokeList (state, then, state->Now);
|
||||
else if (then > state->Now)
|
||||
{ /* need to wrap around the list */
|
||||
{
|
||||
/* Need to wrap around the list. */
|
||||
EnvokeList (state, then, EVENTLISTSIZE - 1L);
|
||||
EnvokeList (state, 0L, state->Now);
|
||||
}
|
||||
}
|
||||
|
||||
/* Envokes all the entries in a range. */
|
||||
|
||||
static void
|
||||
EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
|
||||
/* envokes all the entries in a range */
|
||||
{
|
||||
struct EventNode *anevent;
|
||||
|
||||
for (; from <= to; from++)
|
||||
{
|
||||
struct EventNode *anevent;
|
||||
|
||||
anevent = *(state->EventPtr + from);
|
||||
while (anevent)
|
||||
{
|
||||
@ -875,9 +811,7 @@ EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************\
|
||||
* This routine is returns the number of clock ticks since the last reset. *
|
||||
\***************************************************************************/
|
||||
/* This routine is returns the number of clock ticks since the last reset. */
|
||||
|
||||
unsigned long
|
||||
ARMul_Time (ARMul_State * state)
|
||||
|
Loading…
Reference in New Issue
Block a user