* XScale coprocessor support.
authorMatthew Green <mrg@redhat.com>
Wed, 18 Apr 2001 16:39:37 +0000 (16:39 +0000)
committerMatthew Green <mrg@redhat.com>
Wed, 18 Apr 2001 16:39:37 +0000 (16:39 +0000)
2001-04-18  matthew green  <mrg@redhat.com>

* armcopro.c (write_cp15_reg): Set CHANGEMODE if endianness changes.
(read_cp15_reg): Make non-static.
(XScale_cp15_LDC): Update for write_cp15_reg() change.
(XScale_cp15_MCR): Likewise.
(XScale_cp15_write_reg): Likewise.
(XScale_check_memacc): New function. Check for breakpoints being
activated by memory accesses.  Does not support the Branch Target
Buffer.
(XScale_set_fsr_far): New function. Set FSR and FAR for XScale.
(XScale_debug_moe): New function. Set the debug Method Of Entry,
if configured.
(write_cp14_reg): Reset count counter if requested.
* armdefs.h (struct ARMul_State): New members `LastTime' and
`CP14R0_CCD' used for the timer/counters.
(ARMul_CP13_R0_FIQ, ARMul_CP13_R0_IRQ, ARMul_CP13_R8_PMUS,
ARMul_CP14_R0_ENABLE, ARMul_CP14_R0_CLKRST, ARMul_CP14_R0_CCD,
ARMul_CP14_R0_INTEN0, ARMul_CP14_R0_INTEN1, ARMul_CP14_R0_INTEN2,
ARMul_CP14_R0_FLAG0, ARMul_CP14_R0_FLAG1, ARMul_CP14_R0_FLAG2,
ARMul_CP14_R10_MOE_IB, ARMul_CP14_R10_MOE_DB, ARMul_CP14_R10_MOE_BT,
ARMul_CP15_R1_ENDIAN, ARMul_CP15_R1_ALIGN, ARMul_CP15_R5_X,
ARMul_CP15_R5_ST_ALIGN, ARMul_CP15_R5_IMPRE, ARMul_CP15_R5_MMU_EXCPT,
ARMul_CP15_DBCON_M, ARMul_CP15_DBCON_E1, ARMul_CP15_DBCON_E0): New
defines for XScale registers.
(XScale_check_memacc, XScale_set_fsr_far, XScale_debug_moe): Prototype.
(ARMul_Emulate32, ARMul_Emulate26): Clean up function definition.
(ARMul_Emulate32): Handle the clock counter and hardware instruction
breakpoints.  Call XScale_set_fsr_far() for software breakpoints and
software interrupts.
(LoadMult): Call XScale_set_fsr_far() for data aborts.
(LoadSMult): Likewise.
(StoreMult): Likewise.
(StoreSMult): Likewise.
* armemu.h (write_cp15_reg): Update prototype.
* arminit.c (ARMul_NewState): Initialise CP14R0_CCD and LastTime.
(ARMul_Abort): If XScale, check for FIQ and IRQ being enabled in CP13
register 0.
* armvirt.c (GetWord): Call XScale_check_memacc().
(PutWord): Likewise.

sim/arm/ChangeLog
sim/arm/armcopro.c
sim/arm/armdefs.h
sim/arm/armemu.c
sim/arm/arminit.c
sim/arm/armvirt.c

