diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 4e941060..abd64f4a 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -78,6 +78,9 @@ struct cortexm_priv { unsigned hw_breakpoint_max; /* Copy of DEMCR for vector-catch */ uint32_t demcr; + /* Cache parameters */ + bool has_cache; + uint32_t dcache_minline; }; /* Register number tables */ @@ -179,13 +182,40 @@ ADIv5_AP_t *cortexm_ap(target *t) return ((struct cortexm_priv *)t->priv)->ap; } +static void cortexm_cache_clean(target *t, target_addr addr, size_t len, bool invalidate) +{ + struct cortexm_priv *priv = t->priv; + if (!priv->has_cache || (priv->dcache_minline == 0)) + return; + uint32_t cache_reg = invalidate ? CORTEXM_DCCIMVAC : CORTEXM_DCCMVAC; + size_t minline = priv->dcache_minline; + + /* flush data cache for RAM regions that intersect requested region */ + target_addr mem_end = addr + len; /* following code is NOP if wraparound */ + /* requested region is [src, src_end) */ + for (struct target_ram *r = t->ram; r; r = r->next) { + target_addr ram = r->start; + target_addr ram_end = r->start + r->length; + /* RAM region is [ram, ram_end) */ + if (addr > ram) + ram = addr; + if (mem_end < ram_end) + ram_end = mem_end; + /* intersection is [ram, ram_end) */ + for (ram &= ~(minline-1); ram < ram_end; ram += minline) + adiv5_mem_write(cortexm_ap(t), cache_reg, &ram, 4); + } +} + static void cortexm_mem_read(target *t, void *dest, target_addr src, size_t len) { + cortexm_cache_clean(t, src, len, false); adiv5_mem_read(cortexm_ap(t), dest, src, len); } static void cortexm_mem_write(target *t, target_addr dest, const void *src, size_t len) { + cortexm_cache_clean(t, dest, len, true); adiv5_mem_write(cortexm_ap(t), dest, src, len); } @@ -251,6 +281,15 @@ bool cortexm_probe(ADIv5_AP_t *ap) priv->demcr = CORTEXM_DEMCR_TRCENA | CORTEXM_DEMCR_VC_HARDERR | CORTEXM_DEMCR_VC_CORERESET; + /* Check cache type */ + uint32_t ctr = target_mem_read32(t, CORTEXM_CTR); + if ((ctr >> 29) == 4) { + priv->has_cache = true; + priv->dcache_minline = 4 << (ctr & 0xf); + } else { + target_check_error(t); + } + #define PROBE(x) \ do { if ((x)(t)) return true; else target_check_error(t); } while (0) @@ -551,6 +590,9 @@ void cortexm_halt_resume(target *t, bool step) cortexm_pc_write(t, pc + 2); } + if (priv->has_cache) + target_mem_write32(t, CORTEXM_ICIALLU, 0); + target_mem_write32(t, CORTEXM_DHCSR, dhcsr); } diff --git a/src/target/cortexm.h b/src/target/cortexm.h index bf1d821d..e9bf5476 100644 --- a/src/target/cortexm.h +++ b/src/target/cortexm.h @@ -37,6 +37,17 @@ #define CORTEXM_DCRDR (CORTEXM_SCS_BASE + 0xDF8) #define CORTEXM_DEMCR (CORTEXM_SCS_BASE + 0xDFC) +/* Cache identification */ +#define CORTEXM_CLIDR (CORTEXM_SCS_BASE + 0xD78) +#define CORTEXM_CTR (CORTEXM_SCS_BASE + 0xD7C) +#define CORTEXM_CCSIDR (CORTEXM_SCS_BASE + 0xD80) +#define CORTEXM_CSSELR (CORTEXM_SCS_BASE + 0xD84) + +/* Cache maintenance operations */ +#define CORTEXM_ICIALLU (CORTEXM_SCS_BASE + 0xF50) +#define CORTEXM_DCCMVAC (CORTEXM_SCS_BASE + 0xF68) +#define CORTEXM_DCCIMVAC (CORTEXM_SCS_BASE + 0xF70) + #define CORTEXM_FPB_BASE (CORTEXM_PPB_BASE + 0x2000) /* ARM Literature uses FP_*, we use CORTEXM_FPB_* consistently */