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"
#include "armemu.h"
#include "ansidecl.h"
+#include "iwmmxt.h"
/* Dummy Co-processors. */
/* 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
/* Initialise the ARM Control Register. */
XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078;
-
}
/* Check an access to a register. */
/* Opcode_1should be zero. */
if (opcode_1 != 0)
return ARMul_CANT;
-
+
/* Different register have different access requirements. */
switch (reg)
{
case 0: if ((CRm < 5) || (CRm > 7)) return ARMul_CANT; break;
}
break;
-
+
case 8:
/* Permissable combinations:
Opcode_2 CRm
/* 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)
{
/* 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
BITS (31, 14) and BIT (10) write as zero, BITS (6, 3) write as one. */
value &= 0x00003b87;
value |= 0x00000078;
+
+ /* Change the endianness if necessary. */
+ if ((value & ARMul_CP15_R1_ENDIAN) !=
+ (XScale_cp15_opcode_2_is_0_Regs [reg] & ARMul_CP15_R1_ENDIAN))
+ {
+ state->bigendSig = value & ARMul_CP15_R1_ENDIAN;
+ /* Force ARMulator to notice these now. */
+ state->Emulate = CHANGEMODE;
+ }
break;
case 2: /* Translation Table Base. */
/* 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;
/* 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;
}
break;
}
}
-
+
return XScale_cp15_opcode_2_is_0_Regs [reg];
}
else
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);
{
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. */
+
+void
+XScale_check_memacc (ARMul_State * state, ARMword * address, int store)
+{
+ ARMword dbcon, r0, r1;
+ int e1, e0;
+
+ if (!state->is_XScale)
+ return;
+
+ /* Check for PID-ification.
+ XXX BTB access support will require this test failing. */
+ r0 = (read_cp15_reg (13, 0, 0) & 0xfe000000);
+ if (r0 && (* address & 0xfe000000) == 0)
+ * address |= r0;
+
+ /* Check alignment fault enable/disable. */
+ if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN) && (* address & 3))
+ {
+ /* Set the FSR and FAR.
+ Do not use XScale_set_fsr_far as this checks the DCSR register. */
+ write_cp15_reg (state, 5, 0, 0, ARMul_CP15_R5_MMU_EXCPT);
+ write_cp15_reg (state, 6, 0, 0, * address);
+
+ ARMul_Abort (state, ARMul_DataAbortV);
+ }
+
+ if (XScale_debug_moe (state, -1))
+ return;
+
+ /* Check the data breakpoint registers. */
+ dbcon = read_cp15_reg (14, 0, 4);
+ r0 = read_cp15_reg (14, 0, 0);
+ r1 = read_cp15_reg (14, 0, 3);
+ e0 = dbcon & ARMul_CP15_DBCON_E0;
+
+ if (dbcon & ARMul_CP15_DBCON_M)
+ {
+ /* r1 is a inverse mask. */
+ if (e0 != 0 && ((store && e0 != 3) || (!store && e0 != 1))
+ && ((* address & ~r1) == (r0 & ~r1)))
+ {
+ XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB);
+ ARMul_OSHandleSWI (state, SWI_Breakpoint);
+ }
+ }
+ else
+ {
+ if (e0 != 0 && ((store && e0 != 3) || (!store && e0 != 1))
+ && ((* address & ~3) == (r0 & ~3)))
+ {
+ XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB);
+ ARMul_OSHandleSWI (state, SWI_Breakpoint);
+ }
+
+ e1 = (dbcon & ARMul_CP15_DBCON_E1) >> 2;
+ if (e1 != 0 && ((store && e1 != 3) || (!store && e1 != 1))
+ && ((* address & ~3) == (r1 & ~3)))
+ {
+ XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB);
+ ARMul_OSHandleSWI (state, SWI_Breakpoint);
+ }
+ }
+}
+
+/* Set the XScale FSR and FAR registers. */
+
+void
+XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword far)
+{
+ if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0)
+ return;
+
+ write_cp15_reg (state, 5, 0, 0, fsr);
+ write_cp15_reg (state, 6, 0, 0, far);
+}
+
+/* Set the XScale debug `method of entry' if it is enabled. */
+
+int
+XScale_debug_moe (ARMul_State * state, int moe)
+{
+ ARMword value;
+
+ if (!state->is_XScale)
+ return 1;
+
+ value = read_cp14_reg (10);
+ if (value & (1UL << 31))
+ {
+ if (moe != -1)
+ {
+ value &= ~0x1c;
+ value |= moe;
+
+ write_cp14_reg (10, value);
+ }
+ return 1;
+ }
+ return 0;
+}
+
/* Coprocessor 13: Interrupt Controller and Bus Controller. */
/* There are two sets of registers for copro 13.
unsigned opcode_1,
unsigned opcode_2)
{
- /* Do not allow access to these register in USER mode. */
+ /* Do not allow access to these registers in USER mode. */
if (state->Mode == USER26MODE || state->Mode == USER32MODE)
return ARMul_CANT;
/* 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.
+ Registers 0, 1, 4, 5, 6, 7, 8 are defined when CRm == 1.
For all other CRm values undefined behaviour results. */
if (CRm == 0)
{
}
else if (CRm == 1)
{
- if (reg == 0 || (reg >= 4 && reg <= 8))
+ if (reg == 0 || reg == 1 || (reg >= 4 && reg <= 8))
return ARMul_DONE;
}
/* 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;
value &= 0x7000000f;
value |= XScale_cp13_CR1_Regs[0] & (1UL << 31);
break;
-
+
+ case 1: /* BCUMOD */
+ /* Only bit 0 is accecssible. */
+ value &= 1;
+ value |= XScale_cp13_CR1_Regs[1] & ~ 1;
+ break;
+
case 4: /* ELOG0 */
case 5: /* ELOG1 */
case 6: /* ECAR0 */
/* 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;
/* Should not happen. */
break;
}
-
+
return;
}
{
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);
{
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;
}
/* 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;
/* Store a value into one of coprocessor 14's registers. */
-void
+static void
write_cp14_reg (unsigned reg, ARMword value)
{
switch (reg)
case 0: /* PMNC */
/* Only BITS (27:12), BITS (10:8) and BITS (6:0) can be written. */
value &= 0x0ffff77f;
+
+ /* Reset the clock counter if necessary. */
+ if (value & ARMul_CP14_R0_CLKRST)
+ XScale_cp14_Regs [1] = 0;
break;
case 4:
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;
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;
/* 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;
{
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);
{
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;
}
{
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;
}
{
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;
}
)
{
* value = read_cp14_reg (reg);
-
+
return TRUE;
}
)
{
write_cp14_reg (reg, value);
-
+
return TRUE;
}
d = state->data32Sig;
l = state->lateabtSig;
b = state->bigendSig;
-
+
state->prog32Sig = value >> 4 & 1;
state->data32Sig = value >> 5 & 1;
state->lateabtSig = value >> 6 & 1;
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
if (words++ != 4)
return ARMul_INC;
}
-
+
return ARMul_DONE;
}
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)
else
return ARMul_BUSY;
}
-
+
return ARMul_CANT;
}
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)
/* Install CoPro Instruction handlers here.
The format is:
- ARMul_CoProAttach (state, CP Number,
- Init routine, Exit routine
- LDC routine, STC routine,
- MRC routine, MCR routine,
- CDP routine,
- Read Reg routine, Write Reg routine). */
- ARMul_CoProAttach (state, 4, NULL, NULL,
- ValLDC, ValSTC, ValMRC, ValMCR, ValCDP, NULL, NULL);
-
- ARMul_CoProAttach (state, 5, NULL, NULL,
- NULL, NULL, ValMRC, ValMCR, IntCDP, NULL, NULL);
-
- ARMul_CoProAttach (state, 15, MMUInit, NULL,
- NULL, NULL, MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
-
- ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL,
- 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);
+ ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
+ LDC routine, STC routine, MRC routine, MCR routine,
+ CDP routine, Read Reg routine, Write Reg routine). */
+ if (state->is_ep9312)
+ {
+ ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4,
+ DSPMRC4, DSPMCR4, DSPCDP4, NULL, NULL);
+ ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5,
+ DSPMRC5, DSPMCR5, DSPCDP5, NULL, NULL);
+ ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL,
+ DSPMRC6, DSPMCR6, DSPCDP6, NULL, NULL);
+ }
+ else
+ {
+ ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC,
+ ValMRC, ValMCR, ValCDP, NULL, NULL);
+
+ ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL,
+ ValMRC, ValMCR, IntCDP, NULL, NULL);
+ }
+
+ if (state->is_XScale)
+ {
+ ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL,
+ 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);
+ }
+ else
+ {
+ ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
+ MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
+ }
+
+ if (state->is_iWMMXt)
+ {
+ ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC,
+ NULL, NULL, IwmmxtCDP, NULL, NULL);
+
+ ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL,
+ IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, NULL);
+ }
/* No handlers below here. */
return TRUE;
}
-/***************************************************************************\
-* Install co-processor finalisation routines in this routine *
-\***************************************************************************/
+/* Install co-processor finalisation routines in this routine. */
void
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,