index 9f81f54..5c031ab 100644 (file)
@@ -1,3 +1,44 @@
+2001-04-18  matthew green  <mrg@redhat.com>
+
+       * armcopro.c (write_cp15_reg): Set CHANGEMODE if endianness changes.
+       (read_cp15_reg): Make non-static.
+       (XScale_cp15_LDC): Update for write_cp15_reg() change.
+       (XScale_cp15_MCR): Likewise.
+       (XScale_cp15_write_reg): Likewise.
+       (XScale_check_memacc): New function. Check for breakpoints being
+       activated by memory accesses.  Does not support the Branch Target
+       Buffer.
+       (XScale_set_fsr_far): New function. Set FSR and FAR for XScale.
+       (XScale_debug_moe): New function. Set the debug Method Of Entry,
+       if configured.
+       (write_cp14_reg): Reset count counter if requested.
+       * armdefs.h (struct ARMul_State): New members `LastTime' and
+       `CP14R0_CCD' used for the timer/counters.
+       (ARMul_CP13_R0_FIQ, ARMul_CP13_R0_IRQ, ARMul_CP13_R8_PMUS,
+       ARMul_CP14_R0_ENABLE, ARMul_CP14_R0_CLKRST, ARMul_CP14_R0_CCD,
+       ARMul_CP14_R0_INTEN0, ARMul_CP14_R0_INTEN1, ARMul_CP14_R0_INTEN2,
+       ARMul_CP14_R0_FLAG0, ARMul_CP14_R0_FLAG1, ARMul_CP14_R0_FLAG2,
+       ARMul_CP14_R10_MOE_IB, ARMul_CP14_R10_MOE_DB, ARMul_CP14_R10_MOE_BT,
+       ARMul_CP15_R1_ENDIAN, ARMul_CP15_R1_ALIGN, ARMul_CP15_R5_X,
+       ARMul_CP15_R5_ST_ALIGN, ARMul_CP15_R5_IMPRE, ARMul_CP15_R5_MMU_EXCPT,
+       ARMul_CP15_DBCON_M, ARMul_CP15_DBCON_E1, ARMul_CP15_DBCON_E0): New
+       defines for XScale registers.
+       (XScale_check_memacc, XScale_set_fsr_far, XScale_debug_moe): Prototype.
+       (ARMul_Emulate32, ARMul_Emulate26): Clean up function definition.
+       (ARMul_Emulate32): Handle the clock counter and hardware instruction
+       breakpoints.  Call XScale_set_fsr_far() for software breakpoints and
+       software interrupts.
+       (LoadMult): Call XScale_set_fsr_far() for data aborts.
+       (LoadSMult): Likewise.
+       (StoreMult): Likewise.
+       (StoreSMult): Likewise.
+       * armemu.h (write_cp15_reg): Update prototype.
+       * arminit.c (ARMul_NewState): Initialise CP14R0_CCD and LastTime.
+       (ARMul_Abort): If XScale, check for FIQ and IRQ being enabled in CP13
+       register 0.
+       * armvirt.c (GetWord): Call XScale_check_memacc().
+       (PutWord): Likewise.
+
 2001-03-20  Nick Clifton  <nickc@redhat.com>
 
        * armvirt.c (ARMul_ReLoadInstr): Do not enable alignment checking
index 8605dcf..52b22d7 100644 (file)
@@ -246,6 +246,15 @@ write_cp15_reg (ARMul_State * state, unsigned reg, unsigned opcode_2, unsigned C
             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.  */
@@ -446,6 +455,103 @@ XScale_cp15_write_reg (ARMul_State * state ATTRIBUTE_UNUSED,
   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))
+    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);
+       }
+    }
+}
+
+/***************************************************************************\
+*        Check set 
+\***************************************************************************/
+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.
@@ -735,6 +841,10 @@ write_cp14_reg (unsigned reg, ARMword value)
     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:
index 4ad5c5f..fde3125 100644 (file)
@@ -102,6 +102,9 @@ struct ARMul_State
   ARMul_CPWrites *CPWrite[16]; /* Write CP register */
   unsigned char *CPData[16];   /* Coprocessor data */
   unsigned char const *CPRegWords[16]; /* map of coprocessor register sizes */
+  unsigned long LastTime;      /* Value of last call to ARMul_Time() */
+  ARMword CP14R0_CCD;          /* used to count 64 clock cycles with CP14 R0 bit
+                                  3 set */
 
   unsigned EventSet;           /* the number of events in the queue */
   unsigned long Now;           /* time to the nearest cycle */
