The previous version never wrote dirty registers
for non-current CPU modes ... fix that.
---
And with this ... Cortex-A8 is fairly well supporting all
the top level ARM operations, like ARM7 and ARM9 do.

There are various performance optimizations that can be
made, however.  And it'd be nice if the reset logic
used the vector catch hardware.  :)

 src/target/cortex_a8.c |   80 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 67 insertions(+), 13 deletions(-)

--- a/src/target/cortex_a8.c
+++ b/src/target/cortex_a8.c
@@ -531,7 +531,7 @@ static int cortex_a8_resume(struct targe
                        armv4_5->core_mode, 15).valid = 1;
 
        cortex_a8_restore_context(target);
-//     arm7_9_restore_context(target); TODO Context is currently NOT Properly 
restored
+
 #if 0
        /* the front-end may request us not to handle breakpoints */
        if (handle_breakpoints)
@@ -850,30 +850,84 @@ static int cortex_a8_step(struct target 
 
 static int cortex_a8_restore_context(struct target *target)
 {
-       int i;
        uint32_t value;
        struct armv7a_common *armv7a = target_to_armv7a(target);
-       struct armv4_5_common_s *armv4_5 = &armv7a->armv4_5_common;
+       struct reg_cache *cache = armv7a->armv4_5_common.core_cache;
+       unsigned max = cache->num_regs;
+       struct reg *r;
+       bool flushed, flush_cpsr = false;
 
        LOG_DEBUG(" ");
 
        if (armv7a->pre_restore_context)
                armv7a->pre_restore_context(target);
 
-       for (i = 15; i >= 0; i--)
-       {
-               if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache,
-                                       armv4_5->core_mode, i).dirty)
-               {
-                       value = buf_get_u32(ARMV4_5_CORE_REG_MODE(
-                                               armv4_5->core_cache,
-                                               armv4_5->core_mode, i).value,
-                                       0, 32);
+       /* Flush all dirty registers from the cache, one mode at a time so
+        * that we write CPSR as little as possible.  Save CPSR and R0 for
+        * last; they're used to change modes and write other registers.
+        *
+        * REVISIT be smarter:  save eventual mode for last loop, don't
+        * need to write CPSR an extra time.
+        */
+       do {
+               enum armv4_5_mode mode = ARMV4_5_MODE_ANY;
+               unsigned i;
+
+               flushed = false;
+
+               /* write dirty non-{R0,CPSR} registers sharing the same mode */
+               for (i = max - 1, r = cache->reg_list + 1; i > 0; i--, r++) {
+                       struct armv4_5_core_reg *reg;
+
+                       if (!r->dirty || i == ARMV4_5_CPSR)
+                               continue;
+                       reg = r->arch_info;
+
                        /* TODO Check return values */
-                       cortex_a8_dap_write_coreregister_u32(target, value, i);
+
+                       /* Pick a mode and update CPSR; else ignore this
+                        * register if it's for a different mode than what
+                        * we're handling on this pass.
+                        *
+                        * REVISIT don't distinguish SYS and USR modes.
+                        *
+                        * FIXME if we restore from FIQ mode, R8..R12 will
+                        * get wrongly flushed onto FIQ shadows...
+                        */
+                       if (mode == ARMV4_5_MODE_ANY) {
+                               mode = reg->mode;
+                               if (mode != ARMV4_5_MODE_ANY) {
+                                       cortex_a8_dap_write_coreregister_u32(
+                                                       target, mode, 16);
+                                       flush_cpsr = true;
+                               }
+                       } else if (mode != reg->mode)
+                               continue;
+
+                       /* Write this register */
+                       value = buf_get_u32(r->value, 0, 32);
+                       cortex_a8_dap_write_coreregister_u32(target, value,
+                                       (reg->num == 16) ? 17 : reg->num);
+                       r->dirty = false;
+                       flushed = true;
                }
+
+       } while (flushed);
+
+       /* now flush CPSR if needed ... */
+       r = cache->reg_list + ARMV4_5_CPSR;
+       if (flush_cpsr || r->dirty) {
+               value = buf_get_u32(r->value, 0, 32);
+               cortex_a8_dap_write_coreregister_u32(target, value, 16);
+               r->dirty = false;
        }
 
+       /* ... and R0 always (it was dirtied when we saved context) */
+       r = cache->reg_list + 0;
+       value = buf_get_u32(r->value, 0, 32);
+       cortex_a8_dap_write_coreregister_u32(target, value, 0);
+       r->dirty = false;
+
        if (armv7a->post_restore_context)
                armv7a->post_restore_context(target);
 
_______________________________________________
Openocd-development mailing list
Openocd-development@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/openocd-development

Reply via email to