Revision 852d481f target-sh4/translate.c
b/target-sh4/translate.c | ||
---|---|---|
50 | 50 |
uint32_t delayed_pc; |
51 | 51 |
int singlestep_enabled; |
52 | 52 |
uint32_t features; |
53 |
int has_movcal; |
|
53 | 54 |
} DisasContext; |
54 | 55 |
|
55 | 56 |
#if defined(CONFIG_USER_ONLY) |
... | ... | |
283 | 284 |
env = qemu_mallocz(sizeof(CPUSH4State)); |
284 | 285 |
env->features = def->features; |
285 | 286 |
cpu_exec_init(env); |
287 |
env->movcal_backup_tail = &(env->movcal_backup); |
|
286 | 288 |
sh4_translate_init(); |
287 | 289 |
env->cpu_model_str = cpu_model; |
288 | 290 |
cpu_sh4_reset(env); |
... | ... | |
495 | 497 |
|
496 | 498 |
static void _decode_opc(DisasContext * ctx) |
497 | 499 |
{ |
500 |
/* This code tries to make movcal emulation sufficiently |
|
501 |
accurate for Linux purposes. This instruction writes |
|
502 |
memory, and prior to that, always allocates a cache line. |
|
503 |
It is used in two contexts: |
|
504 |
- in memcpy, where data is copied in blocks, the first write |
|
505 |
of to a block uses movca.l for performance. |
|
506 |
- in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used |
|
507 |
to flush the cache. Here, the data written by movcal.l is never |
|
508 |
written to memory, and the data written is just bogus. |
|
509 |
|
|
510 |
To simulate this, we simulate movcal.l, we store the value to memory, |
|
511 |
but we also remember the previous content. If we see ocbi, we check |
|
512 |
if movcal.l for that address was done previously. If so, the write should |
|
513 |
not have hit the memory, so we restore the previous content. |
|
514 |
When we see an instruction that is neither movca.l |
|
515 |
nor ocbi, the previous content is discarded. |
|
516 |
|
|
517 |
To optimize, we only try to flush stores when we're at the start of |
|
518 |
TB, or if we already saw movca.l in this TB and did not flush stores |
|
519 |
yet. */ |
|
520 |
if (ctx->has_movcal) |
|
521 |
{ |
|
522 |
int opcode = ctx->opcode & 0xf0ff; |
|
523 |
if (opcode != 0x0093 /* ocbi */ |
|
524 |
&& opcode != 0x00c3 /* movca.l */) |
|
525 |
{ |
|
526 |
gen_helper_discard_movcal_backup (); |
|
527 |
ctx->has_movcal = 0; |
|
528 |
} |
|
529 |
} |
|
530 |
|
|
498 | 531 |
#if 0 |
499 | 532 |
fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); |
500 | 533 |
#endif |
... | ... | |
1545 | 1578 |
} |
1546 | 1579 |
return; |
1547 | 1580 |
case 0x00c3: /* movca.l R0,@Rm */ |
1548 |
tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); |
|
1581 |
{ |
|
1582 |
TCGv val = tcg_temp_new(); |
|
1583 |
tcg_gen_qemu_ld32u(val, REG(B11_8), ctx->memidx); |
|
1584 |
gen_helper_movcal (REG(B11_8), val); |
|
1585 |
tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); |
|
1586 |
} |
|
1587 |
ctx->has_movcal = 1; |
|
1549 | 1588 |
return; |
1550 | 1589 |
case 0x40a9: |
1551 | 1590 |
/* MOVUA.L @Rm,R0 (Rm) -> R0 |
... | ... | |
1594 | 1633 |
break; |
1595 | 1634 |
case 0x0093: /* ocbi @Rn */ |
1596 | 1635 |
{ |
1597 |
TCGv dummy = tcg_temp_new(); |
|
1598 |
tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx); |
|
1599 |
tcg_temp_free(dummy); |
|
1636 |
gen_helper_ocbi (REG(B11_8)); |
|
1600 | 1637 |
} |
1601 | 1638 |
return; |
1602 | 1639 |
case 0x00a3: /* ocbp @Rn */ |
... | ... | |
1876 | 1913 |
ctx.tb = tb; |
1877 | 1914 |
ctx.singlestep_enabled = env->singlestep_enabled; |
1878 | 1915 |
ctx.features = env->features; |
1916 |
ctx.has_movcal = (tb->flags & TB_FLAG_PENDING_MOVCA); |
|
1879 | 1917 |
|
1880 | 1918 |
#ifdef DEBUG_DISAS |
1881 | 1919 |
qemu_log_mask(CPU_LOG_TB_CPU, |
Also available in: Unified diff