@@ -342,6 +345,32 @@ extern ARMword ARMul_MemAccess (ARMul_State * state, ARMword, ARMword,
 #define ARMul_CANT 1
 #define ARMul_INC 3
 
+#define ARMul_CP13_R0_FIQ      0x1
+#define ARMul_CP13_R0_IRQ      0x2
+#define ARMul_CP13_R8_PMUS     0x1
+
+#define ARMul_CP14_R0_ENABLE   0x0001
+#define ARMul_CP14_R0_CLKRST   0x0004
+#define ARMul_CP14_R0_CCD      0x0008
+#define ARMul_CP14_R0_INTEN0   0x0010
+#define ARMul_CP14_R0_INTEN1   0x0020
+#define ARMul_CP14_R0_INTEN2   0x0040
+#define ARMul_CP14_R0_FLAG0    0x0100
+#define ARMul_CP14_R0_FLAG1    0x0200
+#define ARMul_CP14_R0_FLAG2    0x0400
+#define ARMul_CP14_R10_MOE_IB  0x0004
+#define ARMul_CP14_R10_MOE_DB  0x0008
+#define ARMul_CP14_R10_MOE_BT  0x000c
+#define ARMul_CP15_R1_ENDIAN   0x0080
+#define ARMul_CP15_R1_ALIGN    0x0002
+#define ARMul_CP15_R5_X                0x0400
+#define ARMul_CP15_R5_ST_ALIGN 0x0001
+#define ARMul_CP15_R5_IMPRE    0x0406
+#define ARMul_CP15_R5_MMU_EXCPT        0x0400
+#define ARMul_CP15_DBCON_M     0x0100
+#define ARMul_CP15_DBCON_E1    0x000c
+#define ARMul_CP15_DBCON_E0    0x0003
+
 extern unsigned ARMul_CoProInit (ARMul_State * state);
 extern void ARMul_CoProExit (ARMul_State * state);
 extern void ARMul_CoProAttach (ARMul_State * state, unsigned number,
@@ -351,6 +380,10 @@ extern void ARMul_CoProAttach (ARMul_State * state, unsigned number,
                               ARMul_CDPs * cdp,
                               ARMul_CPReads * read, ARMul_CPWrites * write);
 extern void ARMul_CoProDetach (ARMul_State * state, unsigned number);
+extern void XScale_check_memacc (ARMul_State * state, ARMword * address,
+                                int store);
+extern void XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword far);
+extern int XScale_debug_moe (ARMul_State * state, int moe);
 
 /***************************************************************************\
 *               Definitons of things in the host environment                *
index dcc505f..0947470 100644 (file)
@@ -529,6 +529,79 @@ ARMul_Emulate26 (register ARMul_State * state)
          break;
        }                       /* cc check */
 
+      /* Handle the Clock counter here.  */
+      if (state->is_XScale)
+       {
+         ARMword cp14r0 = state->CPRead[14] (state, 0, 0);
+
+         if (cp14r0 && ARMul_CP14_R0_ENABLE)
+           {
+             unsigned long newcycles, nowtime = ARMul_Time(state);
+
+             newcycles = nowtime - state->LastTime;
+             state->LastTime = nowtime;
+             if (cp14r0 && ARMul_CP14_R0_CCD)
+               {
+                 if (state->CP14R0_CCD == -1)
+                   state->CP14R0_CCD = newcycles;
+                 else
+                   state->CP14R0_CCD += newcycles;
+                 if (state->CP14R0_CCD >= 64)
+                   {
+                     newcycles = 0;
+                     while (state->CP14R0_CCD >= 64)
+                       state->CP14R0_CCD -= 64, newcycles++;
+                     goto check_PMUintr;
+                   }
+               }
+             else
+               {
+                 ARMword cp14r1;
+                 int do_int = 0;
+
+                 state->CP14R0_CCD = -1;
+check_PMUintr:
+                 cp14r0 |= ARMul_CP14_R0_FLAG2;
+                 (void) state->CPWrite[14] (state, 0, cp14r0);
+
+                 cp14r1 = state->CPRead[14] (state, 1, 0);
+
+                 /* coded like this for portability */
+                 while (newcycles)
+                   {
+                     if (cp14r1 == 0xffffffff)
+                       {
+                         cp14r1 = 0;
+                         do_int = 1;
+                       }
+                     else
+                       cp14r1++;
+                       newcycles--;
+                   }
+                 (void) state->CPWrite[14] (state, 1, cp14r1);
+                 if (do_int && (cp14r0 & ARMul_CP14_R0_INTEN2))
+                   {
+                     if (state->CPRead[13] (state, 8, 0)
+                       && ARMul_CP13_R8_PMUS)
+                       ARMul_Abort (state, ARMul_FIQV);
+                     else
+                       ARMul_Abort (state, ARMul_IRQV);
+                   }
+               }
+           }
+       }
+
+      /* Handle hardware instructions breakpoints here.  */
+      if (state->is_XScale)
+       {
+         if ((pc | 3) == (read_cp15_reg (14, 0, 8) | 2)
+           || (pc | 3) == (read_cp15_reg (14, 0, 9) | 2))
+           {
+             if (XScale_debug_moe (state, ARMul_CP14_R10_MOE_IB))
+               ARMul_OSHandleSWI (state, SWI_Breakpoint);
+           }
+       }
+
 /***************************************************************************\
 *               Actual execution of instructions begins here                *
 \***************************************************************************/
@@ -1355,26 +1428,11 @@ ARMul_Emulate26 (register ARMul_State * state)
                        ARMul_OSHandleSWI (state, SWI_Breakpoint);
                      else
                        {
-                         /* BKPT - normally this will cause an abort, but for the
-                            XScale if bit 31 in register 10 of coprocessor 14 is
-                            clear, then this is treated as a no-op.  */
-                         if (state->is_XScale)
-                           {
-                             if (read_cp14_reg (10) & (1UL << 31))
-                               {
-                                 ARMword value;
-                                 
-                                 value = read_cp14_reg (10);
-                                 value &= ~0x1c;
-                                 value |= 0xc;
-                                 
-                                 write_cp14_reg (10, value);
-                                 write_cp15_reg (state, 5, 0, 0, 0x200);  /* Set FSR.  */
-                                 write_cp15_reg (state, 6, 0, 0, pc);     /* Set FAR.  */
-                               }
-                             else
-                               break;
-                           }
+                       /* BKPT - normally this will cause an abort, but on the
+                          XScale we must check the DCSR.  */
+                         XScale_set_fsr_far (state, ARMul_CP15_R5_MMU_EXCPT, pc);
+                         if (!XScale_debug_moe (state, ARMul_CP14_R10_MOE_BT))
+                           break;
                        }
 
                      /* Force the next instruction to be refetched.  */
@@ -3425,6 +3483,7 @@ ARMul_Emulate26 (register ARMul_State * state)
              if (instr == ARMul_ABORTWORD && state->AbortAddr == pc)
                {
                  /* A prefetch abort.  */
+                 XScale_set_fsr_far (state, ARMul_CP15_R5_MMU_EXCPT, pc);
                  ARMul_Abort (state, ARMul_PrefetchAbortV);
                  break;
                }
@@ -4295,6 +4354,7 @@ LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase)
     state->Reg[temp++] = dest;
   else if (!state->Aborted)
     {
+      XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
       state->Aborted = ARMul_DataAbortV;
     }
 
