Commit dfbc799d8e94d26ab2e6ad4a65dc97fd8fb6ece6

Authored by aurel32
1 parent 37d269df

target-ppc: convert load/store string instructions to TCG

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5828 c046a42c-6fe2-441c-8c8c-71466251a162
target-ppc/helper.h
@@ -9,6 +9,9 @@ DEF_HELPER_3(td, void, tl, tl, i32) @@ -9,6 +9,9 @@ DEF_HELPER_3(td, void, tl, tl, i32)
9 9
10 DEF_HELPER_2(lmw, void, tl, i32) 10 DEF_HELPER_2(lmw, void, tl, i32)
11 DEF_HELPER_2(stmw, void, tl, i32) 11 DEF_HELPER_2(stmw, void, tl, i32)
  12 +DEF_HELPER_3(lsw, void, tl, i32, i32)
  13 +DEF_HELPER_4(lswx, void, tl, i32, i32, i32)
  14 +DEF_HELPER_3(stsw, void, tl, i32, i32)
12 DEF_HELPER_1(dcbz, void, tl) 15 DEF_HELPER_1(dcbz, void, tl)
13 DEF_HELPER_1(dcbz_970, void, tl) 16 DEF_HELPER_1(dcbz_970, void, tl)
14 DEF_HELPER_1(icbi, void, tl) 17 DEF_HELPER_1(icbi, void, tl)
target-ppc/op_helper.c
@@ -170,6 +170,99 @@ void helper_stmw (target_ulong addr, uint32_t reg) @@ -170,6 +170,99 @@ void helper_stmw (target_ulong addr, uint32_t reg)
170 } 170 }
171 } 171 }
172 172
  173 +void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
  174 +{
  175 + int sh;
  176 +#ifdef CONFIG_USER_ONLY
  177 +#define ldfunl ldl_raw
  178 +#define ldfunb ldub_raw
  179 +#else
  180 + int (*ldfunl)(target_ulong);
  181 + int (*ldfunb)(target_ulong);
  182 +
  183 + switch (env->mmu_idx) {
  184 + default:
  185 + case 0:
  186 + ldfunl = ldl_user;
  187 + ldfunb = ldub_user;
  188 + break;
  189 + case 1:
  190 + ldfunl = ldl_kernel;
  191 + ldfunb = ldub_kernel;
  192 + break;
  193 + case 2:
  194 + ldfunl = ldl_hypv;
  195 + ldfunb = ldub_hypv;
  196 + break;
  197 + }
  198 +#endif
  199 + for (; nb > 3; nb -= 4, addr += 4) {
  200 + env->gpr[reg] = ldfunl(get_addr(addr));
  201 + reg = (reg + 1) % 32;
  202 + }
  203 + if (unlikely(nb > 0)) {
  204 + env->gpr[reg] = 0;
  205 + for (sh = 24; nb > 0; nb--, addr++, sh -= 8) {
  206 + env->gpr[reg] |= ldfunb(get_addr(addr)) << sh;
  207 + }
  208 + }
  209 +}
  210 +/* PPC32 specification says we must generate an exception if
  211 + * rA is in the range of registers to be loaded.
  212 + * In an other hand, IBM says this is valid, but rA won't be loaded.
  213 + * For now, I'll follow the spec...
  214 + */
  215 +void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
  216 +{
  217 + if (likely(xer_bc != 0)) {
  218 + if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
  219 + (reg < rb && (reg + xer_bc) > rb))) {
  220 + raise_exception_err(env, POWERPC_EXCP_PROGRAM,
  221 + POWERPC_EXCP_INVAL |
  222 + POWERPC_EXCP_INVAL_LSWX);
  223 + } else {
  224 + helper_lsw(addr, xer_bc, reg);
  225 + }
  226 + }
  227 +}
  228 +
  229 +void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
  230 +{
  231 + int sh;
  232 +#ifdef CONFIG_USER_ONLY
  233 +#define stfunl stl_raw
  234 +#define stfunb stb_raw
  235 +#else
  236 + void (*stfunl)(target_ulong, int);
  237 + void (*stfunb)(target_ulong, int);
  238 +
  239 + switch (env->mmu_idx) {
  240 + default:
  241 + case 0:
  242 + stfunl = stl_user;
  243 + stfunb = stb_user;
  244 + break;
  245 + case 1:
  246 + stfunl = stl_kernel;
  247 + stfunb = stb_kernel;
  248 + break;
  249 + case 2:
  250 + stfunl = stl_hypv;
  251 + stfunb = stb_hypv;
  252 + break;
  253 + }
  254 +#endif
  255 +
  256 + for (; nb > 3; nb -= 4, addr += 4) {
  257 + stfunl(get_addr(addr), env->gpr[reg]);
  258 + reg = (reg + 1) % 32;
  259 + }
  260 + if (unlikely(nb > 0)) {
  261 + for (sh = 24; nb > 0; nb--, addr++, sh -= 8)
  262 + stfunb(get_addr(addr), (env->gpr[reg] >> sh) & 0xFF);
  263 + }
  264 +}
  265 +
