mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-23 06:25:12 +00:00
target/arm: [tcg] Port to tb_start
Incrementally paves the way towards using the generic instruction translation loop. Backports commit b14768544fd715a3f1742c10fc36ae81c703cbc1 from qemu
This commit is contained in:
parent
529c6c17f1
commit
b3878f117e
|
@ -12102,6 +12102,50 @@ static int arm_tr_init_disas_context(DisasContextBase *dcbase,
|
|||
return max_insns;
|
||||
}
|
||||
|
||||
static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
TCGContext *tcg_ctx = cpu->uc->tcg_ctx;
|
||||
|
||||
/* A note on handling of the condexec (IT) bits:
|
||||
*
|
||||
* We want to avoid the overhead of having to write the updated condexec
|
||||
* bits back to the CPUARMState for every instruction in an IT block. So:
|
||||
* (1) if the condexec bits are not already zero then we write
|
||||
* zero back into the CPUARMState now. This avoids complications trying
|
||||
* to do it at the end of the block. (For example if we don't do this
|
||||
* it's hard to identify whether we can safely skip writing condexec
|
||||
* at the end of the TB, which we definitely want to do for the case
|
||||
* where a TB doesn't do anything with the IT state at all.)
|
||||
* (2) if we are going to leave the TB then we call gen_set_condexec()
|
||||
* which will write the correct value into CPUARMState if zero is wrong.
|
||||
* This is done both for leaving the TB at the end, and for leaving
|
||||
* it because of an exception we know will happen, which is done in
|
||||
* gen_exception_insn(). The latter is necessary because we need to
|
||||
* leave the TB with the PC/IT state just prior to execution of the
|
||||
* instruction which caused the exception.
|
||||
* (3) if we leave the TB unexpectedly (eg a data abort on a load)
|
||||
* then the CPUARMState will be wrong and we need to reset it.
|
||||
* This is handled in the same way as restoration of the
|
||||
* PC in these situations; we save the value of the condexec bits
|
||||
* for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
|
||||
* then uses this to restore them after an exception.
|
||||
*
|
||||
* Note that there are no instructions which can read the condexec
|
||||
* bits, and none which can write non-static values to them, so
|
||||
* we don't need to care about whether CPUARMState is correct in the
|
||||
* middle of a TB.
|
||||
*/
|
||||
|
||||
/* Reset the conditional execution bits immediately. This avoids
|
||||
complications trying to do it at the end of the block. */
|
||||
if (dc->condexec_mask || dc->condexec_cond) {
|
||||
TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_movi_i32(tcg_ctx, tmp, 0);
|
||||
store_cpu_field(tcg_ctx, tmp, condexec_bits);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
||||
{
|
||||
|
@ -12163,45 +12207,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
}
|
||||
|
||||
gen_tb_start(tcg_ctx, tb);
|
||||
arm_tr_tb_start(&dc->base, cs);
|
||||
|
||||
/* A note on handling of the condexec (IT) bits:
|
||||
*
|
||||
* We want to avoid the overhead of having to write the updated condexec
|
||||
* bits back to the CPUARMState for every instruction in an IT block. So:
|
||||
* (1) if the condexec bits are not already zero then we write
|
||||
* zero back into the CPUARMState now. This avoids complications trying
|
||||
* to do it at the end of the block. (For example if we don't do this
|
||||
* it's hard to identify whether we can safely skip writing condexec
|
||||
* at the end of the TB, which we definitely want to do for the case
|
||||
* where a TB doesn't do anything with the IT state at all.)
|
||||
* (2) if we are going to leave the TB then we call gen_set_condexec()
|
||||
* which will write the correct value into CPUARMState if zero is wrong.
|
||||
* This is done both for leaving the TB at the end, and for leaving
|
||||
* it because of an exception we know will happen, which is done in
|
||||
* gen_exception_insn(). The latter is necessary because we need to
|
||||
* leave the TB with the PC/IT state just prior to execution of the
|
||||
* instruction which caused the exception.
|
||||
* (3) if we leave the TB unexpectedly (eg a data abort on a load)
|
||||
* then the CPUARMState will be wrong and we need to reset it.
|
||||
* This is handled in the same way as restoration of the
|
||||
* PC in these situations; we save the value of the condexec bits
|
||||
* for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
|
||||
* then uses this to restore them after an exception.
|
||||
*
|
||||
* Note that there are no instructions which can read the condexec
|
||||
* bits, and none which can write non-static values to them, so
|
||||
* we don't need to care about whether CPUARMState is correct in the
|
||||
* middle of a TB.
|
||||
*/
|
||||
|
||||
/* Reset the conditional execution bits immediately. This avoids
|
||||
complications trying to do it at the end of the block. */
|
||||
if (dc->condexec_mask || dc->condexec_cond)
|
||||
{
|
||||
TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_movi_i32(tcg_ctx, tmp, 0);
|
||||
store_cpu_field(tcg_ctx, tmp, condexec_bits);
|
||||
}
|
||||
do {
|
||||
dc->base.num_insns++;
|
||||
dc->insn_start_idx = tcg_op_buf_count(tcg_ctx);
|
||||
|
|
Loading…
Reference in a new issue