@@ -4307,6 +4367,7 @@ LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase)
          state->Reg[temp] = dest;
        else if (!state->Aborted)
          {
+            XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
            state->Aborted = ARMul_DataAbortV;
          }
       }
@@ -4373,6 +4434,7 @@ LoadSMult (ARMul_State * state,
     state->Reg[temp++] = dest;
   else if (!state->Aborted)
     {
+      XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
       state->Aborted = ARMul_DataAbortV;
     }
 
@@ -4388,6 +4450,7 @@ LoadSMult (ARMul_State * state,
          state->Reg[temp] = dest;
        else if (!state->Aborted)
          {
+            XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
            state->Aborted = ARMul_DataAbortV;
          }
       }
@@ -4489,6 +4552,7 @@ StoreMult (ARMul_State * state, ARMword instr,
 
   if (state->abortSig && !state->Aborted)
     {
+      XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
       state->Aborted = ARMul_DataAbortV;
     }
 
@@ -4504,6 +4568,7 @@ StoreMult (ARMul_State * state, ARMword instr,
 
        if (state->abortSig && !state->Aborted)
          {
+            XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
            state->Aborted = ARMul_DataAbortV;
          }
       }
@@ -4585,6 +4650,7 @@ StoreSMult (ARMul_State * state,
 
   if (state->abortSig && !state->Aborted)
     {
+      XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
       state->Aborted = ARMul_DataAbortV;
     }
 
@@ -4599,6 +4665,7 @@ StoreSMult (ARMul_State * state,
 
        if (state->abortSig && !state->Aborted)
          {
+            XScale_set_fsr_far(state, ARMul_CP15_R5_ST_ALIGN, address);
            state->Aborted = ARMul_DataAbortV;
          }
       }
index 2f6e73d..bdbb2c7 100644 (file)
@@ -106,6 +106,9 @@ ARMul_NewState (void)
   state->OSptr = NULL;
   state->CommandLine = NULL;
 
+  state->CP14R0_CCD = -1;
+  state->LastTime = 0;
+
   state->EventSet = 0;
   state->Now = 0;
   state->EventPtr = (struct EventNode **) malloc ((unsigned) EVENTLISTSIZE *
@@ -299,10 +302,14 @@ ARMul_Abort (ARMul_State * state, ARMword vector)
       SETABORT (IBIT, SVC26MODE, isize);
       break;
     case ARMul_IRQV:           /* IRQ */
-      SETABORT (IBIT, state->prog32Sig ? IRQ32MODE : IRQ26MODE, esize);
+      if (!state->is_XScale
+         || (state->CPRead[13](state, 0, 0) & ARMul_CP13_R0_IRQ))
+        SETABORT (IBIT, state->prog32Sig ? IRQ32MODE : IRQ26MODE, esize);
       break;
     case ARMul_FIQV:           /* FIQ */
-      SETABORT (INTBITS, state->prog32Sig ? FIQ32MODE : FIQ26MODE, esize);
+      if (!state->is_XScale
+         || (state->CPRead[13](state, 0, 0) & ARMul_CP13_R0_FIQ))
+        SETABORT (INTBITS, state->prog32Sig ? FIQ32MODE : FIQ26MODE, esize);
       break;
     }
   if (ARMul_MODE32BIT)
index 15f2cb6..ce1e77d 100644 (file)
@@ -64,6 +64,8 @@ GetWord (ARMul_State * state, ARMword address, int check)
   ARMword **pagetable;
   ARMword *pageptr;
 
+  XScale_check_memacc (state, &address, 0);
+
   page = address >> PAGEBITS;
   offset = (address & OFFSETBITS) >> 2;
   pagetable = (ARMword **) state->MemDataPtr;
@@ -97,6 +99,8 @@ PutWord (ARMul_State * state, ARMword address, ARMword data, int check)
   ARMword **pagetable;
   ARMword *pageptr;
 
+  XScale_check_memacc (state, &address, 1);
+
   page = address >> PAGEBITS;
   offset = (address & OFFSETBITS) >> 2;
   pagetable = (ARMword **) state->MemDataPtr;