173 static void do_dcbz(target_ulong addr, int dcache_line_size) 266 static void do_dcbz(target_ulong addr, int dcache_line_size)
174 { 267 {
175 target_long mask = get_addr(~(dcache_line_size - 1)); 268 target_long mask = get_addr(~(dcache_line_size - 1));
target-ppc/op_helper.h
@@ -21,19 +21,12 @@ @@ -21,19 +21,12 @@
21 #if defined(MEMSUFFIX) 21 #if defined(MEMSUFFIX)
22 22
23 /* Memory load/store helpers */ 23 /* Memory load/store helpers */
24 -void glue(do_lsw, MEMSUFFIX) (int dst);  
25 -void glue(do_stsw, MEMSUFFIX) (int src);  
26 void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb); 24 void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb);
27 void glue(do_POWER2_lfq, MEMSUFFIX) (void); 25 void glue(do_POWER2_lfq, MEMSUFFIX) (void);
28 void glue(do_POWER2_lfq_le, MEMSUFFIX) (void); 26 void glue(do_POWER2_lfq_le, MEMSUFFIX) (void);
29 void glue(do_POWER2_stfq, MEMSUFFIX) (void); 27 void glue(do_POWER2_stfq, MEMSUFFIX) (void);
30 void glue(do_POWER2_stfq_le, MEMSUFFIX) (void); 28 void glue(do_POWER2_stfq_le, MEMSUFFIX) (void);
31 29
32 -#if defined(TARGET_PPC64)  
33 -void glue(do_lsw_64, MEMSUFFIX) (int dst);  
34 -void glue(do_stsw_64, MEMSUFFIX) (int src);  
35 -#endif  
36 -  
37 #else 30 #else
38 31
39 void do_print_mem_EA (target_ulong EA); 32 void do_print_mem_EA (target_ulong EA);
target-ppc/op_helper_mem.h
@@ -20,78 +20,6 @@ @@ -20,78 +20,6 @@
20 20
21 #include "op_mem_access.h" 21 #include "op_mem_access.h"
22 22
23 -void glue(do_lsw, MEMSUFFIX) (int dst)  
24 -{  
25 - uint32_t tmp;  
26 - int sh;  
27 -  
28 - for (; T1 > 3; T1 -= 4, T0 += 4) {  
29 - env->gpr[dst++] = glue(ldu32, MEMSUFFIX)((uint32_t)T0);  
30 - if (unlikely(dst == 32))  
31 - dst = 0;  
32 - }  
33 - if (unlikely(T1 != 0)) {  
34 - tmp = 0;  
35 - for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {  
36 - tmp |= glue(ldu8, MEMSUFFIX)((uint32_t)T0) << sh;  
37 - }  
38 - env->gpr[dst] = tmp;  
39 - }  
40 -}  
41 -  
42 -#if defined(TARGET_PPC64)  
43 -void glue(do_lsw_64, MEMSUFFIX) (int dst)  
44 -{  
45 - uint32_t tmp;  
46 - int sh;  
47 -  
48 - for (; T1 > 3; T1 -= 4, T0 += 4) {  
49 - env->gpr[dst++] = glue(ldu32, MEMSUFFIX)((uint64_t)T0);  
50 - if (unlikely(dst == 32))  
51 - dst = 0;  
52 - }  
53 - if (unlikely(T1 != 0)) {  
54 - tmp = 0;  
55 - for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {  
56 - tmp |= glue(ldu8, MEMSUFFIX)((uint64_t)T0) << sh;  
57 - }  
58 - env->gpr[dst] = tmp;  
59 - }  
60 -}  
61 -#endif  
62 -  
63 -void glue(do_stsw, MEMSUFFIX) (int src)  
64 -{  
65 - int sh;  
66 -  
67 - for (; T1 > 3; T1 -= 4, T0 += 4) {  
68 - glue(st32, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]);  
69 - if (unlikely(src == 32))  
70 - src = 0;  
71 - }  
72 - if (unlikely(T1 != 0)) {  
73 - for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)  
74 - glue(st8, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF);  
75 - }  
76 -}  
77 -  
78 -#if defined(TARGET_PPC64)  
79 -void glue(do_stsw_64, MEMSUFFIX) (int src)  
80 -{  
81 - int sh;  
82 -  
83 - for (; T1 > 3; T1 -= 4, T0 += 4) {  
84 - glue(st32, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]);  
85 - if (unlikely(src == 32))  
86 - src = 0;  
87 - }  
88 - if (unlikely(T1 != 0)) {  
89 - for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)  
90 - glue(st8, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF);  
91 - }  
92 -}  
93 -#endif  
94 -  
95 /* PowerPC 601 specific instructions (POWER bridge) */ 23 /* PowerPC 601 specific instructions (POWER bridge) */
96 // XXX: to be tested 24 // XXX: to be tested
97 void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) 25 void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb)
target-ppc/op_mem.h
@@ -20,74 +20,6 @@ @@ -20,74 +20,6 @@
20 20
21 #include "op_mem_access.h" 21 #include "op_mem_access.h"
22 22
23 -/*** Integer load and store strings ***/  
24 -void OPPROTO glue(op_lswi, MEMSUFFIX) (void)  
25 -{  
26 - glue(do_lsw, MEMSUFFIX)(PARAM1);  
27 - RETURN();  
28 -}  
29 -  
30 -#if defined(TARGET_PPC64)  
31 -void OPPROTO glue(op_lswi_64, MEMSUFFIX) (void)  
32 -{  
33 - glue(do_lsw_64, MEMSUFFIX)(PARAM1);  
34 - RETURN();  
35 -}  
36 -#endif  
37 -  
38 -/* PPC32 specification says we must generate an exception if  
39 - * rA is in the range of registers to be loaded.  
40 - * In an other hand, IBM says this is valid, but rA won't be loaded.  
41 - * For now, I'll follow the spec...  
42 - */  
43 -void OPPROTO glue(op_lswx, MEMSUFFIX) (void)  
44 -{  
45 - /* Note: T1 comes from xer_bc then no cast is needed */  
46 - if (likely(T1 != 0)) {  
47 - if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||  
48 - (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {  
49 - raise_exception_err(env, POWERPC_EXCP_PROGRAM,  
50 - POWERPC_EXCP_INVAL |  
51 - POWERPC_EXCP_INVAL_LSWX);  
52 - } else {  
53 - glue(do_lsw, MEMSUFFIX)(PARAM1);  
54 - }  
55 - }  
56 - RETURN();  
57 -}  
58 -  
59 -#if defined(TARGET_PPC64)  
60 -void OPPROTO glue(op_lswx_64, MEMSUFFIX) (void)  
61 -{  
62 - /* Note: T1 comes from xer_bc then no cast is needed */  
63 - if (likely(T1 != 0)) {  
64 - if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||  
65 - (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {  
66 - raise_exception_err(env, POWERPC_EXCP_PROGRAM,  
67 - POWERPC_EXCP_INVAL |  
68 - POWERPC_EXCP_INVAL_LSWX);  
69 - } else {  
70 - glue(do_lsw_64, MEMSUFFIX)(PARAM1);  
71 - }  
72 - }  
73 - RETURN();  
74 -}  
75 -#endif  
76 -  
77 -void OPPROTO glue(op_stsw, MEMSUFFIX) (void)  
78 -{  
79 - glue(do_stsw, MEMSUFFIX)(PARAM1);  
80 - RETURN();  
81 -}  
82 -  
83 -#if defined(TARGET_PPC64)  
84 -void OPPROTO glue(op_stsw_64, MEMSUFFIX) (void)  
85 -{  
86 - glue(do_stsw_64, MEMSUFFIX)(PARAM1);  
87 - RETURN();  
88 -}  
89 -#endif  
90 -  
91 /* Load and set reservation */ 23 /* Load and set reservation */
92 void OPPROTO glue(op_lwarx, MEMSUFFIX) (void) 24 void OPPROTO glue(op_lwarx, MEMSUFFIX) (void)
93 { 25 {
target-ppc/translate.c
@@ -3118,43 +3118,6 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -3118,43 +3118,6 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
3118 } 3118 }
3119 3119
3120 /*** Integer load and store strings ***/ 3120 /*** Integer load and store strings ***/
3121 -#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)  
3122 -#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)  
3123 -/* string load & stores are by definition endian-safe */  
3124 -#define gen_op_lswi_le_raw gen_op_lswi_raw  
3125 -#define gen_op_lswi_le_user gen_op_lswi_user  
3126 -#define gen_op_lswi_le_kernel gen_op_lswi_kernel  
3127 -#define gen_op_lswi_le_hypv gen_op_lswi_hypv  
3128 -#define gen_op_lswi_le_64_raw gen_op_lswi_raw  
3129 -#define gen_op_lswi_le_64_user gen_op_lswi_user  
3130 -#define gen_op_lswi_le_64_kernel gen_op_lswi_kernel  
3131 -#define gen_op_lswi_le_64_hypv gen_op_lswi_hypv  
3132 -static GenOpFunc1 *gen_op_lswi[NB_MEM_FUNCS] = {  
3133 - GEN_MEM_FUNCS(lswi),  
3134 -};  
3135 -#define gen_op_lswx_le_raw gen_op_lswx_raw  
3136 -#define gen_op_lswx_le_user gen_op_lswx_user  
3137 -#define gen_op_lswx_le_kernel gen_op_lswx_kernel  
3138 -#define gen_op_lswx_le_hypv gen_op_lswx_hypv  
3139 -#define gen_op_lswx_le_64_raw gen_op_lswx_raw  
3140 -#define gen_op_lswx_le_64_user gen_op_lswx_user  
3141 -#define gen_op_lswx_le_64_kernel gen_op_lswx_kernel  
3142 -#define gen_op_lswx_le_64_hypv gen_op_lswx_hypv  
3143 -static GenOpFunc3 *gen_op_lswx[NB_MEM_FUNCS] = {  
3144 - GEN_MEM_FUNCS(lswx),  
3145 -};  
3146 -#define gen_op_stsw_le_raw gen_op_stsw_raw  
3147 -#define gen_op_stsw_le_user gen_op_stsw_user  
3148 -#define gen_op_stsw_le_kernel gen_op_stsw_kernel  
3149 -#define gen_op_stsw_le_hypv gen_op_stsw_hypv  
3150 -#define gen_op_stsw_le_64_raw gen_op_stsw_raw  
3151 -#define gen_op_stsw_le_64_user gen_op_stsw_user  
3152 -#define gen_op_stsw_le_64_kernel gen_op_stsw_kernel  
3153 -#define gen_op_stsw_le_64_hypv gen_op_stsw_hypv  
3154 -static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = {  
3155 - GEN_MEM_FUNCS(stsw),  
3156 -};  
3157 -  
3158 /* lswi */ 3121 /* lswi */
3159 /* PowerPC32 specification says we must generate an exception if 3122 /* PowerPC32 specification says we must generate an exception if
3160 * rA is in the range of registers to be loaded. 3123 * rA is in the range of registers to be loaded.
@@ -3163,6 +3126,8 @@ static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = { @@ -3163,6 +3126,8 @@ static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = {
3163 */ 3126 */
3164 GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING) 3127 GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING)
3165 { 3128 {
  3129 + TCGv t0;
  3130 + TCGv_i32 t1, t2;
3166 int nb = NB(ctx->opcode); 3131 int nb = NB(ctx->opcode);
3167 int start = rD(ctx->opcode); 3132 int start = rD(ctx->opcode);
3168 int ra = rA(ctx->opcode); 3133 int ra = rA(ctx->opcode);
@@ -3180,49 +3145,67 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING) @@ -3180,49 +3145,67 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING)
3180 } 3145 }
3181 /* NIP cannot be restored if the memory exception comes from an helper */ 3146 /* NIP cannot be restored if the memory exception comes from an helper */
3182 gen_update_nip(ctx, ctx->nip - 4); 3147 gen_update_nip(ctx, ctx->nip - 4);
3183 - gen_addr_register(cpu_T[0], ctx);  
3184 - tcg_gen_movi_tl(cpu_T[1], nb);  
3185 - op_ldsts(lswi, start); 3148 + t0 = tcg_temp_new();
  3149 + gen_addr_register(t0, ctx);
  3150 + t1 = tcg_const_i32(nb);
  3151 + t2 = tcg_const_i32(start);
  3152 + gen_helper_lsw(t0, t1, t2);
  3153 + tcg_temp_free(t0);
  3154 + tcg_temp_free_i32(t1);
  3155 + tcg_temp_free_i32(t2);
