summaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
authorRichard Henderson2022-08-29 07:17:46 +0200
committerLaurent Vivier2022-09-21 14:59:45 +0200
commit5934dae7a747f0aed24e8d20936ca5e117d95ad9 (patch)
tree6d6d99b7a2d01ca30646db3c65594087ec24e5f3 /target
parentMerge tag 'pull-loongarch-20220920' of https://gitlab.com/gaosong/qemu into s... (diff)
downloadqemu-5934dae7a747f0aed24e8d20936ca5e117d95ad9.tar.gz
qemu-5934dae7a747f0aed24e8d20936ca5e117d95ad9.tar.xz
qemu-5934dae7a747f0aed24e8d20936ca5e117d95ad9.zip
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.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 5098f7e570..ffcc761d60 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)