XScale: restore_context() cleanup
[fw/openocd] / src / target / xscale.c
index 0e58f575e782fdf3ea8ec97b75784c68024e0b76..ccb1de563d80aefa7f8439edc6674186728e69db 100644 (file)
@@ -62,7 +62,7 @@
 static int xscale_resume(struct target *, int current,
        uint32_t address, int handle_breakpoints, int debug_execution);
 static int xscale_debug_entry(struct target *);
-static int xscale_restore_context(struct target *);
+static int xscale_restore_banked(struct target *);
 static int xscale_get_reg(struct reg *reg);
 static int xscale_set_reg(struct reg *reg, uint8_t *buf);
 static int xscale_set_breakpoint(struct target *, struct breakpoint *);
@@ -1251,7 +1251,7 @@ static int xscale_resume(struct target *target, int current,
                        xscale_enable_single_step(target, next_pc);
 
                        /* restore banked registers */
-                       xscale_restore_context(target);
+                       retval = xscale_restore_banked(target);
 
                        /* send resume request (command 0x30 or 0x31)
                         * clean the trace buffer if it is to be enabled (0x62) */
@@ -1296,7 +1296,7 @@ static int xscale_resume(struct target *target, int current,
        xscale_enable_watchpoints(target);
 
        /* restore banked registers */
-       xscale_restore_context(target);
+       retval = xscale_restore_banked(target);
 
        /* send resume request (command 0x30 or 0x31)
         * clean the trace buffer if it is to be enabled (0x62) */
@@ -1371,7 +1371,7 @@ static int xscale_step_inner(struct target *target, int current,
                return retval;
 
        /* restore banked registers */
-       if ((retval = xscale_restore_context(target)) != ERROR_OK)
+       if ((retval = xscale_restore_banked(target)) != ERROR_OK)
                return retval;
 
        /* send resume request (command 0x30 or 0x31)
@@ -1697,50 +1697,56 @@ static int xscale_full_context(struct target *target)
         */
        for (i = 1; i < 7; i++)
        {
-               int valid = 1;
+               enum armv4_5_mode mode = armv4_5_number_to_mode(i);
+               bool valid = true;
+               struct reg *r;
+
+               if (mode == ARMV4_5_MODE_USR)
+                       continue;
 
                /* check if there are invalid registers in the current mode
                 */
-               for (j = 0; j <= 16; j++)
+               for (j = 0; valid && j <= 16; j++)
                {
-                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0)
-                               valid = 0;
+                       if (!ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
+                                       mode, j).valid)
+                               valid = false;
                }
+               if (valid)
+                       continue;
 
-               if (!valid)
-               {
-                       uint32_t tmp_cpsr;
-
-                       /* request banked registers */
-                       xscale_send_u32(target, 0x0);
+               /* request banked registers */
+               xscale_send_u32(target, 0x0);
 
-                       tmp_cpsr = 0x0;
-                       tmp_cpsr |= armv4_5_number_to_mode(i);
-                       tmp_cpsr |= 0xc0; /* I/F bits */
+               /* send CPSR for desired bank mode */
+               xscale_send_u32(target, mode | 0xc0 /* I/F bits */);
 
-                       /* send CPSR for desired mode */
-                       xscale_send_u32(target, tmp_cpsr);
+               /* get banked registers:  r8 to r14; and SPSR
+                * except in USR/SYS mode
+                */
+               if (mode != ARMV4_5_MODE_SYS) {
+                       /* SPSR */
+                       r = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
+                                       mode, 16);
+
+                       xscale_receive(target, buffer, 8);
+
+                       buf_set_u32(r->value, 0, 32, buffer[7]);
+                       r->dirty = false;
+                       r->valid = true;
+               } else {
+                       xscale_receive(target, buffer, 7);
+               }
 
-                       /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */
-                       if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
-                       {
-                               xscale_receive(target, buffer, 8);
-                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]);
-                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0;
-                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1;
-                       }
-                       else
-                       {
-                               xscale_receive(target, buffer, 7);
-                       }
+               /* move data from buffer to register cache */
+               for (j = 8; j <= 14; j++)
+               {
+                       r = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
+                                       mode, j);
 
-                       /* move data from buffer to register cache */
-                       for (j = 8; j <= 14; j++)
-                       {
-                               buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]);
-                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0;
-                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1;
-                       }
+                       buf_set_u32(r->value, 0, 32, buffer[j - 8]);
+                       r->dirty = false;
+                       r->valid = true;
                }
        }
 
@@ -1749,7 +1755,7 @@ static int xscale_full_context(struct target *target)
        return ERROR_OK;
 }
 
-static int xscale_restore_context(struct target *target)
+static int xscale_restore_banked(struct target *target)
 {
        struct arm *armv4_5 = target_to_armv4_5(target);
 
@@ -1762,54 +1768,60 @@ static int xscale_restore_context(struct target *target)
        }
 
        /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS)
-       * we can't enter User mode on an XScale (unpredictable),
-       * but User shares registers with SYS
-       */
+        * and check if any banked registers need to be written.  Ignore
+        * USR mode (number 0) in favor of SYS; we can't enter User mode on
+        * an XScale (unpredictable), but they share all registers.
+        */
        for (i = 1; i < 7; i++)
        {
-               int dirty = 0;
+               enum armv4_5_mode mode = armv4_5_number_to_mode(i);
+               struct reg *r;
 
-               /* check if there are invalid registers in the current mode
-               */
+               if (mode == ARMV4_5_MODE_USR)
+                       continue;
+
+               /* check if there are dirty registers in this mode */
                for (j = 8; j <= 14; j++)
                {
-                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1)
-                               dirty = 1;
+                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
+                                       mode, j).dirty)
+                               goto dirty;
                }
 
                /* if not USR/SYS, check if the SPSR needs to be written */
-               if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
+               if (mode != ARMV4_5_MODE_SYS)
                {
-                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1)
-                               dirty = 1;
+                       if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
+                                       mode, 16).dirty)
+                               goto dirty;
                }
 
-               if (dirty)
-               {
-                       uint32_t tmp_cpsr;
-
-                       /* send banked registers */
-                       xscale_send_u32(target, 0x1);
+               /* there's nothing to flush for this mode */
+               continue;
 
-                       tmp_cpsr = 0x0;
-                       tmp_cpsr |= armv4_5_number_to_mode(i);
-                       tmp_cpsr |= 0xc0; /* I/F bits */
+dirty:
+               /* command 0x1:  "send banked registers" */
+               xscale_send_u32(target, 0x1);
 
-                       /* send CPSR for desired mode */
-                       xscale_send_u32(target, tmp_cpsr);
+               /* send CPSR for desired mode */
+               xscale_send_u32(target, mode | 0xc0 /* I/F bits */);
 
-                       /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */
-                       for (j = 8; j <= 14; j++)
-                       {
-                               xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32));
-                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0;
-                       }
+               /* send r8 to r14/lr ... only FIQ needs more than r13..r14,
+                * but this protocol doesn't understand that nuance.
+                */
+               for (j = 8; j <= 14; j++) {
+                       r = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
+                                       mode, j);
+                       xscale_send_u32(target, buf_get_u32(r->value, 0, 32));
+                       r->dirty = false;
+               }
 
-                       if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
-                       {
-                               xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32));
-                               ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0;
-                       }
+               /* send spsr if not in USR/SYS mode */
+               if (mode != ARMV4_5_MODE_SYS) {
+                       r = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
+                                       mode, 16);
+                       xscale_send_u32(target, buf_get_u32(r->value, 0, 32));
+                       r->dirty = false;
                }
        }