From c21eaa57a40ed22f10087a1019dd456d99e3fb03 Mon Sep 17 00:00:00 2001
From: David Miller <dmiller423@gmail.com>
Date: Tue, 8 Feb 2022 22:33:48 -0500
Subject: [PATCH] s390x/tcg: Implement Miscellaneous-Instruction-Extensions
Facility 3 for the s390x
Signed-off-by: David Miller <dmiller423@gmail.com>
---
target/s390x/helper.h | 1 +
target/s390x/tcg/insn-data.def | 26 +++++++++++++++++
target/s390x/tcg/mem_helper.c | 42 ++++++++++++++++++++++++++
target/s390x/tcg/translate.c | 49 +++++++++++++++++++++++++++++++
tests/tcg/s390x/Makefile.target | 2 +-
tests/tcg/s390x/mie3-compl.c | 52 +++++++++++++++++++++++++++++++++
tests/tcg/s390x/mie3-mvcrl.c | 31 ++++++++++++++++++++
tests/tcg/s390x/mie3-sel.c | 42 ++++++++++++++++++++++++++
8 files changed, 244 insertions(+), 1 deletion(-)
create mode 100644 tests/tcg/s390x/mie3-compl.c
create mode 100644 tests/tcg/s390x/mie3-mvcrl.c
create mode 100644 tests/tcg/s390x/mie3-sel.c
diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 271b081e8c..69f69cf718 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -4,6 +4,7 @@ DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64)
+DEF_HELPER_FLAGS_4(mvcrl, TCG_CALL_NO_WG, void, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(mvcin, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_3(mvcl, i32, env, i32, i32)
diff --git a/target/s390x/tcg/insn-data.def b/target/s390x/tcg/insn-data.def
index 1c3e115712..5678c94b09 100644
--- a/target/s390x/tcg/insn-data.def
+++ b/target/s390x/tcg/insn-data.def
@@ -105,6 +105,9 @@
D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000)
D(0x9400, NI, SI, Z, la1, i2_8u, new, 0, ni, nz64, MO_UB)
D(0xeb54, NIY, SIY, LD, la1, i2_8u, new, 0, ni, nz64, MO_UB)
+/* AND WITH COMPLEMENT */
+ C(0xb9f5, NCRK, RRF_a, MIE3, r2, r3, new, r1_32, andc, nz32)
+ C(0xb9e5, NCGRK, RRF_a, MIE3, r2, r3, r1, 0, andc, nz64)
/* BRANCH AND LINK */
C(0x0500, BALR, RR_a, Z, 0, r2_nz, r1, 0, bal, 0)
@@ -640,6 +643,8 @@
C(0xeb8e, MVCLU, RSY_a, E2, 0, a2, 0, 0, mvclu, 0)
/* MOVE NUMERICS */
C(0xd100, MVN, SS_a, Z, la1, a2, 0, 0, mvn, 0)
+/* MOVE RIGHT TO LEFT */
+ C(0xe50a, MVCRL, SSE, MIE3, la1, a2, 0, 0, mvcrl, 0)
/* MOVE PAGE */
C(0xb254, MVPG, RRE, Z, 0, 0, 0, 0, mvpg, 0)
/* MOVE STRING */
@@ -725,6 +730,21 @@
D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000)
D(0x9600, OI, SI, Z, la1, i2_8u, new, 0, oi, nz64, MO_UB)
D(0xeb56, OIY, SIY, LD, la1, i2_8u, new, 0, oi, nz64, MO_UB)
+/* OR WITH COMPLEMENT */
+ C(0xb975, OCRK, RRF_a, MIE3, r2, r3, new, r1_32, orc, nz32)
+ C(0xb965, OCGRK, RRF_a, MIE3, r2, r3, r1, 0, orc, nz64)
+
+/* NAND */
+ C(0xb974, NNRK, RRF_a, MIE3, r2, r3, new, r1_32, nand, nz32)
+ C(0xb964, NNGRK, RRF_a, MIE3, r2, r3, r1, 0, nand, nz64)
+
+/* NOR */
+ C(0xb976, NORK, RRF_a, MIE3, r2, r3, new, r1_32, nor, nz32)
+ C(0xb966, NOGRK, RRF_a, MIE3, r2, r3, r1, 0, nor, nz64)
+
+/* NOT EXCLUSIVE OR */
+ C(0xb977, NXRK, RRF_a, MIE3, r2, r3, new, r1_32, nxor, nz32)
+ C(0xb967, NXGRK, RRF_a, MIE3, r2, r3, r1, 0, nxor, nz64)
/* PACK */
/* Really format SS_b, but we pack both lengths into one argument
@@ -765,6 +785,12 @@
/* SEARCH STRING UNICODE */
C(0xb9be, SRSTU, RRE, ETF3, 0, 0, 0, 0, srstu, 0)
+/* SELECT */
+ C(0xb9f0, SELR, RRF_a, MIE3, r2, r3, new, r1_32, sel, 0)
+ C(0xb9e3, SELGR, RRF_a, MIE3, r2, r3, r1, 0, sel, 0)
+/* SELECT HIGH */
+ C(0xb9c0, SELFHR, RRF_a, MIE3, r2, r3, new, r1_32h, sel, 0)
+
/* SET ACCESS */
C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0)
/* SET ADDRESSING MODE */
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index 406578d105..9275f1349f 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -546,6 +546,48 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l,
uint64_t dest, uint64_t src)
do_helper_mvc(env, l, dest, src, GETPC());
}
+/* move right to left */
+static uint32_t do_helper_mvcrl(CPUS390XState *env, uint64_t l, uint64_t dest,
+ uint64_t src, uintptr_t ra)
+{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca, desta;
+ uint32_t i;
+
+ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+ __func__, l, dest, src);
+
+ /* MVCRL always copies one more byte than specified - maximum is 256 */
+ l++;
+
+ srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
+ /*
+ * "When the operands overlap, the result is obtained as if the operands
+ * were processed one byte at a time". Only non-destructive overlaps
+ * behave like memmove().
+ */
+ if (dest == src + l - 1) {
+ access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
+ } else if (!is_destructive_overlap(env, dest, src, l)) {
+ access_memmove(env, &desta, &srca, ra);
+ } else {
+ for (i = 0; i < l; i++) {
+ uint32_t ti = l - i - 1;
+ uint8_t byte = access_get_byte(env, &srca, ti, ra);
+ access_set_byte(env, &desta, ti, byte, ra);
+ }
+ }
+
+ return env->cc_op;
+}
+
+void HELPER(mvcrl)(CPUS390XState *env, uint64_t l, uint64_t dest, uint64_t src)
+{
+ do_helper_mvcrl(env, l, dest, src, GETPC());
+}
+
/* move inverse */
void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t
src)
{
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 46dea73357..c0a89e2787 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -1498,6 +1498,48 @@ static DisasJumpType op_andi(DisasContext *s,
DisasOps *o)
return DISAS_NEXT;
}
+static DisasJumpType op_andc(DisasContext *s, DisasOps *o)
+{
+ tcg_gen_andc_i64(o->out, o->in1, o->in2);
+ return DISAS_NEXT;
+}
+
+static DisasJumpType op_orc(DisasContext *s, DisasOps *o)
+{
+ tcg_gen_orc_i64(o->out, o->in1, o->in2);
+ return DISAS_NEXT;
+}
+
+static DisasJumpType op_nand(DisasContext *s, DisasOps *o)
+{
+ tcg_gen_nand_i64(o->out, o->in1, o->in2);
+ return DISAS_NEXT;
+}
+
+static DisasJumpType op_nor(DisasContext *s, DisasOps *o)
+{
+ tcg_gen_nor_i64(o->out, o->in1, o->in2);
+ return DISAS_NEXT;
+}
+
+static DisasJumpType op_nxor(DisasContext *s, DisasOps *o)
+{
+ tcg_gen_xor_i64(o->out, o->in1, o->in2);
+ tcg_gen_not_i64(o->out, o->out);
+ return DISAS_NEXT;
+}
+
+static DisasJumpType op_sel(DisasContext *s, DisasOps *o)
+{
+ DisasCompare c;
+ disas_jcc(s, &c, get_field(s, m4));
+ tcg_gen_movcond_i64(c.cond, o->out, c.u.s64.a, c.u.s64.b,
+ o->in1, o->in2);
+ free_compare(&c);
+ return DISAS_NEXT;
+}
+
+
static DisasJumpType op_ni(DisasContext *s, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
@@ -3358,6 +3400,12 @@ static DisasJumpType op_mvc(DisasContext *s, DisasOps *o)
return DISAS_NEXT;
}
+static DisasJumpType op_mvcrl(DisasContext *s, DisasOps *o)
+{
+ gen_helper_mvcrl(cpu_env, regs[0], o->addr1, o->in2);
+ return DISAS_NEXT;
+}
+
static DisasJumpType op_mvcin(DisasContext *s, DisasOps *o)
{
TCGv_i32 l = tcg_const_i32(get_field(s, l1));
@@ -6170,6 +6218,7 @@ enum DisasInsnEnum {
#define FAC_V S390_FEAT_VECTOR /* vector facility */
#define FAC_VE S390_FEAT_VECTOR_ENH /* vector enhancements
facility 1 */
#define FAC_MIE2 S390_FEAT_MISC_INSTRUCTION_EXT2 /*
miscellaneous-instruction-extensions facility 2 */
+#define FAC_MIE3 S390_FEAT_MISC_INSTRUCTION_EXT3 /*
miscellaneous-instruction-extensions facility 3 */
static const DisasInsn insn_info[] = {
#include "insn-data.def"
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index 1a7238b4eb..16b9d45307 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -1,6 +1,6 @@
S390X_SRC=$(SRC_PATH)/tests/tcg/s390x
VPATH+=$(S390X_SRC)
-CFLAGS+=-march=zEC12 -m64
+CFLAGS+=-march=z15 -m64
TESTS+=hello-s390x
TESTS+=csst
TESTS+=ipm
diff --git a/tests/tcg/s390x/mie3-compl.c b/tests/tcg/s390x/mie3-compl.c
new file mode 100644
index 0000000000..c03c2b6b7f
--- /dev/null
+++ b/tests/tcg/s390x/mie3-compl.c
@@ -0,0 +1,52 @@
+#include <stdint.h>
+
+
+#define F_EPI "stg %%r0, %[res] ": [res] "+m" (res) : : "r0", "r2", "r3"
+
+#define F_PRO asm ( \
+ "llihf %%r0,801\n" \
+ "lg %%r2, %[a] \n" \
+ "lg %%r3, %[b] " \
+ : : [a] "m" (a), \
+ [b] "m" (b) \
+ : "r2", "r3" )
+
+#define FbinOp(S, ASM) uint64_t S(uint64_t a, uint64_t b) \
+{ uint64_t res = 0; F_PRO; ASM; return res; }
+
+
+FbinOp(_ncrk, asm("ncrk %%r0, %%r3, %%r2 \n" F_EPI)) // AND WITH COMPLEMENT
+FbinOp(_ncgrk, asm("ncgrk %%r0, %%r3, %%r2 \n" F_EPI))
+
+FbinOp(_nnrk, asm("nnrk %%r0, %%r3, %%r2 \n" F_EPI)) // NAND
+FbinOp(_nngrk, asm("nngrk %%r0, %%r3, %%r2 \n" F_EPI))
+
+FbinOp(_nxrk, asm("nxrk %%r0, %%r3, %%r2 \n" F_EPI)) // NOT XOR
+FbinOp(_nxgrk, asm("nxgrk %%r0, %%r3, %%r2 \n" F_EPI))
+
+FbinOp(_nork, asm("nork %%r0, %%r3, %%r2 \n" F_EPI)) // NOR
+FbinOp(_nogrk, asm("nogrk %%r0, %%r3, %%r2 \n" F_EPI))
+
+FbinOp(_ocrk, asm("ocrk %%r0, %%r3, %%r2 \n" F_EPI)) // OR WITH COMPLEMENT
+FbinOp(_ocgrk, asm("ocgrk %%r0, %%r3, %%r2 \n" F_EPI))
+
+
+
+int main(int argc, char *argv[])
+{
+ if (_ncrk(0xFF88, 0xAA11) != 0x0000032100000011ull ||
+ _nnrk(0xFF88, 0xAA11) != 0x00000321FFFF55FFull ||
+ _nork(0xFF88, 0xAA11) != 0x00000321FFFF0066ull ||
+ _nxrk(0xFF88, 0xAA11) != 0x00000321FFFFAA66ull ||
+ _ocrk(0xFF88, 0xAA11) != 0x00000321FFFFAA77ull ||
+ _ncgrk(0xFF88, 0xAA11) != 0x0000000000000011ull ||
+ _nngrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFF55FFull ||
+ _nogrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFF0066ull ||
+ _nxgrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFFAA66ull ||
+ _ocgrk(0xFF88, 0xAA11) != 0xFFFFFFFFFFFFAA77ull)
+ {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/tests/tcg/s390x/mie3-mvcrl.c b/tests/tcg/s390x/mie3-mvcrl.c
new file mode 100644
index 0000000000..00f9c150a1
--- /dev/null
+++ b/tests/tcg/s390x/mie3-mvcrl.c
@@ -0,0 +1,31 @@
+#include <stdint.h>
+#include <string.h>
+
+
+static inline void mvcrl_8(const char *dst, const char *src)
+{
+ asm volatile (
+ "llill %%r0, 8 \n"
+ "mvcrl 0(%[dst]), 0(%[src]) \n"
+ : : [dst] "d" (dst), [src] "d" (src)
+ : "memory");
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char* alpha = "abcdefghijklmnop";
+
+ /* array missing 'i' */
+ char tstr[17] = "abcdefghjklmnop\0" ;
+
+ /* mvcrl reference use: 'open a hole in an array' */
+ mvcrl_8(tstr+9, tstr+8);
+
+ /* place missing 'i' */
+ tstr[8] = 'i';
+
+ return strncmp(alpha, tstr, 16ul);
+}
+
+
diff --git a/tests/tcg/s390x/mie3-sel.c b/tests/tcg/s390x/mie3-sel.c
new file mode 100644
index 0000000000..e771b1e413
--- /dev/null
+++ b/tests/tcg/s390x/mie3-sel.c
@@ -0,0 +1,42 @@
+#include <stdint.h>
+
+
+#define F_EPI "stg %%r0, %[res] ": [res] "+m" (res) : : "r0", "r2", "r3"
+
+#define F_PRO asm ( \
+ "lg %%r2, %[a] \n" \
+ "lg %%r3, %[b] \n" \
+ "lg %%r0, %[c] \n" \
+ "ltgr %%r0, %%r0" \
+ : : [a] "m" (a), \
+ [b] "m" (b), \
+ [c] "m" (c) \
+ : "r0", "r2", "r3", "r4")
+
+
+
+#define Fi3(S, ASM) uint64_t S(uint64_t a, uint64_t b, uint64_t c) \
+{ uint64_t res=0; F_PRO ; ASM ; return res; }
+
+
+Fi3 (_selre, asm("selre %%r0, %%r3, %%r2 \n" F_EPI))
+Fi3 (_selgrz, asm("selgrz %%r0, %%r3, %%r2 \n" F_EPI))
+Fi3 (_selfhrnz, asm("selfhrnz %%r0, %%r3, %%r2 \n" F_EPI))
+
+
+int main(int argc, char *argv[])
+{
+ uint64_t a = ~0, b = ~0, c = ~0;
+ a = _selre(0x066600000066ull, 0x066600000006ull,a);
+ b = _selgrz(0xF00D00000005ull, 0xF00D00000055ull,b);
+ c = _selfhrnz(0x004400000044ull, 0x000400000004ull,c);
+
+ if( (0xFFFFFFFF00000066ull != a) ||
+ (0x0000F00D00000005ull != b) ||
+ (0x00000004FFFFFFFFull != c) )
+ {
+ return 1;
+ }
+ return 0;
+}
+