3186 } 3156 }
3187 3157
3188 /* lswx */ 3158 /* lswx */
3189 GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING) 3159 GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING)
3190 { 3160 {
3191 - int ra = rA(ctx->opcode);  
3192 - int rb = rB(ctx->opcode);  
3193 - 3161 + TCGv t0 = tcg_temp_new();
  3162 + TCGv_i32 t1 = tcg_const_i32(rD(ctx->opcode));
  3163 + TCGv_i32 t2 = tcg_const_i32(rA(ctx->opcode));
  3164 + TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
3194 /* NIP cannot be restored if the memory exception comes from an helper */ 3165 /* NIP cannot be restored if the memory exception comes from an helper */
3195 gen_update_nip(ctx, ctx->nip - 4); 3166 gen_update_nip(ctx, ctx->nip - 4);
3196 - gen_addr_reg_index(cpu_T[0], ctx);  
3197 - if (ra == 0) {  
3198 - ra = rb;  
3199 - }  
3200 - tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F);  
3201 - op_ldstsx(lswx, rD(ctx->opcode), ra, rb); 3167 + gen_addr_reg_index(t0, ctx);
  3168 + gen_helper_lswx(t0, t1, t2, t3);
  3169 + tcg_temp_free(t0);
  3170 + tcg_temp_free_i32(t1);
  3171 + tcg_temp_free_i32(t2);
  3172 + tcg_temp_free_i32(t3);
3202 } 3173 }
3203 3174
3204 /* stswi */ 3175 /* stswi */
3205 GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING) 3176 GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING)
3206 { 3177 {
3207 int nb = NB(ctx->opcode); 3178 int nb = NB(ctx->opcode);
3208 - 3179 + TCGv t0 = tcg_temp_new();
  3180 + TCGv_i32 t1;
  3181 + TCGv_i32 t2 = tcg_const_i32(rS(ctx->opcode));
3209 /* NIP cannot be restored if the memory exception comes from an helper */ 3182 /* NIP cannot be restored if the memory exception comes from an helper */
3210 gen_update_nip(ctx, ctx->nip - 4); 3183 gen_update_nip(ctx, ctx->nip - 4);
3211 - gen_addr_register(cpu_T[0], ctx); 3184 + gen_addr_register(t0, ctx);
3212 if (nb == 0) 3185 if (nb == 0)
3213 nb = 32; 3186 nb = 32;
3214 - tcg_gen_movi_tl(cpu_T[1], nb);  
3215 - op_ldsts(stsw, rS(ctx->opcode)); 3187 + t1 = tcg_const_i32(nb);
  3188 + gen_helper_stsw(t0, t1, t2);
  3189 + tcg_temp_free(t0);
  3190 + tcg_temp_free_i32(t1);
  3191 + tcg_temp_free_i32(t2);
3216 } 3192 }
3217 3193
3218 /* stswx */ 3194 /* stswx */
3219 GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING) 3195 GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING)
3220 { 3196 {
  3197 + TCGv t0 = tcg_temp_new();
  3198 + TCGv_i32 t1 = tcg_temp_new_i32();
  3199 + TCGv_i32 t2 = tcg_const_i32(rS(ctx->opcode));
3221 /* NIP cannot be restored if the memory exception comes from an helper */ 3200 /* NIP cannot be restored if the memory exception comes from an helper */
3222 gen_update_nip(ctx, ctx->nip - 4); 3201 gen_update_nip(ctx, ctx->nip - 4);
3223 - gen_addr_reg_index(cpu_T[0], ctx);  
3224 - tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F);  
3225 - op_ldsts(stsw, rS(ctx->opcode)); 3202 + gen_addr_reg_index(t0, ctx);
  3203 + tcg_gen_trunc_tl_i32(t1, cpu_xer);
  3204 + tcg_gen_andi_i32(t1, t1, 0x7F);
  3205 + gen_helper_stsw(t0, t1, t2);
  3206 + tcg_temp_free(t0);
  3207 + tcg_temp_free_i32(t1);
  3208 + tcg_temp_free_i32(t2);
3226 } 3209 }
3227 3210
3228 /*** Memory synchronisation ***/ 3211 /*** Memory synchronisation ***/