@@ -359,6 +359,9 @@
C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0)
/* LOAD ADDRESS RELATIVE LONG */
C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0)
+/* LOAD AND ADD */
+ C(0xebf8, LAA, RSY_a, ILA, r3_32s, m2_32s_atomic, new, m2_32_r1_atomic, add, adds32)
+ C(0xebe8, LAAG, RSY_a, ILA, r3, m2_64_atomic, new, m2_64_r1_atomic, add, adds64)
/* LOAD AND TEST */
C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32)
C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64)
@@ -1118,6 +1118,7 @@ typedef enum DisasFacility {
FAC_PC, /* population count */
FAC_SCF, /* store clock fast */
FAC_SFLE, /* store facility list extended */
+ FAC_ILA, /* interlocked access facility 1 */
} DisasFacility;
struct DisasInsn {
@@ -1297,6 +1298,12 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
return ret;
}
+static TCGv_i64 get_a2(DisasContext *s, DisasFields *f)
+{
+ int x2 = have_field(f, x2) ? get_field(f, x2) : 0;
+ return get_address(s, x2, get_field(f, b2), get_field(f, d2));
+}
+
/* ====================================================================== */
/* The operations. These perform the bulk of the work for any insn,
usually after the operands have been loaded and output initialized. */
@@ -4065,6 +4072,30 @@ static void wout_m2_32(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_wout_m2_32 0
+static void wout_m2_32_r1_atomic(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ TCGv_i64 a2 = get_a2(s, f);
+
+ /* XXX release reservation */
+ tcg_gen_qemu_st32(o->out, a2, get_mem_index(s));
+ store_reg32_i64(get_field(f, r1), o->in2);
+
+ tcg_temp_free_i64(a2);
+}
+#define SPEC_wout_m2_32_r1_atomic 0
+
+static void wout_m2_64_r1_atomic(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ TCGv_i64 a2 = get_a2(s, f);
+
+ /* XXX release reservation */
+ tcg_gen_qemu_st64(o->out, a2, get_mem_index(s));
+ store_reg(get_field(f, r1), o->in2);
+
+ tcg_temp_free_i64(a2);
+}
+#define SPEC_wout_m2_64_r1_atomic 0
+
/* ====================================================================== */
/* The "INput 1" generators. These load the first operand to an insn. */
@@ -4393,8 +4424,7 @@ static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o)
static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o)
{
- int x2 = have_field(f, x2) ? get_field(f, x2) : 0;
- o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2));
+ o->in2 = get_a2(s, f);
}
#define SPEC_in2_a2 0
@@ -4486,6 +4516,20 @@ static void in2_mri2_64(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_in2_mri2_64 0
+static void in2_m2_32s_atomic(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ /* XXX should reserve the address */
+ in2_m2_32s(s, f, o);
+}
+#define SPEC_in2_m2_32s_atomic 0
+
+static void in2_m2_64_atomic(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ /* XXX should reserve the address */
+ in2_m2_64(s, f, o);
+}
+#define SPEC_in2_m2_64_atomic 0
+
static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_const_i64(get_field(f, i2));
We're currently missing the laa and laag instructions in our emulation. In fact, we're missing the complete "interlocked-access facility 1" which is part of zEC12. However, I really only needed the laa instruction for now. Signed-off-by: Alexander Graf <agraf@suse.de> --- This really should implement all the other atomic load&modify instructions, but I'd like to make sure we have a smart scheme to implement them first. v1 -> v2: - move atomic specific bits into load/store helpers, leave actual op as normal op we can reuse --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 48 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-)