diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2022-08-28 22:17:46 -0700 |
---|---|---|
committer | Laurent Vivier <laurent@vivier.eu> | 2022-09-21 14:59:45 +0200 |
commit | 5934dae7a747f0aed24e8d20936ca5e117d95ad9 (patch) | |
tree | 6d6d99b7a2d01ca30646db3c65594087ec24e5f3 /target | |
parent | 832e9e33bc51f52fc3ea667d48912e95af3e28f3 (diff) | |
download | qemu-5934dae7a747f0aed24e8d20936ca5e117d95ad9.zip qemu-5934dae7a747f0aed24e8d20936ca5e117d95ad9.tar.gz qemu-5934dae7a747f0aed24e8d20936ca5e117d95ad9.tar.bz2 |
target/m68k: Implement atomic test-and-set
This is slightly more complicated than cas,
because tas is allowed on data registers.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20220829051746.227094-1-richard.henderson@linaro.org>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Diffstat (limited to 'target')
-rw-r--r-- | target/m68k/translate.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 5098f7e..ffcc761 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2825,19 +2825,39 @@ DISAS_INSN(illegal) gen_exception(s, s->base.pc_next, EXCP_ILLEGAL); } -/* ??? This should be atomic. */ DISAS_INSN(tas) { - TCGv dest; - TCGv src1; - TCGv addr; + int mode = extract32(insn, 3, 3); + int reg0 = REG(insn, 0); - dest = tcg_temp_new(); - SRC_EA(env, src1, OS_BYTE, 1, &addr); - gen_logic_cc(s, src1, OS_BYTE); - tcg_gen_ori_i32(dest, src1, 0x80); - DEST_EA(env, insn, OS_BYTE, dest, &addr); - tcg_temp_free(dest); + if (mode == 0) { + /* data register direct */ + TCGv dest = cpu_dregs[reg0]; + gen_logic_cc(s, dest, OS_BYTE); + tcg_gen_ori_tl(dest, dest, 0x80); + } else { + TCGv src1, addr; + + addr = gen_lea_mode(env, s, mode, reg0, OS_BYTE); + if (IS_NULL_QREG(addr)) { + gen_addr_fault(s); + return; + } + src1 = tcg_temp_new(); + tcg_gen_atomic_fetch_or_tl(src1, addr, tcg_constant_tl(0x80), + IS_USER(s), MO_SB); + gen_logic_cc(s, src1, OS_BYTE); + tcg_temp_free(src1); + + switch (mode) { + case 3: /* Indirect postincrement. */ + tcg_gen_addi_i32(AREG(insn, 0), addr, 1); + break; + case 4: /* Indirect predecrememnt. */ + tcg_gen_mov_i32(AREG(insn, 0), addr); + break; + } + } } DISAS_INSN(mull) |