#include "../gte_arm.h"
#include "../gte_neon.h"
#include "compiler_features.h"
+#include "arm_features.h"
#define FLAGLESS
#include "../gte.h"
#ifdef NDRC_THREAD
#ifdef NDRC_THREAD
static void clear_local_cache(void)
{
-#ifdef _3DS
- if (ndrc_g.thread.cache_dirty) {
- ndrc_g.thread.cache_dirty = 0;
- ctr_invalidate_icache();
- }
+#if defined(__arm__) || defined(__aarch64__)
+ if (ndrc_g.thread.dirty_start) {
+ // see "Ensuring the visibility of updates to instructions"
+ // in v7/v8 reference manuals (DDI0406, DDI0487 etc.)
+#if defined(__aarch64__) || defined(HAVE_ARMV8)
+ // the actual clean/invalidate is broadcast to all cores,
+ // the manual only prescribes an isb
+ __asm__ volatile("isb");
+//#elif defined(_3DS)
+// ctr_invalidate_icache();
#else
- // hopefully nothing is needed, as tested on r-pi4 and switch
+ // while on v6 this is always required, on v7 it depends on
+ // "Multiprocessing Extensions" being present, but that is difficult
+ // to detect so do it always for now
+ new_dyna_clear_cache(ndrc_g.thread.dirty_start, ndrc_g.thread.dirty_end);
+#endif
+ ndrc_g.thread.dirty_start = ndrc_g.thread.dirty_end = 0;
+ }
#endif
}
#endif
}
-static void start_tcache_write(void *start, void *end)
-{
- mprotect_w_x(start, end, 0);
-}
-
-static void end_tcache_write(void *start, void *end)
+void new_dyna_clear_cache(void *start, void *end)
{
#if defined(__arm__) || defined(__aarch64__)
size_t len = (char *)end - (char *)start;
ctr_clear_cache_range(start, end);
else
ctr_clear_cache();
- ndrc_g.thread.cache_dirty = 1;
#elif defined(HAVE_LIBNX)
if (g_jit.type == JitType_CodeMemory) {
armDCacheClean(start, len);
#endif
(void)len;
#endif
+}
+
+static void start_tcache_write(void *start, void *end)
+{
+ mprotect_w_x(start, end, 0);
+}
+
+static void end_tcache_write(void *start, void *end)
+{
+#ifdef NDRC_THREAD
+ if (!ndrc_g.thread.dirty_start || (size_t)ndrc_g.thread.dirty_start > (size_t)start)
+ ndrc_g.thread.dirty_start = start;
+ if ((size_t)ndrc_g.thread.dirty_end < (size_t)end)
+ ndrc_g.thread.dirty_end = end;
+#endif
+ new_dyna_clear_cache(start, end);
mprotect_w_x(start, end, 1);
}
void *handle;
void *lock;
void *cond;
+ void *dirty_start;
+ void *dirty_end;
unsigned int addr;
int busy;
int exit;
- int cache_dirty; // 3ds only
} thread;
};
extern struct ndrc_globals ndrc_g;
int new_dynarec_quick_check_range(unsigned int start, unsigned int end);
void new_dynarec_invalidate_range(unsigned int start, unsigned int end);
void new_dynarec_invalidate_all_pages(void);
+void new_dyna_clear_cache(void *start, void *end);
void new_dyna_start(void *context);
void new_dyna_start_at(void *context, void *compiled_code);