From 0fd81617fad2cae099348877099f6cf4c3bbc5bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 12:49:47 -0700 Subject: [PATCH 001/149] target-s390: Disassemble more z10 and z196 opcodes Also fix disassembly for COMPARE AND BRANCH. The table must be sorted by primary opcode, and several were out of place. Signed-off-by: Richard Henderson --- disas/s390.c | 169 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 151 insertions(+), 18 deletions(-) diff --git a/disas/s390.c b/disas/s390.c index 0859dfa19f..73c4193202 100644 --- a/disas/s390.c +++ b/disas/s390.c @@ -589,6 +589,16 @@ static const struct s390_operand s390_operands[] = { 4, 32, S390_OPERAND_CCODE }, #define I8_32 46 /* 8 bit signed value starting at 32 */ { 8, 32, S390_OPERAND_SIGNED }, +#define U8_24 47 /* 8 bit unsigned value starting at 24 */ + { 8, 24, 0 }, +#define U8_32 48 /* 8 bit unsigned value starting at 32 */ + { 8, 32, 0 }, +#define I16_32 49 + { 16, 32, S390_OPERAND_SIGNED }, +#define M4_16 50 /* 4-bit condition-code starting at 12 */ + { 4, 16, S390_OPERAND_CCODE }, +#define I8_16 51 + { 8, 16, S390_OPERAND_SIGNED }, /* QEMU-END */ }; @@ -801,11 +811,35 @@ static const struct s390_operand s390_operands[] = #define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } /* QEMU-ADD: */ -#define INSTR_RIE_MRRP 6, { M4_32,R_8,R_12,J16_16,0,0 } /* e.g. crj */ +#define INSTR_RIE_MRRP 6, { M4_32, R_8, R_12, J16_16, 0, 0 } /* e.g. crj */ #define MASK_RIE_MRRP { 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff } -#define INSTR_RIE_MRIP 6, { M4_12,R_8,I8_32,J16_16,0,0 } /* e.g. cij */ +#define INSTR_RIE_MRIP 6, { M4_12, R_8, I8_32, J16_16, 0, 0 } /* e.g. cij */ #define MASK_RIE_MRIP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RIE_RRIII 6, { R_8, R_12, U8_16, U8_24, U8_32, 0 } /* risbg */ +#define MASK_RIE_RRIII { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_MRI 6, { M4_32, R_8, I16_16, 0, 0, 0 } /* e.g. cit */ +#define MASK_RIE_MRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_MRU 6, { M4_32, R_8, U16_16, 0, 0, 0 } /* e.g. clfit */ +#define MASK_RIE_MRU { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_RRI 6, { R_8, R_12, I16_16, 0, 0, 0 } +#define MASK_RIE_RRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RXY_URRD 6, { U8_8, D20_20, X_12, B_16, 0, 0 } +#define MASK_RXY_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_SIL_DRI 6, { D_20, B_16, I16_32, 0, 0, 0 } +#define MASK_SIL_DRI { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } + +#define INSTR_RSY_MRRD 6, { M4_12, R_8, D20_20, B_16, 0, 0 } +#define MASK_SRY_MRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RRF_MRR 6, { M4_16, R_24, R_28, 0, 0, 0 } +#define MASK_RRF_MRR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } + +#define INSTR_SIY_DRI 6, { D20_20, B_16, I8_16, 0, 0, 0 } +#define MASK_SIY_DRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } /* QEMU-END */ /* The opcode formats table (blueprints for .insn pseudo mnemonic). */ @@ -926,6 +960,30 @@ static const struct s390_opcode s390_opcodes[] = { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, +/* QEMU-ADD: */ + { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "risbg", OP48(0xec0000000055LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "risbhg", OP48(0xec000000005dLL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "risblg", OP48(0xec0000000051LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rnsbg", OP48(0xec0000000054LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rosbg", OP48(0xec0000000056LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rxsbg", OP48(0xec0000000057LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "cit", OP48(0xec0000000072LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, + { "cgit", OP48(0xec0000000070LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, + { "clfit", OP48(0xec0000000073LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, + { "clgit", OP48(0xec0000000071LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, + { "ahik", OP48(0xec00000000d8LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "aghik", OP48(0xec00000000d9LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "alhsik", OP48(0xec00000000daLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "alghsik", OP48(0xec00000000dbLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, +/* QEMU-END */ { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0}, { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, @@ -985,6 +1043,20 @@ static const struct s390_opcode s390_opcodes[] = { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, +/* QEMU-ADD: */ + { "loc", OP48(0xeb00000000f2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "locg", OP48(0xeb00000000e2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "stoc", OP48(0xeb00000000f3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "stocg", OP48(0xeb00000000e3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "srak", OP48(0xeb00000000dcLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "slak", OP48(0xeb00000000ddLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "srlk", OP48(0xeb00000000deLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "sllk", OP48(0xeb00000000dfLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "asi", OP48(0xeb000000006aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "alsi", OP48(0xeb000000006eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "agsi", OP48(0xeb000000007aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "algsi", OP48(0xeb000000007eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, +/* QEMU-END */ { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0}, { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, @@ -993,6 +1065,17 @@ static const struct s390_opcode s390_opcodes[] = { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2}, { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, +/* QEMU-ADD: */ + { "mvhhi", OP16(0xe544LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "mvghi", OP16(0xe548LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "mvhi", OP16(0xe54cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "chhsi", OP16(0xe554LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clhhsi", OP16(0xe555LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "cghsi", OP16(0xe558LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clghsi", OP16(0xe559LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "chsi", OP16(0xe55cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clfhsi", OP16(0xe55dLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, +/* QEMU-END */ { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, @@ -1116,6 +1199,9 @@ static const struct s390_opcode s390_opcodes[] = { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, +/* QEMU-ADD: */ + { "pfd", OP48(0xe30000000036LL), MASK_RXY_URRD, INSTR_RXY_URRD, 3, 6}, +/* QEMU-END */ { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, @@ -1135,6 +1221,32 @@ static const struct s390_opcode s390_opcodes[] = { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4}, +/* QEMU-ADD: */ + { "exrl", OP16(0xc600ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "pfdrl", OP16(0xc602ll), MASK_RIL_UP, INSTR_RIL_UP, 3, 6}, + { "cghrl", OP16(0xc604ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "chrl", OP16(0xc605ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clghrl", OP16(0xc606ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clhrl", OP16(0xc607ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "cgrl", OP16(0xc608ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clgrl", OP16(0xc60all), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "cgfrl", OP16(0xc60cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "crl", OP16(0xc60dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clgfrl", OP16(0xc60ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clrl", OP16(0xc60fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + + { "llhrl", OP16(0xc400ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lghrl", OP16(0xc404ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lhrl", OP16(0xc405ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "llghrl", OP16(0xc406ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "sthrl", OP16(0xc407ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "stgrl", OP16(0xc40bll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "llgfrl", OP16(0xc40ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "strl", OP16(0xc40fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, +/* QEMU-END */ { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, @@ -1265,6 +1377,29 @@ static const struct s390_opcode s390_opcodes[] = { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, +/* QEMU-ADD: */ + { "crt", OP16(0xb972LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "cgrt", OP16(0xb960LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "clrt", OP16(0xb973LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "clgrt", OP16(0xb961LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "locr", OP16(0xb9f2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, + { "locgr", OP16(0xb9e2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, + { "popcnt", OP16(0xb9e1LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 6}, + { "ngrk", OP16(0xb9e4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ogrk", OP16(0xb9e6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "xgrk", OP16(0xb9e7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "agrk", OP16(0xb9e8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "sgrk", OP16(0xb9e9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "algrk", OP16(0xb9eaLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "slgrk", OP16(0xb9ebLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "nrk", OP16(0xb9f4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ork", OP16(0xb9f6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "xrk", OP16(0xb9f7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ark", OP16(0xb9f8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "srk", OP16(0xb9f9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "alrk", OP16(0xb9faLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "slrk", OP16(0xb9fbLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, +/* QEMU-END */ { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, @@ -1426,6 +1561,20 @@ static const struct s390_opcode s390_opcodes[] = { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, +/* QEMU-ADD: */ + { "clfebr", OP16(0xb39cLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clfdbr", OP16(0xb39dLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clfxbr", OP16(0xb39eLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgebr", OP16(0xb3acLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgdbr", OP16(0xb3adLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgxbr", OP16(0xb3aeLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "celfbr", OP16(0xb390LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cdlfbr", OP16(0xb391LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cxlfbr", OP16(0xb392LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "celgbr", OP16(0xb3a0LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cdlgbr", OP16(0xb3a1LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cxlgbr", OP16(0xb3a2LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, +/* QEMU-END */ { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0}, { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5}, { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5}, @@ -1774,22 +1923,6 @@ static const struct s390_opcode s390_opcodes[] = { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0}, { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0}, { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0}, - -/* QEMU-ADD: */ - { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - - { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - - { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, -/* QEMU-END */ }; static const int s390_num_opcodes = From 79be7c7b603f89da209098a03a5459beb09a579b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 14:13:12 -0700 Subject: [PATCH 002/149] target-s390: Fix disassembly of cpsdr Signed-off-by: Richard Henderson --- disas/s390.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/disas/s390.c b/disas/s390.c index 73c4193202..25499ba419 100644 --- a/disas/s390.c +++ b/disas/s390.c @@ -673,7 +673,9 @@ static const struct s390_operand s390_operands[] = This is just a workaround for existing code e.g. glibc. */ #define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */ #define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */ -#define INSTR_RRF_F0FF2 4, { F_24,F_16,F_28,0,0,0 } /* e.g. cpsdr */ +/* QEMU-MOD */ +#define INSTR_RRF_F0FF2 4, { F_24,F_28,F_16,0,0,0 } /* e.g. cpsdr */ +/* QEMU-END */ #define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */ #define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */ #define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */ From 6ee77b16630bc86c1a44f9df61b072c7974ba503 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 10:44:45 -0700 Subject: [PATCH 003/149] target-s390: Fix gdbstub The real gdb protocol doesn't split out pc or cc as real registers. Those are pseudos that are extracted as needed from the PSW. Don't modify env->cc_op during read -- that way lies heisenbugs. Fill in the XXX for the fp registers. Remove duplicated defines in cpu.h. Signed-off-by: Richard Henderson --- gdbstub.c | 78 ++++++++++++++++++++++++++++------------------ target-s390x/cpu.h | 73 ------------------------------------------- 2 files changed, 48 insertions(+), 103 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index a8dd437ec0..e62dc798c3 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -40,6 +40,7 @@ #include "cpu.h" #include "qemu/sockets.h" #include "sysemu/kvm.h" +#include "qemu/bitops.h" #ifndef TARGET_CPU_MEMORY_RW_DEBUG static inline int target_memory_rw_debug(CPUArchState *env, target_ulong addr, @@ -1535,27 +1536,34 @@ static int cpu_gdb_write_register(CPUAlphaState *env, uint8_t *mem_buf, int n) } #elif defined (TARGET_S390X) -#define NUM_CORE_REGS S390_NUM_TOTAL_REGS +#define NUM_CORE_REGS S390_NUM_REGS static int cpu_gdb_read_register(CPUS390XState *env, uint8_t *mem_buf, int n) { + uint64_t val; + int cc_op; + switch (n) { - case S390_PSWM_REGNUM: GET_REGL(env->psw.mask); break; - case S390_PSWA_REGNUM: GET_REGL(env->psw.addr); break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - GET_REGL(env->regs[n-S390_R0_REGNUM]); break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - GET_REG32(env->aregs[n-S390_A0_REGNUM]); break; - case S390_FPC_REGNUM: GET_REG32(env->fpc); break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - /* XXX */ - break; - case S390_PC_REGNUM: GET_REGL(env->psw.addr); break; - case S390_CC_REGNUM: - env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, - env->cc_vr); - GET_REG32(env->cc_op); - break; + case S390_PSWM_REGNUM: + cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); + val = deposit64(env->psw.mask, 44, 2, cc_op); + GET_REGL(val); + break; + case S390_PSWA_REGNUM: + GET_REGL(env->psw.addr); + break; + case S390_R0_REGNUM ... S390_R15_REGNUM: + GET_REGL(env->regs[n-S390_R0_REGNUM]); + break; + case S390_A0_REGNUM ... S390_A15_REGNUM: + GET_REG32(env->aregs[n-S390_A0_REGNUM]); + break; + case S390_FPC_REGNUM: + GET_REG32(env->fpc); + break; + case S390_F0_REGNUM ... S390_F15_REGNUM: + GET_REG64(env->fregs[n-S390_F0_REGNUM].ll); + break; } return 0; @@ -1570,20 +1578,30 @@ static int cpu_gdb_write_register(CPUS390XState *env, uint8_t *mem_buf, int n) tmp32 = ldl_p(mem_buf); switch (n) { - case S390_PSWM_REGNUM: env->psw.mask = tmpl; break; - case S390_PSWA_REGNUM: env->psw.addr = tmpl; break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - env->regs[n-S390_R0_REGNUM] = tmpl; break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - env->aregs[n-S390_A0_REGNUM] = tmp32; r=4; break; - case S390_FPC_REGNUM: env->fpc = tmp32; r=4; break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - /* XXX */ - break; - case S390_PC_REGNUM: env->psw.addr = tmpl; break; - case S390_CC_REGNUM: env->cc_op = tmp32; r=4; break; + case S390_PSWM_REGNUM: + env->psw.mask = tmpl; + env->cc_op = extract64(tmpl, 44, 2); + break; + case S390_PSWA_REGNUM: + env->psw.addr = tmpl; + break; + case S390_R0_REGNUM ... S390_R15_REGNUM: + env->regs[n-S390_R0_REGNUM] = tmpl; + break; + case S390_A0_REGNUM ... S390_A15_REGNUM: + env->aregs[n-S390_A0_REGNUM] = tmp32; + r = 4; + break; + case S390_FPC_REGNUM: + env->fpc = tmp32; + r = 4; + break; + case S390_F0_REGNUM ... S390_F15_REGNUM: + env->fregs[n-S390_F0_REGNUM].ll = tmpl; + break; + default: + return 0; } - return r; } #elif defined (TARGET_LM32) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index cd565c91de..529716de47 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -430,79 +430,6 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) /* Total. */ #define S390_NUM_REGS 51 -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) - - - -/* Program Status Word. */ -#define S390_PSWM_REGNUM 0 -#define S390_PSWA_REGNUM 1 -/* General Purpose Registers. */ -#define S390_R0_REGNUM 2 -#define S390_R1_REGNUM 3 -#define S390_R2_REGNUM 4 -#define S390_R3_REGNUM 5 -#define S390_R4_REGNUM 6 -#define S390_R5_REGNUM 7 -#define S390_R6_REGNUM 8 -#define S390_R7_REGNUM 9 -#define S390_R8_REGNUM 10 -#define S390_R9_REGNUM 11 -#define S390_R10_REGNUM 12 -#define S390_R11_REGNUM 13 -#define S390_R12_REGNUM 14 -#define S390_R13_REGNUM 15 -#define S390_R14_REGNUM 16 -#define S390_R15_REGNUM 17 -/* Access Registers. */ -#define S390_A0_REGNUM 18 -#define S390_A1_REGNUM 19 -#define S390_A2_REGNUM 20 -#define S390_A3_REGNUM 21 -#define S390_A4_REGNUM 22 -#define S390_A5_REGNUM 23 -#define S390_A6_REGNUM 24 -#define S390_A7_REGNUM 25 -#define S390_A8_REGNUM 26 -#define S390_A9_REGNUM 27 -#define S390_A10_REGNUM 28 -#define S390_A11_REGNUM 29 -#define S390_A12_REGNUM 30 -#define S390_A13_REGNUM 31 -#define S390_A14_REGNUM 32 -#define S390_A15_REGNUM 33 -/* Floating Point Control Word. */ -#define S390_FPC_REGNUM 34 -/* Floating Point Registers. */ -#define S390_F0_REGNUM 35 -#define S390_F1_REGNUM 36 -#define S390_F2_REGNUM 37 -#define S390_F3_REGNUM 38 -#define S390_F4_REGNUM 39 -#define S390_F5_REGNUM 40 -#define S390_F6_REGNUM 41 -#define S390_F7_REGNUM 42 -#define S390_F8_REGNUM 43 -#define S390_F9_REGNUM 44 -#define S390_F10_REGNUM 45 -#define S390_F11_REGNUM 46 -#define S390_F12_REGNUM 47 -#define S390_F13_REGNUM 48 -#define S390_F14_REGNUM 49 -#define S390_F15_REGNUM 50 -/* Total. */ -#define S390_NUM_REGS 51 - -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) - /* CC optimization */ enum cc_op { From 063eb0f3038434ab4cf9ad4bcc19a8789e15d237 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 08:15:42 -0700 Subject: [PATCH 004/149] target-s390: Add missing temp_free in gen_op_calc_cc Signed-off-by: Richard Henderson --- target-s390x/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9e34741311..f1e754f76a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -757,6 +757,7 @@ static void gen_op_calc_cc(DisasContext *s) } tcg_temp_free_i32(local_cc_op); + tcg_temp_free_i64(dummy); /* We now have cc in cc_op as constant */ set_cc_static(s); From 431253c28f9177a3f4783dc47b952c8fffcf3177 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 06:57:35 -0700 Subject: [PATCH 005/149] target-s390: Use TCG registers for FPR At the same time, tidy other usages of tcg_gen_deposit_i64. In some cases we can "type cast" rather than extend, and in others we can allow tcg_gen_deposit_i64 itself to optimize the HOST_LONG_BITS==32 case. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 68 +++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f1e754f76a..27450656f5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -97,7 +97,7 @@ void cpu_dump_state(CPUS390XState *env, FILE *f, fprintf_function cpu_fprintf, } for (i = 0; i < 16; i++) { - cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]); + cpu_fprintf(f, "F%02d=%016" PRIx64, i, env->fregs[i].ll); if ((i % 4) == 3) { cpu_fprintf(f, "\n"); } else { @@ -134,21 +134,22 @@ static TCGv_i64 cc_src; static TCGv_i64 cc_dst; static TCGv_i64 cc_vr; -static char cpu_reg_names[10*3 + 6*4]; +static char cpu_reg_names[32][4]; static TCGv_i64 regs[16]; +static TCGv_i64 fregs[16]; static uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; void s390x_translate_init(void) { int i; - size_t cpu_reg_names_size = sizeof(cpu_reg_names); - char *p; cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, psw.addr), + psw_addr = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUS390XState, psw.addr), "psw_addr"); - psw_mask = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, psw.mask), + psw_mask = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUS390XState, psw.mask), "psw_mask"); cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op), @@ -160,13 +161,18 @@ void s390x_translate_init(void) cc_vr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, cc_vr), "cc_vr"); - p = cpu_reg_names; for (i = 0; i < 16; i++) { - snprintf(p, cpu_reg_names_size, "r%d", i); + snprintf(cpu_reg_names[i], sizeof(cpu_reg_names[0]), "r%d", i); regs[i] = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUS390XState, regs[i]), p); - p += (i < 10) ? 3 : 4; - cpu_reg_names_size -= (i < 10) ? 3 : 4; + offsetof(CPUS390XState, regs[i]), + cpu_reg_names[i]); + } + + for (i = 0; i < 16; i++) { + snprintf(cpu_reg_names[i + 16], sizeof(cpu_reg_names[0]), "f%d", i); + fregs[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUS390XState, fregs[i].d), + cpu_reg_names[i + 16]); } } @@ -180,14 +186,18 @@ static inline TCGv_i64 load_reg(int reg) static inline TCGv_i64 load_freg(int reg) { TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ld_i64(r, cpu_env, offsetof(CPUS390XState, fregs[reg].d)); + tcg_gen_mov_i64(r, fregs[reg]); return r; } static inline TCGv_i32 load_freg32(int reg) { TCGv_i32 r = tcg_temp_new_i32(); - tcg_gen_ld_i32(r, cpu_env, offsetof(CPUS390XState, fregs[reg].l.upper)); +#if HOST_LONG_BITS == 32 + tcg_gen_mov_i32(r, TCGV_HIGH(fregs[reg])); +#else + tcg_gen_shri_i64(MAKE_TCGV_I64(GET_TCGV_I32(r)), fregs[reg], 32); +#endif return r; } @@ -212,39 +222,35 @@ static inline void store_reg(int reg, TCGv_i64 v) static inline void store_freg(int reg, TCGv_i64 v) { - tcg_gen_st_i64(v, cpu_env, offsetof(CPUS390XState, fregs[reg].d)); + tcg_gen_mov_i64(fregs[reg], v); } static inline void store_reg32(int reg, TCGv_i32 v) { + /* 32 bit register writes keep the upper half */ #if HOST_LONG_BITS == 32 tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v); #else - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, v); - /* 32 bit register writes keep the upper half */ - tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 32); - tcg_temp_free_i64(tmp); + tcg_gen_deposit_i64(regs[reg], regs[reg], + MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 32); #endif } static inline void store_reg32_i64(int reg, TCGv_i64 v) { /* 32 bit register writes keep the upper half */ -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_LOW(regs[reg]), TCGV_LOW(v)); -#else tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); -#endif } static inline void store_reg16(int reg, TCGv_i32 v) { - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, v); /* 16 bit register writes keep the upper bytes */ - tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 16); - tcg_temp_free_i64(tmp); +#if HOST_LONG_BITS == 32 + tcg_gen_deposit_i32(TCGV_LOW(regs[reg]), TCGV_LOW(regs[reg]), v, 0, 16); +#else + tcg_gen_deposit_i64(regs[reg], regs[reg], + MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 16); +#endif } static inline void store_reg8(int reg, TCGv_i64 v) @@ -255,7 +261,13 @@ static inline void store_reg8(int reg, TCGv_i64 v) static inline void store_freg32(int reg, TCGv_i32 v) { - tcg_gen_st_i32(v, cpu_env, offsetof(CPUS390XState, fregs[reg].l.upper)); + /* 32 bit register writes keep the lower half */ +#if HOST_LONG_BITS == 32 + tcg_gen_mov_i32(TCGV_HIGH(fregs[reg]), v); +#else + tcg_gen_deposit_i64(fregs[reg], fregs[reg], + MAKE_TCGV_I64(GET_TCGV_I32(v)), 32, 32); +#endif } static inline void update_psw_addr(DisasContext *s) From 7e68da2a9dd112a1a4ef16e8ef3dc1916529ae6b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Sep 2012 09:14:33 -0700 Subject: [PATCH 006/149] target-s390: Register helpers Which highlights a lot of cc helpers that no longer exist. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 21 ++++----------------- target-s390x/translate.c | 4 ++++ 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c4926c52ad..2498f83be7 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -7,21 +7,10 @@ DEF_HELPER_4(xc, i32, env, i32, i64, i64) DEF_HELPER_4(mvc, void, env, i32, i64, i64) DEF_HELPER_4(clc, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) -DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_NO_RWG_SE, i32, s32) -DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_NO_RWG_SE, i32, s64) -DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_3(mlg, void, env, i32, i64) DEF_HELPER_3(dlg, void, env, i32, i64) -DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) @@ -38,7 +27,6 @@ DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) @@ -112,11 +100,13 @@ DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) +DEF_HELPER_3(cksm, void, env, i32, i32) +DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) +#ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) -DEF_HELPER_1(program_interrupt, void, i32) DEF_HELPER_FLAGS_2(stidp, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) @@ -144,9 +134,6 @@ DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_3(lra, i32, env, i64, i32) DEF_HELPER_3(stura, void, env, i64, i32) -DEF_HELPER_3(cksm, void, env, i32, i32) - -DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, - i32, env, i32, i64, i64, i64) +#endif #include "exec/def-helper.h" diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 27450656f5..1df3c538e5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -174,6 +174,10 @@ void s390x_translate_init(void) offsetof(CPUS390XState, fregs[i].d), cpu_reg_names[i + 16]); } + + /* register helpers */ +#define GEN_HELPER 2 +#include "helper.h" } static inline TCGv_i64 load_reg(int reg) From afd43fecfe7f6e863884b850f53fac4a75c28d84 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Sep 2012 05:22:18 -0700 Subject: [PATCH 007/149] target-s390: Fix SACF exit DISAS_EXCP is exit via exception; we wanted DISAS_JUMP. This matters when we start cleaning up the TB exit paths. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1df3c538e5..4898c7b8ad 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2933,7 +2933,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i64(tmp); break; case 0x79: /* SACF D2(B2) [S] */ - /* Store Clock Extended */ + /* Set Address Space Control Fast */ check_privileged(env, s, ilc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -2943,7 +2943,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, /* addressing mode has changed, so end the block */ s->pc += ilc * 2; update_psw_addr(s); - s->is_jmp = DISAS_EXCP; + s->is_jmp = DISAS_JUMP; break; case 0x7d: /* STSI D2,(B2) [S] */ check_privileged(env, s, ilc); From 9d126faf4279b324d5c4cdf09a3570d4a2041626 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Sep 2012 05:25:09 -0700 Subject: [PATCH 008/149] target-s390: Fix BCR There were are two exit paths for which we forgot to copy s->cc_op back to the tcg register. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 4898c7b8ad..79ab3e5344 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1212,6 +1212,7 @@ static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, if (mask == 0xf) { /* unconditional */ + gen_update_cc_op(s); tcg_gen_mov_i64(psw_addr, target); tcg_gen_exit_tb(0); } else if (mask == 0) { @@ -1223,6 +1224,7 @@ static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, tcg_gen_mov_i64(new_addr, target); skip = gen_new_label(); gen_jcc(s, mask, skip); + gen_update_cc_op(s); tcg_gen_mov_i64(psw_addr, new_addr); tcg_temp_free_i64(new_addr); tcg_gen_exit_tb(0); From 2f22e2ec79c07de03016adefb166cf01745fc852 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Sep 2012 05:28:43 -0700 Subject: [PATCH 009/149] target-s390: Tidy unconditional BRCL Yes, we're about to rewrite all of this, but having this unconditional jump recompute cc_op is a large source of "false diff errors" when trying to examine before and after dumps. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 79ab3e5344..b8f2ca8678 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3706,6 +3706,11 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 tcg_temp_free_i64(tmp); break; case 0x4: /* BRCL M1,I2 [RIL] */ + if (r1 == 15) { /* m1 == r1 */ + gen_goto_tb(s, 0, target); + s->is_jmp = DISAS_TB_JUMP; + break; + } /* m1 & (1 << (3 - cc)) */ tmp32_1 = tcg_const_i32(3); tmp32_2 = tcg_const_i32(1); From 51855ecf1a9d5a8388778571b8ab32134e83f378 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Sep 2012 12:06:15 -0700 Subject: [PATCH 010/149] target-s390: Fix PSW_MASK handling We were treating psw.mask as the 32-bit quantity it is in ESA mode. In particular, the CC field was at the wrong place. Signed-off-by: Richard Henderson --- target-s390x/helper.c | 9 +++++---- target-s390x/translate.c | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 42e06eb85e..7dc4d46eac 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -454,18 +454,19 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) env->psw.addr = addr; env->psw.mask = mask; - env->cc_op = (mask >> 13) & 3; + env->cc_op = (mask >> 44) & 3; } static uint64_t get_psw_mask(CPUS390XState *env) { - uint64_t r = env->psw.mask; + uint64_t r; env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); - r &= ~(3ULL << 13); + r = env->psw.mask; + r &= ~PSW_MASK_CC; assert(!(env->cc_op & ~3)); - r |= env->cc_op << 13; + r |= (uint64_t)env->cc_op << 44; return r; } diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b8f2ca8678..dc0f9cc8b9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -4559,6 +4559,8 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); tcg_gen_addi_i64(tmp, tmp, 4); tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); + /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ + tcg_gen_shli_i64(tmp2, tmp2, 32); gen_helper_load_psw(cpu_env, tmp2, tmp3); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); From ad044d09de62c10c361003765d5039396c057abe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Aug 2012 17:16:22 -0700 Subject: [PATCH 011/149] target-s390: Add format based disassassmbly infrastructure Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 54 ++ target-s390x/insn-format.def | 55 ++ target-s390x/translate.c | 1113 +++++++++++++++++++++++----------- 3 files changed, 858 insertions(+), 364 deletions(-) create mode 100644 target-s390x/insn-data.def create mode 100644 target-s390x/insn-format.def diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def new file mode 100644 index 0000000000..7d81928350 --- /dev/null +++ b/target-s390x/insn-data.def @@ -0,0 +1,54 @@ +/* ADD */ + C(0x1a00, AR, RR_a, Z, r1, r2, new, r1_32, add, adds32) + C(0xb9f8, ARK, RRF_a, DO, r2, r3, new, r1_32, add, adds32) + C(0x5a00, A, RX_a, Z, r1, m2_32s, new, r1_32, add, adds32) + C(0xe35a, AY, RXY_a, LD, r1, m2_32s, new, r1_32, add, adds32) + C(0xb908, AGR, RRE, Z, r1, r2, r1, 0, add, adds64) + C(0xb918, AGFR, RRE, Z, r1, r2_32s, r1, 0, add, adds64) + C(0xb9e8, AGRK, RRF_a, DO, r2, r3, r1, 0, add, adds64) + C(0xe308, AG, RXY_a, Z, r1, m2_64, r1, 0, add, adds64) + C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) +/* ADD IMMEDIATE */ + C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) + C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32) + C(0xecd8, AHIK, RIE_d, DO, r3, i2, new, r1_32, add, adds32) + C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) + C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64) + C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) +/* ADD LOGICAL */ + C(0x1e00, ALR, RR_a, Z, r1, r2, new, r1_32, add, addu32) + C(0xb9fa, ALRK, RRF_a, DO, r2, r3, new, r1_32, add, addu32) + C(0x5e00, AL, RX_a, Z, r1, m2_32u, new, r1_32, add, addu32) + C(0xe35e, ALY, RXY_a, LD, r1, m2_32u, new, r1_32, add, addu32) + C(0xb90a, ALGR, RRE, Z, r1, r2, r1, 0, add, addu64) + C(0xb91a, ALGFR, RRE, Z, r1, r2_32u, r1, 0, add, addu64) + C(0xb9ea, ALGRK, RRF_a, DO, r2, r3, r1, 0, add, addu64) + C(0xe30a, ALG, RXY_a, Z, r1, m2_64, r1, 0, add, addu64) + C(0xe31a, ALGF, RXY_a, Z, r1, m2_32u, r1, 0, add, addu64) +/* ADD LOGICAL IMMEDIATE */ + C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32) + C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64) + +/* SUBTRACT */ + C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) + C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) + C(0x5b00, S, RX_a, Z, r1, m2_32s, new, r1_32, sub, subs32) + C(0xe35b, SY, RXY_a, LD, r1, m2_32s, new, r1_32, sub, subs32) + C(0xb909, SGR, RRE, Z, r1, r2, r1, 0, sub, subs64) + C(0xb919, SGFR, RRE, Z, r1, r2_32s, r1, 0, sub, subs64) + C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) + C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) + C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) +/* SUBTRACT LOGICAL */ + C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32) + C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32) + C(0x5f00, SL, RX_a, Z, r1, m2_32u, new, r1_32, sub, subu32) + C(0xe35f, SLY, RXY_a, LD, r1, m2_32u, new, r1_32, sub, subu32) + C(0xb90b, SLGR, RRE, Z, r1, r2, r1, 0, sub, subu64) + C(0xb91b, SLGFR, RRE, Z, r1, r2_32u, r1, 0, sub, subu64) + C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, sub, subu64) + C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, sub, subu64) + C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, sub, subu64) +/* SUBTRACT LOGICAL IMMEDIATE */ + C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32) + C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64) diff --git a/target-s390x/insn-format.def b/target-s390x/insn-format.def new file mode 100644 index 0000000000..0e898b90bd --- /dev/null +++ b/target-s390x/insn-format.def @@ -0,0 +1,55 @@ +/* Description of s390 insn formats. */ +/* NAME F1, F2... */ +F0(E) +F1(I, I(1, 8, 8)) +F2(RI_a, R(1, 8), I(2,16,16)) +F2(RI_b, R(1, 8), I(2,16,16)) +F2(RI_c, M(1, 8), I(2,16,16)) +F3(RIE_a, R(1, 8), I(2,16,16), M(3,32)) +F4(RIE_b, R(1, 8), R(2,12), M(3,32), I(4,16,16)) +F4(RIE_c, R(1, 8), I(2,32, 8), M(3,12), I(4,16,16)) +F3(RIE_d, R(1, 8), I(2,16,16), R(3,12)) +F3(RIE_e, R(1, 8), I(2,16,16), R(3,12)) +F5(RIE_f, R(1, 8), R(2,12), I(3,16,8), I(4,24,8), I(5,32,8)) +F2(RIL_a, R(1, 8), I(2,16,32)) +F2(RIL_b, R(1, 8), I(2,16,32)) +F2(RIL_c, M(1, 8), I(2,16,32)) +F4(RIS, R(1, 8), I(2,32, 8), M(3,12), BD(4,16,20)) +/* ??? The PoO does not call out subtypes _a and _b for RR, as it does + for e.g. RX. Our checking requires this for e.g. BCR. */ +F2(RR_a, R(1, 8), R(2,12)) +F2(RR_b, M(1, 8), R(2,12)) +F2(RRE, R(1,24), R(2,28)) +F3(RRD, R(1,16), R(2,28), R(3,24)) +F4(RRF_a, R(1,24), R(2,28), R(3,16), M(4,20)) +F4(RRF_b, R(1,24), R(2,28), R(3,16), M(4,20)) +F4(RRF_c, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRF_d, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRF_e, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRS, R(1, 8), R(2,12), M(3,32), BD(4,16,20)) +F3(RS_a, R(1, 8), BD(2,16,20), R(3,12)) +F3(RS_b, R(1, 8), BD(2,16,20), M(3,12)) +F3(RSI, R(1, 8), I(2,16,16), R(3,12)) +F2(RSL, L(1, 8, 4), BD(1,16,20)) +F3(RSY_a, R(1, 8), BDL(2), R(3,12)) +F3(RSY_b, R(1, 8), BDL(2), M(3,12)) +F2(RX_a, R(1, 8), BXD(2)) +F2(RX_b, M(1, 8), BXD(2)) +F2(RXE, R(1, 8), BXD(2)) +F3(RXF, R(1,32), BXD(2), R(3, 8)) +F2(RXY_a, R(1, 8), BXDL(2)) +F2(RXY_b, M(1, 8), BXDL(2)) +F1(S, BD(2,16,20)) +F2(SI, BD(1,16,20), I(2,8,8)) +F2(SIL, BD(1,16,20), I(2,32,16)) +F2(SIY, BDL(1), I(2, 8, 8)) +F3(SS_a, L(1, 8, 8), BD(1,16,20), BD(2,32,36)) +F4(SS_b, L(1, 8, 4), BD(1,16,20), L(2,12,4), BD(2,32,36)) +F4(SS_c, L(1, 8, 4), BD(1,16,20), BD(2,32,36), I(3,12, 4)) +/* ??? Odd man out. The L1 field here is really a register, but the + easy way to compress the fields has R1 and B1 overlap. */ +F4(SS_d, L(1, 8, 4), BD(1,16,20), BD(2,32,36), R(3,12)) +F4(SS_e, R(1, 8), BD(2,16,20), R(3,12), BD(4,32,36)) +F3(SS_f, BD(1,16,20), L(2,8,8), BD(2,32,36)) +F2(SSE, BD(1,16,20), BD(2,32,36)) +F3(SSF, BD(1,16,20), BD(2,32,36), R(3,8)) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dc0f9cc8b9..92d49e1c6f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -42,12 +42,20 @@ static TCGv_ptr cpu_env; #define GEN_HELPER 1 #include "helper.h" + +/* Information that (most) every instruction needs to manipulate. */ typedef struct DisasContext DisasContext; +typedef struct DisasInsn DisasInsn; +typedef struct DisasFields DisasFields; + struct DisasContext { - uint64_t pc; - int is_jmp; - enum cc_op cc_op; struct TranslationBlock *tb; + const DisasInsn *insn; + DisasFields *fields; + uint64_t pc, next_pc; + enum cc_op cc_op; + bool singlestep_enabled; + int is_jmp; }; #define DISAS_EXCP 4 @@ -295,15 +303,12 @@ static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc) { - return (uint64_t)cpu_ldl_code(env, pc); + return (uint64_t)(uint32_t)cpu_ldl_code(env, pc); } static inline uint64_t ld_code6(CPUS390XState *env, uint64_t pc) { - uint64_t opc; - opc = (uint64_t)cpu_lduw_code(env, pc) << 32; - opc |= (uint64_t)(uint32_t)cpu_ldl_code(env, pc + 2); - return opc; + return (ld_code2(env, pc) << 32) | ld_code4(env, pc + 2); } static inline int get_mem_index(DisasContext *s) @@ -607,17 +612,6 @@ static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr); } -static void set_cc_sub64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_SUB_64, v1, v2, vr); -} - -static void set_cc_subu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_SUBU_64, v1, v2, vr); -} - static void set_cc_abs64(DisasContext *s, TCGv_i64 v1) { gen_op_update1_cc_i64(s, CC_OP_ABS_64, v1); @@ -644,12 +638,6 @@ static void set_cc_sub32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) gen_op_update3_cc_i32(s, CC_OP_SUB_32, v1, v2, vr); } -static void set_cc_subu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_SUBU_32, v1, v2, vr); -} - static void set_cc_abs32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1); @@ -1535,72 +1523,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp3); tcg_temp_free_i64(tmp4); break; - case 0x8: /* AG R1,D2(X2,B2) [RXY] */ - case 0xa: /* ALG R1,D2(X2,B2) [RXY] */ - case 0x18: /* AGF R1,D2(X2,B2) [RXY] */ - case 0x1a: /* ALGF R1,D2(X2,B2) [RXY] */ - if (op == 0x1a) { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - } else if (op == 0x18) { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x8: - case 0x18: - set_cc_add64(s, tmp4, tmp2, tmp3); - break; - case 0xa: - case 0x1a: - set_cc_addu64(s, tmp4, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; - case 0x9: /* SG R1,D2(X2,B2) [RXY] */ - case 0xb: /* SLG R1,D2(X2,B2) [RXY] */ - case 0x19: /* SGF R1,D2(X2,B2) [RXY] */ - case 0x1b: /* SLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0x19) { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else if (op == 0x1b) { - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_sub_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x9: - case 0x19: - set_cc_sub64(s, tmp4, tmp2, tmp3); - break; - case 0xb: - case 0x1b: - set_cc_subu64(s, tmp4, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0xf: /* LRVG R1,D2(X2,B2) [RXE] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); @@ -1723,40 +1645,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg32_i64(r1, tmp3); tcg_temp_free_i64(tmp3); break; - case 0x5a: /* AY R1,D2(X2,B2) [RXY] */ - case 0x5b: /* SY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_temp_free_i64(tmp2); - switch (op) { - case 0x5a: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - break; - case 0x5b: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - switch (op) { - case 0x5a: - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5b: - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ store_reg(r1, addr); break; @@ -3350,68 +3238,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x8: /* AGR R1,R2 [RRE] */ - case 0xa: /* ALGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x8: - set_cc_add64(s, tmp, tmp2, tmp3); - break; - case 0xa: - set_cc_addu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x9: /* SGR R1,R2 [RRE] */ - case 0xb: /* SLGR R1,R2 [RRE] */ - case 0x1b: /* SLGFR R1,R2 [RRE] */ - case 0x19: /* SGFR R1,R2 [RRE] */ - tmp = load_reg(r1); - switch (op) { - case 0x1b: - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x19: - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - default: - tmp2 = load_reg(r2); - break; - } - tmp3 = tcg_temp_new_i64(); - tcg_gen_sub_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x9: - case 0x19: - set_cc_sub64(s, tmp, tmp2, tmp3); - break; - case 0xb: - case 0x1b: - set_cc_subu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0xc: /* MSGR R1,R2 [RRE] */ case 0x1c: /* MSGFR R1,R2 [RRE] */ tmp = load_reg(r1); @@ -3469,29 +3295,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x18: /* AGFR R1,R2 [RRE] */ - case 0x1a: /* ALGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - if (op == 0x18) { - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - } else { - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - } - tcg_temp_free_i32(tmp32_1); - tmp = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - if (op == 0x18) { - set_cc_add64(s, tmp, tmp2, tmp3); - } else { - set_cc_addu64(s, tmp, tmp2, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x0f: /* LRVGR R1,R2 [RRE] */ tcg_gen_bswap64_i64(regs[r1], regs[r2]); break; @@ -3794,54 +3597,10 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { - TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i64 tmp; + TCGv_i32 tmp32_1; switch (op) { - case 0x4: /* SLGFI R1,I2 [RIL] */ - case 0xa: /* ALGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2); - tmp3 = tcg_temp_new_i64(); - switch (op) { - case 0x4: - tcg_gen_sub_i64(tmp3, tmp, tmp2); - set_cc_subu64(s, tmp, tmp2, tmp3); - break; - case 0xa: - tcg_gen_add_i64(tmp3, tmp, tmp2); - set_cc_addu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x5: /* SLFI R1,I2 [RIL] */ - case 0xb: /* ALFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(i2); - tmp32_3 = tcg_temp_new_i32(); - switch (op) { - case 0x5: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0xb: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0xc: /* CGFI R1,I2 [RIL] */ tmp = load_reg(r1); cmp_s64c(s, tmp, (int64_t)i2); @@ -4059,42 +3818,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x1a: /* AR R1,R2 [RR] */ - case 0x1e: /* ALR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_3); - if (opc == 0x1a) { - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - } else { - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x1b: /* SR R1,R2 [RR] */ - case 0x1f: /* SLR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_3); - if (opc == 0x1b) { - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - } else { - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x1c: /* MR R1,R2 [RR] */ /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ insn = ld_code2(env, s->pc); @@ -4380,51 +4103,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5a: /* A R1,D2(X2,B2) [RX] */ - case 0x5b: /* S R1,D2(X2,B2) [RX] */ - case 0x5e: /* AL R1,D2(X2,B2) [RX] */ - case 0x5f: /* SL R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp); - switch (opc) { - case 0x5a: - case 0x5e: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - break; - case 0x5b: - case 0x5f: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - switch (opc) { - case 0x5a: - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5e: - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5b: - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5f: - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x5c: /* M R1,D2(X2,B2) [RX] */ /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */ insn = ld_code4(env, s->pc); @@ -5131,9 +4809,699 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) gen_illegal_opcode(env, s, ilc); break; } +} + +/* ====================================================================== */ +/* Define the insn format enumeration. */ +#define F0(N) FMT_##N, +#define F1(N, X1) F0(N) +#define F2(N, X1, X2) F0(N) +#define F3(N, X1, X2, X3) F0(N) +#define F4(N, X1, X2, X3, X4) F0(N) +#define F5(N, X1, X2, X3, X4, X5) F0(N) + +typedef enum { +#include "insn-format.def" +} DisasFormat; + +#undef F0 +#undef F1 +#undef F2 +#undef F3 +#undef F4 +#undef F5 + +/* Define a structure to hold the decoded fields. We'll store each inside + an array indexed by an enum. In order to conserve memory, we'll arrange + for fields that do not exist at the same time to overlap, thus the "C" + for compact. For checking purposes there is an "O" for original index + as well that will be applied to availability bitmaps. */ + +enum DisasFieldIndexO { + FLD_O_r1, + FLD_O_r2, + FLD_O_r3, + FLD_O_m1, + FLD_O_m3, + FLD_O_m4, + FLD_O_b1, + FLD_O_b2, + FLD_O_b4, + FLD_O_d1, + FLD_O_d2, + FLD_O_d4, + FLD_O_x2, + FLD_O_l1, + FLD_O_l2, + FLD_O_i1, + FLD_O_i2, + FLD_O_i3, + FLD_O_i4, + FLD_O_i5 +}; + +enum DisasFieldIndexC { + FLD_C_r1 = 0, + FLD_C_m1 = 0, + FLD_C_b1 = 0, + FLD_C_i1 = 0, + + FLD_C_r2 = 1, + FLD_C_b2 = 1, + FLD_C_i2 = 1, + + FLD_C_r3 = 2, + FLD_C_m3 = 2, + FLD_C_i3 = 2, + + FLD_C_m4 = 3, + FLD_C_b4 = 3, + FLD_C_i4 = 3, + FLD_C_l1 = 3, + + FLD_C_i5 = 4, + FLD_C_d1 = 4, + + FLD_C_d2 = 5, + + FLD_C_d4 = 6, + FLD_C_x2 = 6, + FLD_C_l2 = 6, + + NUM_C_FIELD = 7 +}; + +struct DisasFields { + unsigned op:8; + unsigned op2:8; + unsigned presentC:16; + unsigned int presentO; + int c[NUM_C_FIELD]; +}; + +/* This is the way fields are to be accessed out of DisasFields. */ +#define have_field(S, F) have_field1((S), FLD_O_##F) +#define get_field(S, F) get_field1((S), FLD_O_##F, FLD_C_##F) + +static bool have_field1(const DisasFields *f, enum DisasFieldIndexO c) +{ + return (f->presentO >> c) & 1; +} + +static int get_field1(const DisasFields *f, enum DisasFieldIndexO o, + enum DisasFieldIndexC c) +{ + assert(have_field1(f, o)); + return f->c[c]; +} + +/* Describe the layout of each field in each format. */ +typedef struct DisasField { + unsigned int beg:8; + unsigned int size:8; + unsigned int type:2; + unsigned int indexC:6; + enum DisasFieldIndexO indexO:8; +} DisasField; + +typedef struct DisasFormatInfo { + DisasField op[NUM_C_FIELD]; +} DisasFormatInfo; + +#define R(N, B) { B, 4, 0, FLD_C_r##N, FLD_O_r##N } +#define M(N, B) { B, 4, 0, FLD_C_m##N, FLD_O_m##N } +#define BD(N, BB, BD) { BB, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { BD, 12, 0, FLD_C_d##N, FLD_O_d##N } +#define BXD(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 12, 4, 0, FLD_C_x##N, FLD_O_x##N }, \ + { 20, 12, 0, FLD_C_d##N, FLD_O_d##N } +#define BDL(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 20, 20, 2, FLD_C_d##N, FLD_O_d##N } +#define BXDL(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 12, 4, 0, FLD_C_x##N, FLD_O_x##N }, \ + { 20, 20, 2, FLD_C_d##N, FLD_O_d##N } +#define I(N, B, S) { B, S, 1, FLD_C_i##N, FLD_O_i##N } +#define L(N, B, S) { B, S, 0, FLD_C_l##N, FLD_O_l##N } + +#define F0(N) { { } }, +#define F1(N, X1) { { X1 } }, +#define F2(N, X1, X2) { { X1, X2 } }, +#define F3(N, X1, X2, X3) { { X1, X2, X3 } }, +#define F4(N, X1, X2, X3, X4) { { X1, X2, X3, X4 } }, +#define F5(N, X1, X2, X3, X4, X5) { { X1, X2, X3, X4, X5 } }, + +static const DisasFormatInfo format_info[] = { +#include "insn-format.def" +}; + +#undef F0 +#undef F1 +#undef F2 +#undef F3 +#undef F4 +#undef F5 +#undef R +#undef M +#undef BD +#undef BXD +#undef BDL +#undef BXDL +#undef I +#undef L + +/* Generally, we'll extract operands into this structures, operate upon + them, and store them back. See the "in1", "in2", "prep", "wout" sets + of routines below for more details. */ +typedef struct { + bool g_out, g_out2, g_in1, g_in2; + TCGv_i64 out, out2, in1, in2; + TCGv_i64 addr1; +} DisasOps; + +/* Return values from translate_one, indicating the state of the TB. */ +typedef enum { + /* Continue the TB. */ + NO_EXIT, + /* We have emitted one or more goto_tb. No fixup required. */ + EXIT_GOTO_TB, + /* We are not using a goto_tb (for whatever reason), but have updated + the PC (for whatever reason), so there's no need to do it again on + exiting the TB. */ + EXIT_PC_UPDATED, + /* We are exiting the TB, but have neither emitted a goto_tb, nor + updated the PC for the next instruction to be executed. */ + EXIT_PC_STALE, + /* We are ending the TB with a noreturn function call, e.g. longjmp. + No following code will be executed. */ + EXIT_NORETURN, +} ExitStatus; + +typedef enum DisasFacility { + FAC_Z, /* zarch (default) */ + FAC_CASS, /* compare and swap and store */ + FAC_CASS2, /* compare and swap and store 2*/ + FAC_DFP, /* decimal floating point */ + FAC_DFPR, /* decimal floating point rounding */ + FAC_DO, /* distinct operands */ + FAC_EE, /* execute extensions */ + FAC_EI, /* extended immediate */ + FAC_FPE, /* floating point extension */ + FAC_FPSSH, /* floating point support sign handling */ + FAC_FPRGR, /* FPR-GR transfer */ + FAC_GIE, /* general instructions extension */ + FAC_HFP_MA, /* HFP multiply-and-add/subtract */ + FAC_HW, /* high-word */ + FAC_IEEEE_SIM, /* IEEE exception sumilation */ + FAC_LOC, /* load/store on condition */ + FAC_LD, /* long displacement */ + FAC_PC, /* population count */ + FAC_SCF, /* store clock fast */ + FAC_SFLE, /* store facility list extended */ +} DisasFacility; + +struct DisasInsn { + unsigned opc:16; + DisasFormat fmt:6; + DisasFacility fac:6; + + const char *name; + + void (*help_in1)(DisasContext *, DisasFields *, DisasOps *); + void (*help_in2)(DisasContext *, DisasFields *, DisasOps *); + void (*help_prep)(DisasContext *, DisasFields *, DisasOps *); + void (*help_wout)(DisasContext *, DisasFields *, DisasOps *); + void (*help_cout)(DisasContext *, DisasOps *); + ExitStatus (*help_op)(DisasContext *, DisasOps *); + + uint64_t data; +}; + +/* ====================================================================== */ +/* The operations. These perform the bulk of the work for any insn, + usually after the operands have been loaded and output initialized. */ + +static ExitStatus op_add(DisasContext *s, DisasOps *o) +{ + tcg_gen_add_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sub(DisasContext *s, DisasOps *o) +{ + tcg_gen_sub_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +/* ====================================================================== */ +/* The "Cc OUTput" generators. Given the generated output (and in some cases + the original inputs), update the various cc data structures in order to + be able to compute the new condition code. */ + +static void cout_adds32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADD_32, o->in1, o->in2, o->out); +} + +static void cout_adds64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADD_64, o->in1, o->in2, o->out); +} + +static void cout_addu32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDU_32, o->in1, o->in2, o->out); +} + +static void cout_addu64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); +} + +static void cout_subs32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out); +} + +static void cout_subs64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUB_64, o->in1, o->in2, o->out); +} + +static void cout_subu32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBU_32, o->in1, o->in2, o->out); +} + +static void cout_subu64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out); +} + +/* ====================================================================== */ +/* The "PREPeration" generators. These initialize the DisasOps.OUT fields + with the TCG register to which we will write. Used in combination with + the "wout" generators, in some cases we need a new temporary, and in + some cases we can write to a TCG global. */ + +static void prep_new(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = tcg_temp_new_i64(); +} + +static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = regs[get_field(f, r1)]; + o->g_out = true; +} + +/* ====================================================================== */ +/* The "Write OUTput" generators. These generally perform some non-trivial + copy of data to TCG globals, or to main memory. The trivial cases are + generally handled by having a "prep" generator install the TCG global + as the destination of the operation. */ + +static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg32_i64(get_field(f, r1), o->out); +} + +static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); +} + +static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s)); +} + +/* ====================================================================== */ +/* The "INput 1" generators. These load the first operand to an insn. */ + +static void in1_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r1)); +} + +static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r2)); +} + +static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r3)); +} + +static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); +} + +static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s)); +} + +static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s)); +} + +/* ====================================================================== */ +/* The "INput 2" generators. These load the second operand to an insn. */ + +static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_reg(get_field(f, r2)); +} + +static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_reg(get_field(f, r3)); +} + +static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]); +} + +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)); +} + +static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_m2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64(get_field(f, i2)); +} + +static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); +} + +/* ====================================================================== */ + +/* Find opc within the table of insns. This is formulated as a switch + statement so that (1) we get compile-time notice of cut-paste errors + for duplicated opcodes, and (2) the compiler generates the binary + search tree, rather than us having to post-process the table. */ + +#define C(OPC, NM, FT, FC, I1, I2, P, W, OP, CC) \ + D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, 0) + +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) insn_ ## NM, + +enum DisasInsnEnum { +#include "insn-data.def" +}; + +#undef D +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \ + .opc = OPC, \ + .fmt = FMT_##FT, \ + .fac = FAC_##FC, \ + .name = #NM, \ + .help_in1 = in1_##I1, \ + .help_in2 = in2_##I2, \ + .help_prep = prep_##P, \ + .help_wout = wout_##W, \ + .help_cout = cout_##CC, \ + .help_op = op_##OP, \ + .data = D \ + }, + +/* Allow 0 to be used for NULL in the table below. */ +#define in1_0 NULL +#define in2_0 NULL +#define prep_0 NULL +#define wout_0 NULL +#define cout_0 NULL +#define op_0 NULL + +static const DisasInsn insn_info[] = { +#include "insn-data.def" +}; + +#undef D +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) \ + case OPC: return &insn_info[insn_ ## NM]; + +static const DisasInsn *lookup_opc(uint16_t opc) +{ + switch (opc) { +#include "insn-data.def" + default: + return NULL; + } +} + +#undef D +#undef C + +/* Extract a field from the insn. The INSN should be left-aligned in + the uint64_t so that we can more easily utilize the big-bit-endian + definitions we extract from the Principals of Operation. */ + +static void extract_field(DisasFields *o, const DisasField *f, uint64_t insn) +{ + uint32_t r, m; + + if (f->size == 0) { + return; + } + + /* Zero extract the field from the insn. */ + r = (insn << f->beg) >> (64 - f->size); + + /* Sign-extend, or un-swap the field as necessary. */ + switch (f->type) { + case 0: /* unsigned */ + break; + case 1: /* signed */ + assert(f->size <= 32); + m = 1u << (f->size - 1); + r = (r ^ m) - m; + break; + case 2: /* dl+dh split, signed 20 bit. */ + r = ((int8_t)r << 12) | (r >> 8); + break; + default: + abort(); + } + + /* Validate that the "compressed" encoding we selected above is valid. + I.e. we havn't make two different original fields overlap. */ + assert(((o->presentC >> f->indexC) & 1) == 0); + o->presentC |= 1 << f->indexC; + o->presentO |= 1 << f->indexO; + + o->c[f->indexC] = r; +} + +/* Lookup the insn at the current PC, extracting the operands into O and + returning the info struct for the insn. Returns NULL for invalid insn. */ + +static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, + DisasFields *f) +{ + uint64_t insn, pc = s->pc; + int op, op2; + const DisasInsn *info; + + insn = ld_code2(env, pc); + op = (insn >> 8) & 0xff; + switch (get_ilc(op)) { + case 1: + insn = insn << 48; + break; + case 2: + insn = ld_code4(env, pc) << 32; + break; + case 3: + insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); + break; + default: + abort(); + } + + /* We can't actually determine the insn format until we've looked up + the full insn opcode. Which we can't do without locating the + secondary opcode. Assume by default that OP2 is at bit 40; for + those smaller insns that don't actually have a secondary opcode + this will correctly result in OP2 = 0. */ + switch (op) { + case 0x01: /* E */ + case 0x80: /* S */ + case 0x82: /* S */ + case 0x93: /* S */ + case 0xb2: /* S, RRF, RRE */ + case 0xb3: /* RRE, RRD, RRF */ + case 0xb9: /* RRE, RRF */ + case 0xe5: /* SSE, SIL */ + op2 = (insn << 8) >> 56; + break; + case 0xa5: /* RI */ + case 0xa7: /* RI */ + case 0xc0: /* RIL */ + case 0xc2: /* RIL */ + case 0xc4: /* RIL */ + case 0xc6: /* RIL */ + case 0xc8: /* SSF */ + case 0xcc: /* RIL */ + op2 = (insn << 12) >> 60; + break; + case 0xd0 ... 0xdf: /* SS */ + case 0xe1: /* SS */ + case 0xe2: /* SS */ + case 0xe8: /* SS */ + case 0xe9: /* SS */ + case 0xea: /* SS */ + case 0xee ... 0xf3: /* SS */ + case 0xf8 ... 0xfd: /* SS */ + op2 = 0; + break; + default: + op2 = (insn << 40) >> 56; + break; + } + + memset(f, 0, sizeof(*f)); + f->op = op; + f->op2 = op2; + + /* Lookup the instruction. */ + info = lookup_opc(op << 8 | op2); + + /* If we found it, extract the operands. */ + if (info != NULL) { + DisasFormat fmt = info->fmt; + int i; + + for (i = 0; i < NUM_C_FIELD; ++i) { + extract_field(f, &format_info[fmt].op[i], insn); + } + } + return info; +} + +static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) +{ + const DisasInsn *insn; + ExitStatus ret = NO_EXIT; + DisasFields f; + DisasOps o; + + insn = extract_insn(env, s, &f); /* Instruction length is encoded in the opcode */ - s->pc += (ilc * 2); + s->next_pc = s->pc + get_ilc(f.op) * 2; + + /* If not found, try the old interpreter. This includes ILLOPC. */ + if (insn == NULL) { + disas_s390_insn(env, s); + switch (s->is_jmp) { + case DISAS_NEXT: + ret = NO_EXIT; + break; + case DISAS_TB_JUMP: + ret = EXIT_GOTO_TB; + break; + case DISAS_JUMP: + ret = EXIT_PC_UPDATED; + break; + case DISAS_EXCP: + ret = EXIT_NORETURN; + break; + default: + abort(); + } + + s->pc = s->next_pc; + return ret; + } + + /* Set up the strutures we use to communicate with the helpers. */ + s->insn = insn; + s->fields = &f; + o.g_out = o.g_out2 = o.g_in1 = o.g_in2 = false; + TCGV_UNUSED_I64(o.out); + TCGV_UNUSED_I64(o.out2); + TCGV_UNUSED_I64(o.in1); + TCGV_UNUSED_I64(o.in2); + TCGV_UNUSED_I64(o.addr1); + + /* Implement the instruction. */ + if (insn->help_in1) { + insn->help_in1(s, &f, &o); + } + if (insn->help_in2) { + insn->help_in2(s, &f, &o); + } + if (insn->help_prep) { + insn->help_prep(s, &f, &o); + } + if (insn->help_op) { + ret = insn->help_op(s, &o); + } + if (insn->help_wout) { + insn->help_wout(s, &f, &o); + } + if (insn->help_cout) { + insn->help_cout(s, &o); + } + + /* Free any temporaries created by the helpers. */ + if (!TCGV_IS_UNUSED_I64(o.out) && !o.g_out) { + tcg_temp_free_i64(o.out); + } + if (!TCGV_IS_UNUSED_I64(o.out2) && !o.g_out2) { + tcg_temp_free_i64(o.out2); + } + if (!TCGV_IS_UNUSED_I64(o.in1) && !o.g_in1) { + tcg_temp_free_i64(o.in1); + } + if (!TCGV_IS_UNUSED_I64(o.in2) && !o.g_in2) { + tcg_temp_free_i64(o.in2); + } + if (!TCGV_IS_UNUSED_I64(o.addr1)) { + tcg_temp_free_i64(o.addr1); + } + + /* Advance to the next instruction. */ + s->pc = s->next_pc; + return ret; } static inline void gen_intermediate_code_internal(CPUS390XState *env, @@ -5147,6 +5515,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, int j, lj = -1; int num_insns, max_insns; CPUBreakpoint *bp; + ExitStatus status; pc_start = tb->pc; @@ -5155,10 +5524,11 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, pc_start &= 0x7fffffff; } - dc.pc = pc_start; - dc.is_jmp = DISAS_NEXT; dc.tb = tb; + dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; + dc.singlestep_enabled = env->singlestep_enabled; + dc.is_jmp = DISAS_NEXT; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -5194,7 +5564,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_ctx.gen_opc_instr_start[lj] = 1; tcg_ctx.gen_opc_icount[lj] = num_insns; } - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + if (++num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); } @@ -5202,36 +5572,50 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_gen_debug_insn_start(dc.pc); } - disas_s390_insn(env, &dc); + status = translate_one(env, &dc); - num_insns++; - if (env->singlestep_enabled) { - gen_debug(&dc); + /* If we reach a page boundary, are single stepping, + or exhaust instruction count, stop generation. */ + if (status == NO_EXIT + && (dc.pc >= next_page_start + || tcg_ctx.gen_opc_ptr >= gen_opc_end + || num_insns >= max_insns + || singlestep + || env->singlestep_enabled)) { + status = EXIT_PC_STALE; } - } while (!dc.is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end - && dc.pc < next_page_start - && num_insns < max_insns && !env->singlestep_enabled - && !singlestep); - - if (!dc.is_jmp) { - update_psw_addr(&dc); - } - - if (singlestep && dc.cc_op != CC_OP_DYNAMIC) { - gen_op_calc_cc(&dc); - } else { - /* next TB starts off with CC_OP_DYNAMIC, so make sure the cc op type - is in env */ - gen_op_set_cc_op(&dc); - } + } while (status == NO_EXIT); if (tb->cflags & CF_LAST_IO) { gen_io_end(); } - /* Generate the return instruction */ - if (dc.is_jmp != DISAS_TB_JUMP) { - tcg_gen_exit_tb(0); + + switch (status) { + case EXIT_GOTO_TB: + case EXIT_NORETURN: + break; + case EXIT_PC_STALE: + update_psw_addr(&dc); + /* FALLTHRU */ + case EXIT_PC_UPDATED: + if (singlestep && dc.cc_op != CC_OP_DYNAMIC) { + gen_op_calc_cc(&dc); + } else { + /* Next TB starts off with CC_OP_DYNAMIC, + so make sure the cc op type is in env */ + gen_op_set_cc_op(&dc); + } + if (env->singlestep_enabled) { + gen_debug(&dc); + } else { + /* Generate the return instruction */ + tcg_gen_exit_tb(0); + } + break; + default: + abort(); } + gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { @@ -5244,6 +5628,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tb->size = dc.pc - pc_start; tb->icount = num_insns; } + #if defined(S390X_DEBUG_DISAS) if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("IN: %s\n", lookup_symbol(pc_start)); From 3fde06f5fb67dd9e5373b8105318e74e18eec895 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 13:31:01 -0700 Subject: [PATCH 012/149] target-s390: Split out disas_jcc Lots of duplicated code replaced with a couple of tables. We no longer attempt to manually invert the logic operation: the comments now match the code. In the fully general test, constant propagate (1 << (3 - cc)) into (8 >> cc). The new function will be usable by non-branch insns as well. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 618 ++++++++++++++++++--------------------- 1 file changed, 277 insertions(+), 341 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 92d49e1c6f..6761889e1f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -58,6 +58,18 @@ struct DisasContext { int is_jmp; }; +/* Information carried about a condition to be evaluated. */ +typedef struct { + TCGCond cond:8; + bool is_64; + bool g1; + bool g2; + union { + struct { TCGv_i64 a, b; } s64; + struct { TCGv_i32 a, b; } s32; + } u; +} DisasCompare; + #define DISAS_EXCP 4 static void gen_op_calc_cc(DisasContext *s); @@ -840,357 +852,281 @@ static inline void account_noninline_branch(DisasContext *s, int cc_op) #endif } -static inline void account_inline_branch(DisasContext *s) +static inline void account_inline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES - inline_branch_hit[s->cc_op]++; + inline_branch_hit[cc_op]++; #endif } +/* Table of mask values to comparison codes, given a comparison as input. + For a true comparison CC=3 will never be set, but we treat this + conservatively for possible use when CC=3 indicates overflow. */ +static const TCGCond ltgt_cond[16] = { + TCG_COND_NEVER, TCG_COND_NEVER, /* | | | x */ + TCG_COND_GT, TCG_COND_NEVER, /* | | GT | x */ + TCG_COND_LT, TCG_COND_NEVER, /* | LT | | x */ + TCG_COND_NE, TCG_COND_NEVER, /* | LT | GT | x */ + TCG_COND_EQ, TCG_COND_NEVER, /* EQ | | | x */ + TCG_COND_GE, TCG_COND_NEVER, /* EQ | | GT | x */ + TCG_COND_LE, TCG_COND_NEVER, /* EQ | LT | | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | LT | GT | x */ +}; + +/* Table of mask values to comparison codes, given a logic op as input. + For such, only CC=0 and CC=1 should be possible. */ +static const TCGCond nz_cond[16] = { + /* | | x | x */ + TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, + /* | NE | x | x */ + TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, + /* EQ | | x | x */ + TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, + /* EQ | NE | x | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, +}; + +/* Interpret MASK in terms of S->CC_OP, and fill in C with all the + details required to generate a TCG comparison. */ +static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) +{ + TCGCond cond; + enum cc_op old_cc_op = s->cc_op; + + if (mask == 15 || mask == 0) { + c->cond = (mask ? TCG_COND_ALWAYS : TCG_COND_NEVER); + c->u.s32.a = cc_op; + c->u.s32.b = cc_op; + c->g1 = c->g2 = true; + c->is_64 = false; + return; + } + + /* Find the TCG condition for the mask + cc op. */ + switch (old_cc_op) { + case CC_OP_LTGT0_32: + case CC_OP_LTGT0_64: + case CC_OP_LTGT_32: + case CC_OP_LTGT_64: + cond = ltgt_cond[mask]; + if (cond == TCG_COND_NEVER) { + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_LTUGTU_32: + case CC_OP_LTUGTU_64: + cond = tcg_unsigned_cond(ltgt_cond[mask]); + if (cond == TCG_COND_NEVER) { + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_NZ: + cond = nz_cond[mask]; + if (cond == TCG_COND_NEVER) { + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_TM_32: + case CC_OP_TM_64: + switch (mask) { + case 8: + cond = TCG_COND_EQ; + break; + case 4 | 2 | 1: + cond = TCG_COND_NE; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_ICM: + switch (mask) { + case 8: + cond = TCG_COND_EQ; + break; + case 4 | 2 | 1: + case 4 | 2: + cond = TCG_COND_NE; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + default: + do_dynamic: + /* Calculate cc value. */ + gen_op_calc_cc(s); + /* FALLTHRU */ + + case CC_OP_STATIC: + /* Jump based on CC. We'll load up the real cond below; + the assignment here merely avoids a compiler warning. */ + account_noninline_branch(s, old_cc_op); + old_cc_op = CC_OP_STATIC; + cond = TCG_COND_NEVER; + break; + } + + /* Load up the arguments of the comparison. */ + c->is_64 = true; + c->g1 = c->g2 = false; + switch (old_cc_op) { + case CC_OP_LTGT0_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_dst); + c->u.s32.b = tcg_const_i32(0); + break; + case CC_OP_LTGT_32: + case CC_OP_LTUGTU_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_src); + c->u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.b, cc_dst); + break; + + case CC_OP_LTGT0_64: + case CC_OP_NZ: + case CC_OP_ICM: + c->u.s64.a = cc_dst; + c->u.s64.b = tcg_const_i64(0); + c->g1 = true; + break; + case CC_OP_LTGT_64: + case CC_OP_LTUGTU_64: + c->u.s64.a = cc_src; + c->u.s64.b = cc_dst; + c->g1 = c->g2 = true; + break; + + case CC_OP_TM_32: + case CC_OP_TM_64: + c->u.s64.a = tcg_temp_new_i64(); + c->u.s64.b = tcg_const_i64(0); + tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); + break; + + case CC_OP_STATIC: + c->is_64 = false; + c->u.s32.a = cc_op; + c->g1 = true; + switch (mask) { + case 0x8 | 0x4 | 0x2: /* cc != 3 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(3); + break; + case 0x8 | 0x4 | 0x1: /* cc != 2 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(2); + break; + case 0x8 | 0x2 | 0x1: /* cc != 1 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(1); + break; + case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */ + cond = TCG_COND_EQ; + c->g1 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_andi_i32(c->u.s32.a, cc_op, 1); + break; + case 0x8 | 0x4: /* cc < 2 */ + cond = TCG_COND_LTU; + c->u.s32.b = tcg_const_i32(2); + break; + case 0x8: /* cc == 0 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(0); + break; + case 0x4 | 0x2 | 0x1: /* cc != 0 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(0); + break; + case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */ + cond = TCG_COND_NE; + c->g1 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_andi_i32(c->u.s32.a, cc_op, 1); + break; + case 0x4: /* cc == 1 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(1); + break; + case 0x2 | 0x1: /* cc > 1 */ + cond = TCG_COND_GTU; + c->u.s32.b = tcg_const_i32(1); + break; + case 0x2: /* cc == 2 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(2); + break; + case 0x1: /* cc == 3 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(3); + break; + default: + /* CC is masked by something else: (8 >> cc) & mask. */ + cond = TCG_COND_NE; + c->g1 = false; + c->u.s32.a = tcg_const_i32(8); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_shr_i32(c->u.s32.a, c->u.s32.a, cc_op); + tcg_gen_andi_i32(c->u.s32.a, c->u.s32.a, mask); + break; + } + break; + + default: + abort(); + } + c->cond = cond; +} + +static void free_compare(DisasCompare *c) +{ + if (!c->g1) { + if (c->is_64) { + tcg_temp_free_i64(c->u.s64.a); + } else { + tcg_temp_free_i32(c->u.s32.a); + } + } + if (!c->g2) { + if (c->is_64) { + tcg_temp_free_i64(c->u.s64.b); + } else { + tcg_temp_free_i32(c->u.s32.b); + } + } +} + static void gen_jcc(DisasContext *s, uint32_t mask, int skip) { - TCGv_i32 tmp, tmp2, r; - TCGv_i64 tmp64; - int old_cc_op; + DisasCompare c; + TCGCond cond; - switch (s->cc_op) { - case CC_OP_LTGT0_32: - tmp = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* dst <= 0 */ - tcg_gen_brcondi_i32(TCG_COND_GT, tmp, 0, skip); - break; - case 0x8 | 0x2: /* dst >= 0 */ - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, skip); - break; - case 0x8: /* dst == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - break; - case 0x7: /* dst != 0 */ - case 0x6: /* dst != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - break; - case 0x4: /* dst < 0 */ - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, skip); - break; - case 0x2: /* dst > 0 */ - tcg_gen_brcondi_i32(TCG_COND_LE, tmp, 0, skip); - break; - default: - tcg_temp_free_i32(tmp); - goto do_dynamic; - } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - break; - case CC_OP_LTGT0_64: - switch (mask) { - case 0x8 | 0x4: /* dst <= 0 */ - tcg_gen_brcondi_i64(TCG_COND_GT, cc_dst, 0, skip); - break; - case 0x8 | 0x2: /* dst >= 0 */ - tcg_gen_brcondi_i64(TCG_COND_LT, cc_dst, 0, skip); - break; - case 0x8: /* dst == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); - break; - case 0x7: /* dst != 0 */ - case 0x6: /* dst != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); - break; - case 0x4: /* dst < 0 */ - tcg_gen_brcondi_i64(TCG_COND_GE, cc_dst, 0, skip); - break; - case 0x2: /* dst > 0 */ - tcg_gen_brcondi_i64(TCG_COND_LE, cc_dst, 0, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_LTGT_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i32(TCG_COND_GT, tmp, tmp2, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i32(TCG_COND_LT, tmp, tmp2, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i32(TCG_COND_GE, tmp, tmp2, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i32(TCG_COND_LE, tmp, tmp2, skip); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto do_dynamic; - } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - break; - case CC_OP_LTGT_64: - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i64(TCG_COND_GT, cc_src, cc_dst, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i64(TCG_COND_LT, cc_src, cc_dst, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i64(TCG_COND_GE, cc_src, cc_dst, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i64(TCG_COND_LE, cc_src, cc_dst, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_LTUGTU_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i32(TCG_COND_GTU, tmp, tmp2, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i32(TCG_COND_LTU, tmp, tmp2, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i32(TCG_COND_GEU, tmp, tmp2, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i32(TCG_COND_LEU, tmp, tmp2, skip); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto do_dynamic; - } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - break; - case CC_OP_LTUGTU_64: - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i64(TCG_COND_GTU, cc_src, cc_dst, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i64(TCG_COND_LTU, cc_src, cc_dst, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i64(TCG_COND_GEU, cc_src, cc_dst, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i64(TCG_COND_LEU, cc_src, cc_dst, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_NZ: - switch (mask) { - /* dst == 0 || dst != 0 */ - case 0x8 | 0x4: - case 0x8 | 0x4 | 0x2: - case 0x8 | 0x4 | 0x2 | 0x1: - case 0x8 | 0x4 | 0x1: - break; - /* dst == 0 */ - case 0x8: - case 0x8 | 0x2: - case 0x8 | 0x2 | 0x1: - case 0x8 | 0x1: - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); - break; - /* dst != 0 */ - case 0x4: - case 0x4 | 0x2: - case 0x4 | 0x2 | 0x1: - case 0x4 | 0x1: - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_TM_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); + disas_jcc(s, &c, mask); + cond = tcg_invert_cond(c.cond); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - tcg_gen_and_i32(tmp, tmp, tmp2); - switch (mask) { - case 0x8: /* val & mask == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* val & mask != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto do_dynamic; - } - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - account_inline_branch(s); - break; - case CC_OP_TM_64: - tmp64 = tcg_temp_new_i64(); - - tcg_gen_and_i64(tmp64, cc_src, cc_dst); - switch (mask) { - case 0x8: /* val & mask == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, tmp64, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* val & mask != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, tmp64, 0, skip); - break; - default: - tcg_temp_free_i64(tmp64); - goto do_dynamic; - } - tcg_temp_free_i64(tmp64); - account_inline_branch(s); - break; - case CC_OP_ICM: - switch (mask) { - case 0x8: /* val == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* val != 0 */ - case 0x4 | 0x2: /* val != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_STATIC: - old_cc_op = s->cc_op; - goto do_dynamic_nocccalc; - case CC_OP_DYNAMIC: - default: -do_dynamic: - old_cc_op = s->cc_op; - /* calculate cc value */ - gen_op_calc_cc(s); - -do_dynamic_nocccalc: - /* jump based on cc */ - account_noninline_branch(s, old_cc_op); - - switch (mask) { - case 0x8 | 0x4 | 0x2 | 0x1: - /* always true */ - break; - case 0x8 | 0x4 | 0x2: /* cc != 3 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 3, skip); - break; - case 0x8 | 0x4 | 0x1: /* cc != 2 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 2, skip); - break; - case 0x8 | 0x2 | 0x1: /* cc != 1 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 1, skip); - break; - case 0x8 | 0x2: /* cc == 0 || cc == 2 */ - tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cc_op, 1); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - tcg_temp_free_i32(tmp); - break; - case 0x8 | 0x4: /* cc < 2 */ - tcg_gen_brcondi_i32(TCG_COND_GEU, cc_op, 2, skip); - break; - case 0x8: /* cc == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* cc != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 0, skip); - break; - case 0x4 | 0x1: /* cc == 1 || cc == 3 */ - tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cc_op, 1); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - tcg_temp_free_i32(tmp); - break; - case 0x4: /* cc == 1 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 1, skip); - break; - case 0x2 | 0x1: /* cc > 1 */ - tcg_gen_brcondi_i32(TCG_COND_LEU, cc_op, 1, skip); - break; - case 0x2: /* cc == 2 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 2, skip); - break; - case 0x1: /* cc == 3 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 3, skip); - break; - default: /* cc is masked by something else */ - tmp = tcg_const_i32(3); - /* 3 - cc */ - tcg_gen_sub_i32(tmp, tmp, cc_op); - tmp2 = tcg_const_i32(1); - /* 1 << (3 - cc) */ - tcg_gen_shl_i32(tmp2, tmp2, tmp); - r = tcg_const_i32(mask); - /* mask & (1 << (3 - cc)) */ - tcg_gen_and_i32(r, r, tmp2); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - - tcg_gen_brcondi_i32(TCG_COND_EQ, r, 0, skip); - tcg_temp_free_i32(r); - break; - } - break; + if (c.is_64) { + tcg_gen_brcond_i64(cond, c.u.s64.a, c.u.s64.b, skip); + } else { + tcg_gen_brcond_i32(cond, c.u.s32.a, c.u.s32.b, skip); } + + free_compare(&c); } static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, From d5a103cd6eb3b407feb4e007cb778a89b1b20c5f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Sep 2012 19:31:57 -0700 Subject: [PATCH 013/149] target-s390: Reorg exception handling Make the user path more like the system path. Prepare for more kinds of runtime exceptions. Rename ILC to ILEN to make it clear that we want to pass around a full instruction length, rather than a "code" that happens to be stored one bit left in a larger field. Signed-off-by: Richard Henderson --- linux-user/main.c | 142 ++++++++++++++-------- linux-user/s390x/syscall.h | 2 +- target-s390x/cpu.h | 49 ++++---- target-s390x/helper.c | 58 +++++---- target-s390x/mem_helper.c | 2 +- target-s390x/misc_helper.c | 8 +- target-s390x/translate.c | 242 ++++++++++++++----------------------- 7 files changed, 242 insertions(+), 261 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index f6c4c8d7a3..15bacb9a30 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2933,71 +2933,115 @@ void cpu_loop(CPUAlphaState *env) #ifdef TARGET_S390X void cpu_loop(CPUS390XState *env) { - int trapnr; + int trapnr, n, sig; target_siginfo_t info; + target_ulong addr; while (1) { - trapnr = cpu_s390x_exec (env); - + trapnr = cpu_s390x_exec(env); switch (trapnr) { case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ + /* Just indicate that signals should be handled asap. */ break; - case EXCP_DEBUG: - { - int sig; - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } - } - break; case EXCP_SVC: - { - int n = env->int_svc_code; - if (!n) { - /* syscalls > 255 */ - n = env->regs[1]; - } - env->psw.addr += env->int_svc_ilc; - env->regs[2] = do_syscall(env, n, - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5], - env->regs[6], - env->regs[7], - 0, 0); + n = env->int_svc_code; + if (!n) { + /* syscalls > 255 */ + n = env->regs[1]; + } + env->psw.addr += env->int_svc_ilen; + env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3], + env->regs[4], env->regs[5], + env->regs[6], env->regs[7], 0, 0); + break; + + case EXCP_DEBUG: + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { + n = TARGET_TRAP_BRKPT; + goto do_signal_pc; } break; - case EXCP_ADDR: - { - info.si_signo = SIGSEGV; - info.si_errno = 0; + case EXCP_PGM: + n = env->int_pgm_code; + switch (n) { + case PGM_OPERATION: + case PGM_PRIVILEGED: + sig = SIGILL; + n = TARGET_ILL_ILLOPC; + goto do_signal_pc; + case PGM_PROTECTION: + case PGM_ADDRESSING: + sig = SIGSEGV; /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); + n = TARGET_SEGV_MAPERR; + addr = env->__excp_addr; + goto do_signal; + case PGM_EXECUTE: + case PGM_SPECIFICATION: + case PGM_SPECIAL_OP: + case PGM_OPERAND: + do_sigill_opn: + sig = SIGILL; + n = TARGET_ILL_ILLOPN; + goto do_signal_pc; + + case PGM_FIXPT_OVERFLOW: + sig = SIGFPE; + n = TARGET_FPE_INTOVF; + goto do_signal_pc; + case PGM_FIXPT_DIVIDE: + sig = SIGFPE; + n = TARGET_FPE_INTDIV; + goto do_signal_pc; + + case PGM_DATA: + n = (env->fpc >> 8) & 0xff; + if (n == 0xff) { + /* compare-and-trap */ + goto do_sigill_opn; + } else { + /* An IEEE exception, simulated or otherwise. */ + if (n & 0x80) { + n = TARGET_FPE_FLTINV; + } else if (n & 0x40) { + n = TARGET_FPE_FLTDIV; + } else if (n & 0x20) { + n = TARGET_FPE_FLTOVF; + } else if (n & 0x10) { + n = TARGET_FPE_FLTUND; + } else if (n & 0x08) { + n = TARGET_FPE_FLTRES; + } else { + /* ??? Quantum exception; BFP, DFP error. */ + goto do_sigill_opn; + } + sig = SIGFPE; + goto do_signal_pc; + } + + default: + fprintf(stderr, "Unhandled program exception: %#x\n", n); + cpu_dump_state(env, stderr, fprintf, 0); + exit(1); } break; - case EXCP_SPEC: - { - fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPC; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); - } + + do_signal_pc: + addr = env->psw.addr; + do_signal: + info.si_signo = sig; + info.si_errno = 0; + info.si_code = n; + info._sifields._sigfault._addr = addr; + queue_signal(env, info.si_signo, &info); break; + default: - printf ("Unhandled trap: 0x%x\n", trapnr); + fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); - exit (1); + exit(1); } process_pending_signals (env); } diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index c2ea151ea5..e4603b79c3 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -16,7 +16,7 @@ struct target_pt_regs { target_psw_t psw; abi_ulong gprs[TARGET_NUM_GPRS]; abi_ulong orig_gpr2; - unsigned short ilc; + unsigned short ilen; unsigned short trap; }; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 529716de47..83e618ab0e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -79,10 +79,10 @@ typedef struct CPUS390XState { uint64_t psa; uint32_t int_pgm_code; - uint32_t int_pgm_ilc; + uint32_t int_pgm_ilen; uint32_t int_svc_code; - uint32_t int_svc_ilc; + uint32_t int_svc_ilen; uint64_t cregs[16]; /* control registers */ @@ -253,25 +253,31 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); } -static inline int get_ilc(uint8_t opc) +/* While the PoO talks about ILC (a number between 1-3) what is actually + stored in LowCore is shifted left one bit (an even between 2-6). As + this is the actual length of the insn and therefore more useful, that + is what we want to pass around and manipulate. To make sure that we + have applied this distinction universally, rename the "ILC" to "ILEN". */ +static inline int get_ilen(uint8_t opc) { switch (opc >> 6) { case 0: - return 1; + return 2; case 1: case 2: - return 2; - case 3: - return 3; + return 4; + default: + return 6; } - - return 0; } -#define ILC_LATER 0x20 -#define ILC_LATER_INC 0x21 -#define ILC_LATER_INC_2 0x22 - +#ifndef CONFIG_USER_ONLY +/* In several cases of runtime exceptions, we havn't recorded the true + instruction length. Use these codes when raising exceptions in order + to re-compute the length by examining the insn in memory. */ +#define ILEN_LATER 0x20 +#define ILEN_LATER_INC 0x21 +#endif S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); @@ -352,21 +358,10 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) #include "exec/exec-all.h" -#ifdef CONFIG_USER_ONLY - -#define EXCP_OPEX 1 /* operation exception (sigill) */ -#define EXCP_SVC 2 /* supervisor call (syscall) */ -#define EXCP_ADDR 5 /* addressing exception */ -#define EXCP_SPEC 6 /* specification exception */ - -#else - #define EXCP_EXT 1 /* external interrupt */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_PGM 3 /* program interruption */ -#endif /* CONFIG_USER_ONLY */ - #define INTERRUPT_EXT (1 << 0) #define INTERRUPT_TOD (1 << 1) #define INTERRUPT_CPUTIMER (1 << 2) @@ -532,9 +527,9 @@ typedef struct LowCore uint32_t ext_params; /* 0x080 */ uint16_t cpu_addr; /* 0x084 */ uint16_t ext_int_code; /* 0x086 */ - uint16_t svc_ilc; /* 0x088 */ + uint16_t svc_ilen; /* 0x088 */ uint16_t svc_code; /* 0x08a */ - uint16_t pgm_ilc; /* 0x08c */ + uint16_t pgm_ilen; /* 0x08c */ uint16_t pgm_code; /* 0x08e */ uint32_t data_exc_code; /* 0x090 */ uint16_t mon_class_num; /* 0x094 */ @@ -924,6 +919,6 @@ uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); /* misc_helper.c */ -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); #endif diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 7dc4d46eac..9a132e6d2c 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -99,10 +99,10 @@ void do_interrupt(CPUS390XState *env) int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, int rw, int mmu_idx) { - /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", - __func__, address, rw, mmu_idx); */ - env->exception_index = EXCP_ADDR; - /* FIXME: find out how this works on a real machine */ + env->exception_index = EXCP_PGM; + env->int_pgm_code = PGM_ADDRESSING; + /* On real machines this value is dropped into LowMem. Since this + is userland, simply put this someplace that cpu_loop can find it. */ env->__excp_addr = address; return 1; } @@ -111,11 +111,11 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, /* Ensure to exit the TB after this call! */ static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, - uint32_t ilc) + uint32_t ilen) { env->exception_index = EXCP_PGM; env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; } static int trans_bits(CPUS390XState *env, uint64_t mode) @@ -143,30 +143,30 @@ static int trans_bits(CPUS390XState *env, uint64_t mode) static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode) { - int ilc = ILC_LATER_INC_2; + int ilen = ILEN_LATER_INC; int bits = trans_bits(env, mode) | 4; DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, PGM_PROTECTION, ilc); + trigger_pgm_exception(env, PGM_PROTECTION, ilen); } static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, uint64_t asc, int rw) { - int ilc = ILC_LATER; + int ilen = ILEN_LATER; int bits = trans_bits(env, asc); + /* Code accesses have an undefined ilc. */ if (rw == 2) { - /* code has is undefined ilc */ - ilc = 2; + ilen = 2; } DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, type, ilc); + trigger_pgm_exception(env, type, ilen); } static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, @@ -406,7 +406,7 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, if (raddr > (ram_size + virtio_size)) { DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)aaddr, (uint64_t)ram_size); - trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER); + trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); return 1; } @@ -480,9 +480,9 @@ static void do_svc_interrupt(CPUS390XState *env) lowcore = cpu_physical_memory_map(env->psa, &len, 1); lowcore->svc_code = cpu_to_be16(env->int_svc_code); - lowcore->svc_ilc = cpu_to_be16(env->int_svc_ilc); + lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); - lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + (env->int_svc_ilc)); + lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); mask = be64_to_cpu(lowcore->svc_new_psw.mask); addr = be64_to_cpu(lowcore->svc_new_psw.addr); @@ -496,28 +496,26 @@ static void do_program_interrupt(CPUS390XState *env) uint64_t mask, addr; LowCore *lowcore; hwaddr len = TARGET_PAGE_SIZE; - int ilc = env->int_pgm_ilc; + int ilen = env->int_pgm_ilen; - switch (ilc) { - case ILC_LATER: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); + switch (ilen) { + case ILEN_LATER: + ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); break; - case ILC_LATER_INC: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); - env->psw.addr += ilc * 2; - break; - case ILC_LATER_INC_2: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2; - env->psw.addr += ilc; + case ILEN_LATER_INC: + ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); + env->psw.addr += ilen; break; + default: + assert(ilen == 2 || ilen == 4 || ilen == 6); } - qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilc=%d\n", - __func__, env->int_pgm_code, ilc); + qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", + __func__, env->int_pgm_code, ilen); lowcore = cpu_physical_memory_map(env->psa, &len, 1); - lowcore->pgm_ilc = cpu_to_be16(ilc); + lowcore->pgm_ilen = cpu_to_be16(ilen); lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); @@ -527,7 +525,7 @@ static void do_program_interrupt(CPUS390XState *env) cpu_physical_memory_unmap(lowcore, len, 1, len); DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, - env->int_pgm_code, ilc, env->psw.mask, + env->int_pgm_code, ilen, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index bed21e6e1c..7eb3790b40 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -594,7 +594,7 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); env->psw.addr = ret - 4; env->int_svc_code = (insn | v1) & 0xff; - env->int_svc_ilc = 4; + env->int_svc_ilen = 4; helper_exception(env, EXCP_SVC); } else if ((insn & 0xff00) == 0xbf00) { uint32_t insn2, r1, r3, b2, d2; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 70f9739685..2aa1ed0b5e 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -41,7 +41,7 @@ #define HELPER_LOG(x...) #endif -/* raise an exception */ +/* Raise an exception statically from a TB. */ void HELPER(exception)(CPUS390XState *env, uint32_t excp) { HELPER_LOG("%s: exception %d\n", __func__, excp); @@ -50,7 +50,7 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) } #ifndef CONFIG_USER_ONLY -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) { qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", env->psw.addr); @@ -61,7 +61,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) #endif } else { env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; env->exception_index = EXCP_PGM; cpu_loop_exit(env); } @@ -105,7 +105,7 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, } if (r) { - program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); + program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); } return r; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6761889e1f..076bb7f5fe 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -18,7 +18,6 @@ * License along with this library; if not, see . */ -/* #define DEBUG_ILLEGAL_INSTRUCTIONS */ /* #define DEBUG_INLINE_BRANCHES */ #define S390X_DEBUG_DISAS /* #define S390X_DEBUG_DISAS_VERBOSE */ @@ -338,105 +337,52 @@ static inline int get_mem_index(DisasContext *s) } } -static inline void gen_debug(DisasContext *s) +static void gen_exception(int excp) { - TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); - update_psw_addr(s); - gen_op_calc_cc(s); + TCGv_i32 tmp = tcg_const_i32(excp); gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; } -#ifdef CONFIG_USER_ONLY - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) -{ - TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; -} - -#else /* CONFIG_USER_ONLY */ - -static void debug_print_inst(CPUS390XState *env, DisasContext *s, int ilc) -{ -#ifdef DEBUG_ILLEGAL_INSTRUCTIONS - uint64_t inst = 0; - - switch (ilc & 3) { - case 1: - inst = ld_code2(env, s->pc); - break; - case 2: - inst = ld_code4(env, s->pc); - break; - case 3: - inst = ld_code6(env, s->pc); - break; - } - - fprintf(stderr, "Illegal instruction [%d at %016" PRIx64 "]: 0x%016" - PRIx64 "\n", ilc, s->pc, inst); -#endif -} - -static void gen_program_exception(CPUS390XState *env, DisasContext *s, int ilc, - int code) +static void gen_program_exception(DisasContext *s, int code) { TCGv_i32 tmp; - debug_print_inst(env, s, ilc); - - /* remember what pgm exeption this was */ + /* Remember what pgm exeption this was. */ tmp = tcg_const_i32(code); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_temp_free_i32(tmp); - tmp = tcg_const_i32(ilc); - tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilc)); + tmp = tcg_const_i32(s->next_pc - s->pc); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen)); tcg_temp_free_i32(tmp); - /* advance past instruction */ - s->pc += (ilc * 2); + /* Advance past instruction. */ + s->pc = s->next_pc; update_psw_addr(s); - /* save off cc */ + /* Save off cc. */ gen_op_calc_cc(s); - /* trigger exception */ - tmp = tcg_const_i32(EXCP_PGM); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + /* Trigger exception. */ + gen_exception(EXCP_PGM); - /* end TB here */ + /* End TB here. */ s->is_jmp = DISAS_EXCP; } - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) +static inline void gen_illegal_opcode(DisasContext *s) { - gen_program_exception(env, s, ilc, PGM_SPECIFICATION); + gen_program_exception(s, PGM_SPECIFICATION); } -static void gen_privileged_exception(CPUS390XState *env, DisasContext *s, - int ilc) -{ - gen_program_exception(env, s, ilc, PGM_PRIVILEGED); -} - -static void check_privileged(CPUS390XState *env, DisasContext *s, int ilc) +static inline void check_privileged(DisasContext *s) { if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) { - gen_privileged_exception(env, s, ilc); + gen_program_exception(s, PGM_PRIVILEGED); } } -#endif /* CONFIG_USER_ONLY */ - static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { TCGv_i64 tmp; @@ -1769,7 +1715,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } tcg_temp_free_i64(addr); @@ -1794,7 +1740,7 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) break; default: LOG_DISAS("illegal e5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } @@ -1809,7 +1755,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, TCGv_i64 tmp, tmp2, tmp3, tmp4; TCGv_i32 tmp32_1, tmp32_2; int i, stm_len; - int ilc = 3; LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); @@ -1947,7 +1892,7 @@ do_mh: #ifndef CONFIG_USER_ONLY case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ /* Load Control */ - check_privileged(env, s, ilc); + check_privileged(s); tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); @@ -1959,7 +1904,7 @@ do_mh: break; case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ /* Store Control */ - check_privileged(env, s, ilc); + check_privileged(s); tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); @@ -2036,7 +1981,7 @@ do_mh: break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -2156,7 +2101,7 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal ed operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); return; } tcg_temp_free_i32(tmp_r1); @@ -2313,7 +2258,7 @@ static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal a5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); return; } } @@ -2451,7 +2396,7 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); return; } } @@ -2462,7 +2407,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, TCGv_i64 tmp, tmp2, tmp3; TCGv_i32 tmp32_1, tmp32_2, tmp32_3; int r1, r2; - int ilc = 2; #ifndef CONFIG_USER_ONLY int r3, d2, b2; #endif @@ -2556,7 +2500,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, #ifndef CONFIG_USER_ONLY case 0x02: /* STIDP D2(B2) [S] */ /* Store CPU ID */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2565,7 +2509,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x04: /* SCK D2(B2) [S] */ /* Set Clock */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2584,7 +2528,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x06: /* SCKC D2(B2) [S] */ /* Set Clock Comparator */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2593,7 +2537,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x07: /* STCKC D2(B2) [S] */ /* Store Clock Comparator */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2602,7 +2546,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x08: /* SPT D2(B2) [S] */ /* Set CPU Timer */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2611,7 +2555,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x09: /* STPT D2(B2) [S] */ /* Store CPU Timer */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2620,7 +2564,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x0a: /* SPKA D2(B2) [S] */ /* Set PSW Key from Address */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2632,12 +2576,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x0d: /* PTLB [S] */ /* Purge TLB */ - check_privileged(env, s, ilc); + check_privileged(s); gen_helper_ptlb(cpu_env); break; case 0x10: /* SPX D2(B2) [S] */ /* Set Prefix Register */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2646,7 +2590,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x11: /* STPX D2(B2) [S] */ /* Store Prefix */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2657,7 +2601,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x12: /* STAP D2(B2) [S] */ /* Store CPU Address */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2671,7 +2615,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x21: /* IPTE R1,R2 [RRE] */ /* Invalidate PTE */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp = load_reg(r1); @@ -2682,7 +2626,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x29: /* ISKE R1,R2 [RRE] */ /* Insert Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp = load_reg(r2); @@ -2694,7 +2638,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x2a: /* RRBE R1,R2 [RRE] */ /* Set Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2706,7 +2650,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x2b: /* SSKE R1,R2 [RRE] */ /* Set Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2717,12 +2661,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x34: /* STCH ? */ /* Store Subchannel */ - check_privileged(env, s, ilc); + check_privileged(s); gen_op_movi_cc(s, 3); break; case 0x46: /* STURA R1,R2 [RRE] */ /* Store Using Real Address */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2734,7 +2678,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x50: /* CSP R1,R2 [RRE] */ /* Compare And Swap And Purge */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = tcg_const_i32(r1); @@ -2746,7 +2690,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x5f: /* CHSC ? */ /* Channel Subsystem Call */ - check_privileged(env, s, ilc); + check_privileged(s); gen_op_movi_cc(s, 3); break; case 0x78: /* STCKE D2(B2) [S] */ @@ -2760,19 +2704,19 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x79: /* SACF D2(B2) [S] */ /* Set Address Space Control Fast */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); gen_helper_sacf(cpu_env, tmp); tcg_temp_free_i64(tmp); /* addressing mode has changed, so end the block */ - s->pc += ilc * 2; + s->pc = s->next_pc; update_psw_addr(s); s->is_jmp = DISAS_JUMP; break; case 0x7d: /* STSI D2,(B2) [S] */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp32_1 = load_reg32(0); @@ -2798,7 +2742,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0xb1: /* STFL D2(B2) [S] */ /* Store Facility List (CPU features) at 200 */ - check_privileged(env, s, ilc); + check_privileged(s); tmp2 = tcg_const_i64(0xc0000000); tmp = tcg_const_i64(200); tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); @@ -2807,7 +2751,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0xb2: /* LPSWE D2(B2) [S] */ /* Load PSW Extended */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2824,7 +2768,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x20: /* SERVC R1,R2 [RRE] */ /* SCLP Service call (PV hypercall) */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); tmp32_1 = load_reg32(r2); tmp = load_reg(r1); @@ -2836,7 +2780,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, #endif default: LOG_DISAS("illegal b2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -3112,7 +3056,7 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, break; default: LOG_DISAS("illegal b3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); break; } @@ -3419,7 +3363,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal b9 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); break; } } @@ -3525,7 +3469,7 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } } @@ -3559,7 +3503,7 @@ static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal c2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } } @@ -3589,14 +3533,11 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; TCGv_i32 vl; - int ilc; int l1; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); - ilc = get_ilc(opc); - switch (opc) { #ifndef CONFIG_USER_ONLY case 0x01: /* SAM */ @@ -3649,15 +3590,13 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) update_psw_addr(s); gen_op_calc_cc(s); tmp32_1 = tcg_const_i32(i); - tmp32_2 = tcg_const_i32(ilc * 2); - tmp32_3 = tcg_const_i32(EXCP_SVC); + tmp32_2 = tcg_const_i32(s->next_pc - s->pc); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); - tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc)); - gen_helper_exception(cpu_env, tmp32_3); + tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); + gen_exception(EXCP_SVC); s->is_jmp = DISAS_EXCP; tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); break; case 0xd: /* BASR R1,R2 [RR] */ insn = ld_code2(env, s->pc); @@ -4148,7 +4087,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4164,7 +4103,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0x82: /* LPSW D2(B2) [S] */ /* Load PSW */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4184,7 +4123,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0x83: /* DIAG R1,R3,D2 [RS] */ /* Diagnose call (KVM hypercall) */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -4402,7 +4341,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xac: /* STNSM D1(B1),I2 [SI] */ case 0xad: /* STOSM D1(B1),I2 [SI] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); tmp = decode_si(s, insn, &i2, &b1, &d1); tmp2 = tcg_temp_new_i64(); @@ -4418,7 +4357,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); break; case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4432,7 +4371,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); break; case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); tmp32_1 = tcg_const_i32(r1); @@ -4476,7 +4415,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ /* Store Control */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4490,7 +4429,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ /* Load Control */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4674,7 +4613,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); insn = ld_code6(env, s->pc); r1 = (insn >> 36) & 0xf; @@ -4712,7 +4651,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xe5: /* Test Protection */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code6(env, s->pc); debug_insn(insn); disas_e5(env, s, insn); @@ -4742,7 +4681,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -5273,19 +5212,22 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, DisasFields *f) { uint64_t insn, pc = s->pc; - int op, op2; + int op, op2, ilen; const DisasInsn *info; insn = ld_code2(env, pc); op = (insn >> 8) & 0xff; - switch (get_ilc(op)) { - case 1: + ilen = get_ilen(op); + s->next_pc = s->pc + ilen; + + switch (ilen) { + case 2: insn = insn << 48; break; - case 2: + case 4: insn = ld_code4(env, pc) << 32; break; - case 3: + case 6: insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); break; default: @@ -5361,9 +5303,6 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) insn = extract_insn(env, s, &f); - /* Instruction length is encoded in the opcode */ - s->next_pc = s->pc + get_ilc(f.op) * 2; - /* If not found, try the old interpreter. This includes ILLOPC. */ if (insn == NULL) { disas_s390_insn(env, s); @@ -5452,6 +5391,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, int num_insns, max_insns; CPUBreakpoint *bp; ExitStatus status; + bool do_debug; pc_start = tb->pc; @@ -5463,7 +5403,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, dc.tb = tb; dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; - dc.singlestep_enabled = env->singlestep_enabled; + do_debug = dc.singlestep_enabled = env->singlestep_enabled; dc.is_jmp = DISAS_NEXT; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -5479,14 +5419,6 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, gen_icount_start(); do { - if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { - QTAILQ_FOREACH(bp, &env->breakpoints, entry) { - if (bp->pc == dc.pc) { - gen_debug(&dc); - break; - } - } - } if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { @@ -5508,7 +5440,19 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_gen_debug_insn_start(dc.pc); } - status = translate_one(env, &dc); + status = NO_EXIT; + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc.pc) { + status = EXIT_PC_STALE; + do_debug = true; + break; + } + } + } + if (status == NO_EXIT) { + status = translate_one(env, &dc); + } /* If we reach a page boundary, are single stepping, or exhaust instruction count, stop generation. */ @@ -5541,8 +5485,8 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, so make sure the cc op type is in env */ gen_op_set_cc_op(&dc); } - if (env->singlestep_enabled) { - gen_debug(&dc); + if (do_debug) { + gen_exception(EXCP_DEBUG); } else { /* Generate the return instruction */ tcg_gen_exit_tb(0); From d82287dee9d8bfe2c4cb520e30c76244fcbb705c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 16 Aug 2012 14:09:45 -0700 Subject: [PATCH 014/149] target-s390: Convert ADD HALFWORD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 43 +++++++------------------------------- 2 files changed, 14 insertions(+), 36 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7d81928350..2acc8f0539 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -15,6 +15,13 @@ C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64) C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) +/* ADD HALFWORD */ + C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32) + C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32) +/* ADD HALFWORD IMMEDIATE */ + C(0xa70a, AHI, RI_a, Z, r1, i2, new, r1_32, add, adds32) + C(0xa70b, AGHI, RI_a, Z, r1, i2, r1, 0, add, adds64) + /* ADD LOGICAL */ C(0x1e00, ALR, RR_a, Z, r1, r2, new, r1_32, add, addu32) C(0xb9fa, ALRK, RRF_a, DO, r2, r3, new, r1_32, add, addu32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 076bb7f5fe..0a916b1a3f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -559,11 +559,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_add64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_ADD_64, v1, v2, vr); -} - static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) { @@ -2267,7 +2262,7 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1; int l1; LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); @@ -2342,36 +2337,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0xa: /* AHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_const_i32(i2); - - if (i2 < 0) { - tcg_gen_subi_i32(tmp32_2, tmp32_1, -i2); - } else { - tcg_gen_add_i32(tmp32_2, tmp32_1, tmp32_3); - } - - store_reg32(r1, tmp32_2); - set_cc_add32(s, tmp32_1, tmp32_3, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xb: /* aghi r1, i2 */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64(i2); - - if (i2 < 0) { - tcg_gen_subi_i64(regs[r1], tmp, -i2); - } else { - tcg_gen_add_i64(regs[r1], tmp, tmp2); - } - set_cc_add64(s, tmp, tmp2, regs[r1]); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0xc: /* MHI R1,I2 [RI] */ tmp32_1 = load_reg32(r1); tcg_gen_muli_i32(tmp32_1, tmp32_1, i2); @@ -5078,6 +5043,12 @@ static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); } +static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s)); +} + static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From 3f4cb56a4351b0710f90d1205f2d6178a8ebc02f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 14:46:42 -0700 Subject: [PATCH 015/149] target-s390: Implement SUBTRACT HALFWORD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2acc8f0539..44e1ca7997 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -46,6 +46,9 @@ C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) +/* SUBTRACT HALFWORD */ + C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) + C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) /* SUBTRACT LOGICAL */ C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32) C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32) From e272b3ace35ffafe24754986b999bda19f56f373 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 16 Aug 2012 14:42:49 -0700 Subject: [PATCH 016/149] target-s390: Implement ADD LOGICAL WITH SIGNED IMMEDIATE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 44e1ca7997..acde181783 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -35,6 +35,11 @@ /* ADD LOGICAL IMMEDIATE */ C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32) C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64) +/* ADD LOGICAL WITH SIGNED IMMEDIATE */ + C(0xeb6e, ALSI, SIY, GIE, m1_32u, i2, new, m1_32, add, addu32) + C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) + C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) + C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0a916b1a3f..5d5856a114 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -5005,6 +5005,13 @@ static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s)); } +static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s)); +} + static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) { in1_la1(s, f, o); From d1c04a2ba05bec8567a52f28979288e2237dfe9c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Sep 2012 15:10:35 -0700 Subject: [PATCH 017/149] target-s390: Convert MULTIPLY HALFWORD, SINGLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 18 ++++++ target-s390x/translate.c | 121 ++++++------------------------------- 2 files changed, 36 insertions(+), 103 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index acde181783..055113a073 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -41,6 +41,24 @@ C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* MULTIPLY HALFWORD */ + C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) + C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) +/* MULTIPLY HALFWORD IMMEDIATE */ + C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) + C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY SINGLE */ + C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) + C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xe351, MSY, RXY_a, LD, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xb90c, MSGR, RRE, Z, r1_o, r2_o, r1, 0, mul, 0) + C(0xb91c, MSGFR, RRE, Z, r1_o, r2_32s, r1, 0, mul, 0) + C(0xe30c, MSG, RXY_a, Z, r1_o, m2_64, r1, 0, mul, 0) + C(0xe31c, MSGF, RXY_a, Z, r1_o, m2_32s, r1, 0, mul, 0) +/* MULTIPLY SINGLE IMMEDIATE */ + C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) + C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5d5856a114..f09b7d19aa 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -575,22 +575,12 @@ static void set_cc_nabs64(DisasContext *s, TCGv_i64 v1) gen_op_update1_cc_i64(s, CC_OP_NABS_64, v1); } -static void set_cc_add32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_ADD_32, v1, v2, vr); -} - static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) { gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr); } -static void set_cc_sub32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_SUB_32, v1, v2, vr); -} - static void set_cc_abs32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1); @@ -1371,17 +1361,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0xc: /* MSG R1,D2(X2,B2) [RXY] */ - case 0x1c: /* MSGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0xc) { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } - tcg_gen_mul_i64(regs[r1], regs[r1], tmp2); - tcg_temp_free_i64(tmp2); - break; case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); @@ -2337,18 +2316,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0xc: /* MHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tcg_gen_muli_i32(tmp32_1, tmp32_1, i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0xd: /* MGHI R1,I2 [RI] */ - tmp = load_reg(r1); - tcg_gen_muli_i64(tmp, tmp, i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0xe: /* CHI R1,I2 [RI] */ tmp32_1 = load_reg32(r1); cmp_s32c(s, tmp32_1, i2); @@ -2408,14 +2375,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x52: /* MSR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x54: /* MVPG R1,R2 [RRE] */ tmp = load_reg(0); tmp2 = load_reg(r1); @@ -3083,18 +3042,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0xc: /* MSGR R1,R2 [RRE] */ - case 0x1c: /* MSGFR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - if (op == 0x1c) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - tcg_gen_mul_i64(tmp, tmp, tmp2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0xd: /* DSGR R1,R2 [RRE] */ case 0x1d: /* DSGFR R1,R2 [RRE] */ tmp = load_reg(r1 + 1); @@ -3820,41 +3767,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x4a: /* AH R1,D2(X2,B2) [RX] */ - case 0x4b: /* SH R1,D2(X2,B2) [RX] */ - case 0x4c: /* MH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - switch (opc) { - case 0x4a: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x4b: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x4c: - tcg_gen_mul_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4022,21 +3934,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x71: /* MS R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x78: /* LE R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4886,6 +4783,12 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mul(DisasContext *s, DisasOps *o) +{ + tcg_gen_mul_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); @@ -4983,6 +4886,12 @@ static void in1_r1(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = load_reg(get_field(f, r1)); } +static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = regs[get_field(f, r1)]; + o->g_in1 = true; +} + static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); @@ -5027,6 +4936,12 @@ static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = load_reg(get_field(f, r2)); } +static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = regs[get_field(f, r2)]; + o->g_in2 = true; +} + static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r3)); From d87aaf934f2fa24443bba7db60036b698e04d6a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Sep 2012 15:17:59 -0700 Subject: [PATCH 018/149] target-s390: Convert 32-bit MULTIPLY, MULTIPLY LOGICAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 ++++ target-s390x/translate.c | 82 ++++++++++++-------------------------- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 055113a073..ca12e475b8 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -41,12 +41,19 @@ C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* MULTIPLY */ + C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) + C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) /* MULTIPLY HALFWORD */ C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) /* MULTIPLY HALFWORD IMMEDIATE */ C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY LOGICAL */ + C(0xb996, MLR, RRE, Z, r1p1_32u, r2_32u, new, r1_D32, mul, 0) + C(0xe396, ML, RXY_a, Z, r1p1_32u, m2_32u, new, r1_D32, mul, 0) /* MULTIPLY SINGLE */ C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f09b7d19aa..a08d47163b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1624,18 +1624,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg32_i64(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x96: /* ML R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x97: /* DL R1,D2(X2,B2) [RXY] */ /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ @@ -3219,19 +3207,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x96: /* MLR R1,R2 [RRE] */ - /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x97: /* DLR R1,R2 [RRE] */ /* reg(r1) = reg(r1, r1+1) % reg(r2) */ /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ @@ -3605,21 +3580,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x1c: /* MR R1,R2 [RR] */ - /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32s_i64(tmp2, tmp2); - tcg_gen_ext32s_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3855,23 +3815,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5c: /* M R1,D2(X2,B2) [RX] */ - /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32s_i64(tmp2, tmp2); - tcg_gen_ext32s_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4868,6 +4811,15 @@ static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(get_field(f, r1), o->out); } +static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + store_reg32_i64((r1 + 1) & 15, o->out); + tcg_gen_shri_i64(o->out, o->out, 32); + store_reg32_i64(r1, o->out); +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); @@ -4892,6 +4844,22 @@ static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[(r1 + 1) & 15]); +} + +static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[(r1 + 1) & 15]); +} + static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); From 1ac5889f48127321a585886524013fcb6e2c91e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Sep 2012 15:26:59 -0700 Subject: [PATCH 019/149] target-s390: Convert 64-bit MULTIPLY LOGICAL Use a new "retxl" member of CPUS290XState to return the "eXtra Low" part of a 128-bit value. That said, this will get used when two independent values need returning (e.g. quotient+remainder) as well. At the same time, shuffle the elements of CPUS390XState to get this new space from existing padding in the structure. Signed-off-by: Richard Henderson --- target-s390x/cpu.h | 17 ++++++++++------- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/int_helper.c | 15 ++++----------- target-s390x/translate.c | 36 ++++++++++++++++++++++++++++-------- 5 files changed, 45 insertions(+), 27 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 83e618ab0e..afe33dc4b8 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -60,17 +60,20 @@ typedef struct ExtQueue { } ExtQueue; typedef struct CPUS390XState { - uint64_t regs[16]; /* GP registers */ - - uint32_t aregs[16]; /* access registers */ - - uint32_t fpc; /* floating-point control register */ + uint64_t regs[16]; /* GP registers */ CPU_DoubleU fregs[16]; /* FP registers */ + uint32_t aregs[16]; /* access registers */ + + uint32_t fpc; /* floating-point control register */ + uint32_t cc_op; + float_status fpu_status; /* passed to softfloat lib */ + /* The low part of a 128-bit return, or remainder of a divide. */ + uint64_t retxl; + PSW psw; - uint32_t cc_op; uint64_t cc_src; uint64_t cc_dst; uint64_t cc_vr; @@ -86,8 +89,8 @@ typedef struct CPUS390XState { uint64_t cregs[16]; /* control registers */ - int pending_int; ExtQueue ext_queue[MAX_EXT_QUEUE]; + int pending_int; int ext_index; diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 2498f83be7..88a065cad3 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -9,7 +9,7 @@ DEF_HELPER_4(clc, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) DEF_HELPER_4(stcm, void, env, i32, i32, i64) -DEF_HELPER_3(mlg, void, env, i32, i64) +DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_3(dlg, void, env, i32, i64) DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ca12e475b8..94cd2205b6 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -54,6 +54,8 @@ /* MULTIPLY LOGICAL */ C(0xb996, MLR, RRE, Z, r1p1_32u, r2_32u, new, r1_D32, mul, 0) C(0xe396, ML, RXY_a, Z, r1p1_32u, m2_32u, new, r1_D32, mul, 0) + C(0xb986, MLGR, RRE, Z, r1p1, r2_o, r1_P, 0, mul128, 0) + C(0xe386, MLG, RXY_a, Z, r1p1, m2_64, r1_P, 0, mul128, 0) /* MULTIPLY SINGLE */ C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index b683709860..4f18d29cd4 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -30,18 +30,11 @@ #endif /* 64/64 -> 128 unsigned multiplication */ -void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) { -#if HOST_LONG_BITS == 64 && defined(__GNUC__) - /* assuming 64-bit hosts have __uint128_t */ - __uint128_t res = (__uint128_t)env->regs[r1 + 1]; - - res *= (__uint128_t)v2; - env->regs[r1] = (uint64_t)(res >> 64); - env->regs[r1 + 1] = (uint64_t)res; -#else - mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); -#endif + uint64_t reth; + mulu64(&env->retxl, &reth, v1, v2); + return reth; } /* 128 -> 64/64 unsigned division */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a08d47163b..c38dde8323 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -293,6 +293,11 @@ static inline void store_freg32(int reg, TCGv_i32 v) #endif } +static inline void return_low128(TCGv_i64 dest) +{ + tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); +} + static inline void update_psw_addr(DisasContext *s) { /* psw.addr */ @@ -1563,14 +1568,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, set_cc_nz_u64(s, regs[r1]); tcg_temp_free_i64(tmp3); break; - case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_mlg(cpu_env, tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); @@ -4732,6 +4729,13 @@ static ExitStatus op_mul(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mul128(DisasContext *s, DisasOps *o) +{ + gen_helper_mul128(o->out, cpu_env, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); @@ -4800,6 +4804,15 @@ static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) o->g_out = true; } +static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->out = regs[r1]; + o->out2 = regs[(r1 + 1) & 15]; + o->g_out = o->g_out2 = true; +} + /* ====================================================================== */ /* The "Write OUTput" generators. These generally perform some non-trivial copy of data to TCG globals, or to main memory. The trivial cases are @@ -4844,6 +4857,13 @@ static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = load_reg((r1 + 1) & 15); +} + static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ From 3bbfbd1f956d82f552a0fe160abf929ec88a78ad Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 16:28:39 -0700 Subject: [PATCH 020/149] target-s390: Convert AND, OR, XOR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 27 ++++++++ target-s390x/translate.c | 134 ++++++++----------------------------- 2 files changed, 56 insertions(+), 105 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 94cd2205b6..7563cd894f 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -41,6 +41,24 @@ C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* AND */ + C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) + C(0xb9f4, NRK, RRF_a, DO, r2, r3, new, r1_32, and, nz32) + C(0x5400, N, RX_a, Z, r1, m2_32s, new, r1_32, and, nz32) + C(0xe354, NY, RXY_a, LD, r1, m2_32s, new, r1_32, and, nz32) + C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) + C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) + C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) + +/* EXCLUSIVE OR */ + C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) + C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) + C(0x5700, X, RX_a, Z, r1, m2_32s, new, r1_32, xor, nz32) + C(0xe357, XY, RXY_a, LD, r1, m2_32s, new, r1_32, xor, nz32) + C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) + C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) + C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) + /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) @@ -68,6 +86,15 @@ C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) +/* OR */ + C(0x1600, OR, RR_a, Z, r1, r2, new, r1_32, or, nz32) + C(0xb9f6, ORK, RRF_a, DO, r2, r3, new, r1_32, or, nz32) + C(0x5600, O, RX_a, Z, r1, m2_32s, new, r1_32, or, nz32) + C(0xe356, OY, RXY_a, LD, r1, m2_32s, new, r1_32, or, nz32) + C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) + C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) + C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c38dde8323..ba154f73d9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1487,19 +1487,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x57: /* XY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_xor_i32(tmp32_2, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_2); - set_cc_nz_u32(s, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x58: /* LY R1,D2(X2,B2) [RXY] */ tmp3 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(tmp3, addr, get_mem_index(s)); @@ -1547,27 +1534,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg32_i64(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x80: /* NG R1,D2(X2,B2) [RXY] */ - case 0x81: /* OG R1,D2(X2,B2) [RXY] */ - case 0x82: /* XG R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp3, addr, get_mem_index(s)); - switch (op) { - case 0x80: - tcg_gen_and_i64(regs[r1], regs[r1], tmp3); - break; - case 0x81: - tcg_gen_or_i64(regs[r1], regs[r1], tmp3); - break; - case 0x82: - tcg_gen_xor_i64(regs[r1], regs[r1], tmp3); - break; - default: - tcg_abort(); - } - set_cc_nz_u64(s, regs[r1]); - tcg_temp_free_i64(tmp3); - break; case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); @@ -3115,29 +3081,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x80: /* NGR R1,R2 [RRE] */ - case 0x81: /* OGR R1,R2 [RRE] */ - case 0x82: /* XGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - switch (op) { - case 0x80: - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x81: - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - case 0x82: - tcg_gen_xor_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - set_cc_nz_u64(s, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -3392,23 +3335,6 @@ static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, } } -static void gen_and_or_xor_i32(int opc, TCGv_i32 tmp, TCGv_i32 tmp2) -{ - switch (opc & 0xf) { - case 0x4: - tcg_gen_and_i32(tmp, tmp, tmp2); - break; - case 0x6: - tcg_gen_or_i32(tmp, tmp, tmp2); - break; - case 0x7: - tcg_gen_xor_i32(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; @@ -3543,19 +3469,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) set_cc_comp32(s, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x14: /* NR R1,R2 [RR] */ - case 0x16: /* OR R1,R2 [RR] */ - case 0x17: /* XR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_2 = load_reg32(r2); - tmp32_1 = load_reg32(r1); - gen_and_or_xor_i32(opc, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x18: /* LR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3768,24 +3681,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x54: /* N R1,D2(X2,B2) [RX] */ - case 0x56: /* O R1,D2(X2,B2) [RX] */ - case 0x57: /* X R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - gen_and_or_xor_i32(opc, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x58: /* l r1, d2(x2, b2) */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4723,6 +4618,12 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_and(DisasContext *s, DisasOps *o) +{ + tcg_gen_and_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); @@ -4736,12 +4637,24 @@ static ExitStatus op_mul128(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_or(DisasContext *s, DisasOps *o) +{ + tcg_gen_or_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); return NO_EXIT; } +static ExitStatus op_xor(DisasContext *s, DisasOps *o) +{ + tcg_gen_xor_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + /* ====================================================================== */ /* The "Cc OUTput" generators. Given the generated output (and in some cases the original inputs), update the various cc data structures in order to @@ -4767,6 +4680,17 @@ static void cout_addu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); } +static void cout_nz32(DisasContext *s, DisasOps *o) +{ + tcg_gen_ext32u_i64(cc_dst, o->out); + gen_op_update1_cc_i64(s, CC_OP_NZ, cc_dst); +} + +static void cout_nz64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ, o->out); +} + static void cout_subs32(DisasContext *s, DisasOps *o) { gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out); From a7e836d5ebef23022ec53a0dba5d3a1ac0883a03 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 16 Aug 2012 15:20:51 -0700 Subject: [PATCH 021/149] target-s390: Convert COMPARE, COMPARE LOGICAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 48 +++++++ target-s390x/translate.c | 267 +++++++++++-------------------------- 2 files changed, 129 insertions(+), 186 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7563cd894f..09eb30e4aa 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -50,6 +50,54 @@ C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) +/* COMPARE */ + C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) + C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xe359, CY, RXY_a, LD, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xb920, CGR, RRE, Z, r1_o, r2_o, 0, 0, 0, cmps64) + C(0xb930, CGFR, RRE, Z, r1_o, r2_32s, 0, 0, 0, cmps64) + C(0xe320, CG, RXY_a, Z, r1_o, m2_64, 0, 0, 0, cmps64) + C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) +/* COMPARE IMMEDIATE */ + C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) + C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) +/* COMPARE HALFWORD */ + C(0x4900, CH, RX_a, Z, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe379, CHY, RXY_a, LD, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe334, CGH, RXY_a, GIE, r1_o, m2_16s, 0, 0, 0, cmps64) +/* COMPARE HALFWORD IMMEDIATE */ + C(0xa70e, CHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps32) + C(0xa70f, CGHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps64) + C(0xe554, CHHSI, SIL, GIE, m1_16s, i2, 0, 0, 0, cmps64) + C(0xe55c, CHSI, SIL, GIE, m1_32s, i2, 0, 0, 0, cmps64) + C(0xe558, CGHSI, SIL, GIE, m1_64, i2, 0, 0, 0, cmps64) +/* COMPARE HALFWORD RELATIVE LONG */ + C(0xc605, CHRL, RIL_a, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) + C(0xc604, CGHRL, RIL_a, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) + +/* COMPARE LOGICAL */ + C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32) + C(0x5500, CL, RX_a, Z, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xe355, CLY, RXY_a, LD, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xb921, CLGR, RRE, Z, r1, r2, 0, 0, 0, cmpu64) + C(0xb931, CLGFR, RRE, Z, r1, r2_32u, 0, 0, 0, cmpu64) + C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) + C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL IMMEDIATE */ + C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) + C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) + C(0x9500, CLI, SI, Z, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xeb55, CLIY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xe555, CLHHSI, SIL, GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64) + C(0xe55d, CLFHSI, SIL, GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64) + C(0xe559, CLGHSI, SIL, GIE, m1_64, i2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL RELATIVE LONG */ + C(0xc60f, CLRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32) + C(0xc60a, CLGRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64) + C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) + C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) + C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) + /* EXCLUSIVE OR */ C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index ba154f73d9..09c85349da 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1434,39 +1434,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg16(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x20: /* CG R1,D2(X2,B2) [RXY] */ - case 0x21: /* CLG R1,D2(X2,B2) */ - case 0x30: /* CGF R1,D2(X2,B2) [RXY] */ - case 0x31: /* CLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - switch (op) { - case 0x20: - case 0x21: - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - break; - case 0x30: - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - break; - case 0x31: - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - break; - default: - tcg_abort(); - } - switch (op) { - case 0x20: - case 0x30: - cmp_s64(s, regs[r1], tmp2); - break; - case 0x21: - case 0x31: - cmp_u64(s, regs[r1], tmp2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - break; case 0x24: /* stg r1, d2(x2,b2) */ tcg_gen_qemu_st64(regs[r1], addr, get_mem_index(s)); break; @@ -1881,17 +1848,6 @@ do_mh: tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x55: /* CLIY D1(B1),I2 [SIY] */ - tmp3 = get_address(s, 0, b2, d2); /* SIY -> this is the 1st operand */ - tmp = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld8u(tmp, tmp3, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - cmp_u32c(s, tmp32_1, (r1 << 4) | r3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i32(tmp32_1); - break; case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); @@ -2267,16 +2223,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0xe: /* CHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - cmp_s32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xf: /* CGHI R1,I2 [RI] */ - tmp = load_reg(r1); - cmp_s64c(s, tmp, i2); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3047,28 +2993,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x20: /* CGR R1,R2 [RRE] */ - case 0x30: /* CGFR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - if (op == 0x30) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - tmp = load_reg(r1); - cmp_s64(s, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x21: /* CLGR R1,R2 [RRE] */ - case 0x31: /* CLGFR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - if (op == 0x31) { - tcg_gen_ext32u_i64(tmp2, tmp2); - } - tmp = load_reg(r1); - cmp_u64(s, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x26: /* LBR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tcg_gen_ext8s_i32(tmp32_1, tmp32_1); @@ -3301,40 +3225,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 } } -static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) -{ - TCGv_i64 tmp; - TCGv_i32 tmp32_1; - - switch (op) { - case 0xc: /* CGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - cmp_s64c(s, tmp, (int64_t)i2); - tcg_temp_free_i64(tmp); - break; - case 0xe: /* CLGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - cmp_u64c(s, tmp, (uint64_t)(uint32_t)i2); - tcg_temp_free_i64(tmp); - break; - case 0xd: /* CFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - cmp_s32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xf: /* CLFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - cmp_u32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - default: - LOG_DISAS("illegal c2 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; @@ -3476,20 +3366,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x15: /* CLR R1,R2 [RR] */ - case 0x19: /* CR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - if (opc == 0x15) { - cmp_u32(s, tmp32_1, tmp32_2); - } else { - cmp_s32(s, tmp32_1, tmp32_2); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3623,20 +3499,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x49: /* CH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - cmp_s32(s, tmp32_1, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3667,20 +3529,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x55: /* CL R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r1); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - cmp_u32(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x58: /* l r1, d2(x2, b2) */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3693,20 +3541,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x59: /* C R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r1); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - cmp_s32(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3962,15 +3796,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x95: /* CLI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - cmp_u64c(s, tmp2, i2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -4239,21 +4064,11 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) } break; case 0xc0: - case 0xc2: insn = ld_code6(env, s->pc); r1 = (insn >> 36) & 0xf; op = (insn >> 32) & 0xf; i2 = (int)insn; - switch (opc) { - case 0xc0: - disas_c0(env, s, op, r1, i2); - break; - case 0xc2: - disas_c2(env, s, op, r1, i2); - break; - default: - tcg_abort(); - } + disas_c0(env, s, op, r1, i2); break; case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ @@ -4680,6 +4495,26 @@ static void cout_addu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); } +static void cout_cmps32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2); +} + +static void cout_cmps64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTGT_64, o->in1, o->in2); +} + +static void cout_cmpu32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_32, o->in1, o->in2); +} + +static void cout_cmpu64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2); +} + static void cout_nz32(DisasContext *s, DisasOps *o) { tcg_gen_ext32u_i64(cc_dst, o->out); @@ -4819,6 +4654,27 @@ static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); } +static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s)); +} + +static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s)); +} + +static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s)); +} + static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in1_la1(s, f, o); @@ -4877,6 +4733,11 @@ static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); } +static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); +} + static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); @@ -4901,11 +4762,45 @@ static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); } +static void in2_mri2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_mri2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_mri2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_mri2_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); +} + static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64(get_field(f, i2)); } +static void in2_i2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint8_t)get_field(f, i2)); +} + +static void in2_i2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint16_t)get_field(f, i2)); +} + static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); From 22c37a08bd0ce680d6b9750c73704a025bc3fc93 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 09:45:53 -0700 Subject: [PATCH 022/149] target-s390: Convert LOAD, LOAD LOGICAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 20 ++++++++ target-s390x/translate.c | 100 +++++++++++++++---------------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 09eb30e4aa..0a7cba31d5 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -107,6 +107,26 @@ C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) +/* LOAD */ + C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) + C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xe358, LY, RXY_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0) + C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) + C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) + C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) +/* LOAD IMMEDIATE */ + C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) +/* LOAD RELATIVE LONG */ + C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) + C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) + C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) +/* LOAD LOGICAL */ + C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) + C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) +/* LOAD LOGICAL RELATIVE LONG */ + C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) + /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 09c85349da..5c31ecf0ba 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1350,7 +1350,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, addr = get_address(s, x2, b2, d2); switch (op) { case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ - case 0x4: /* lg r1,d2(x2,b2) */ + case 0x4: /* LG r1,d2(x2,b2) */ tcg_gen_qemu_ld64(regs[r1], addr, get_mem_index(s)); if (op == 0x2) { set_cc_s64(s, regs[r1]); @@ -1391,16 +1391,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x14: /* LGF R1,D2(X2,B2) [RXY] */ - case 0x16: /* LLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - if (op == 0x14) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); @@ -1454,12 +1444,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x58: /* LY R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp3, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp3); - break; case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ store_reg(r1, addr); break; @@ -2930,9 +2914,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, } tcg_temp_free_i64(tmp); break; - case 0x4: /* LGR R1,R2 [RRE] */ - store_reg(r1, regs[r2]); - break; case 0x6: /* LGBR R1,R2 [RRE] */ tmp2 = load_reg(r2); tcg_gen_ext8s_i64(tmp2, tmp2); @@ -2959,22 +2940,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x14: /* LGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x16: /* LLGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x17: /* LLGTR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tmp = tcg_temp_new_i64(); @@ -3134,11 +3099,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0x1: /* LGFI R1,I2 [RIL] */ - tmp = tcg_const_i64((int64_t)i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0x4: /* BRCL M1,I2 [RIL] */ if (r1 == 15) { /* m1 == r1 */ gen_goto_tb(s, 0, target); @@ -3359,13 +3319,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) set_cc_comp32(s, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x18: /* LR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3529,18 +3482,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x58: /* l r1, d2(x2, b2) */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4439,6 +4380,33 @@ static ExitStatus op_and(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ld32s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld32u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld64(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_mov2(DisasContext *s, DisasOps *o) +{ + o->out = o->in2; + o->g_out = o->g_in2; + TCGV_UNUSED_I64(o->in2); + o->g_in2 = false; + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); @@ -4578,6 +4546,11 @@ static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) generally handled by having a "prep" generator install the TCG global as the destination of the operation. */ +static void wout_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg(get_field(f, r1), o->out); +} + static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); @@ -4592,6 +4565,13 @@ static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(r1, o->out); } +static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + if (get_field(f, r1) != get_field(f, r2)) { + store_reg32_i64(get_field(f, r1), o->out); + } +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); From aedec19d628dacf4f04ee7258ac2c5c9e47b5a7e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 09:57:07 -0700 Subject: [PATCH 023/149] target-s390: Convert LOAD ADDRESS Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 14 -------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0a7cba31d5..f0dcea617c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -121,6 +121,11 @@ C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) +/* LOAD ADDRESS */ + C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0) + 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 LOGICAL */ C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5c31ecf0ba..0cf090262f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1444,9 +1444,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ - store_reg(r1, addr); - break; case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ tmp32_1 = load_reg32(r1); tmp2 = tcg_temp_new_i64(); @@ -3094,11 +3091,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); switch (op) { - case 0: /* larl r1, i2 */ - tmp = tcg_const_i64(target); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0x4: /* BRCL M1,I2 [RIL] */ if (r1 == 15) { /* m1 == r1 */ gen_goto_tb(s, 0, target); @@ -3376,12 +3368,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x41: /* la */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ - tcg_temp_free_i64(tmp); - break; case 0x42: /* STC R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); From c698d8768756c66dd0dd55ea884c69c2212d59f9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 10:27:29 -0700 Subject: [PATCH 024/149] target-s390: Convert LOAD (LOGICAL) BYTE, CHARACTER, HALFWORD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 30 +++++++ target-s390x/translate.c | 157 ++++++++++++------------------------- 2 files changed, 78 insertions(+), 109 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f0dcea617c..796185f002 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -126,11 +126,41 @@ 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 BYTE */ + C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) + C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) + C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) + C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) +/* LOAD HALFWORD */ + C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) + C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) + C(0x4800, LH, RX_a, Z, 0, a2, new, r1_32, ld16s, 0) + C(0xe378, LHY, RXY_a, LD, 0, a2, new, r1_32, ld16s, 0) + C(0xe315, LGH, RXY_a, Z, 0, a2, r1, 0, ld16s, 0) +/* LOAD HALFWORD IMMEDIATE */ + C(0xa708, LHI, RI_a, Z, 0, i2, 0, r1_32, mov2, 0) + C(0xa709, LGHI, RI_a, Z, 0, i2, 0, r1, mov2, 0) +/* LOAD HALFWORD RELATIVE LONG */ + C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) + C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) /* LOAD LOGICAL */ C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) /* LOAD LOGICAL RELATIVE LONG */ C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) +/* LOAD LOGICAL CHARACTER */ + C(0xb994, LLCR, RRE, EI, 0, r2_8u, 0, r1_32, mov2, 0) + C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0) + C(0xe394, LLC, RXY_a, EI, 0, a2, new, r1_32, ld8u, 0) + C(0xe390, LLGC, RXY_a, Z, 0, a2, r1, 0, ld8u, 0) +/* LOAD LOGICAL HALFWORD */ + C(0xb995, LLHR, RRE, EI, 0, r2_16u, 0, r1_32, mov2, 0) + C(0xb985, LLGHR, RRE, EI, 0, r2_16u, 0, r1, mov2, 0) + C(0xe395, LLH, RXY_a, EI, 0, a2, new, r1_32, ld16u, 0) + C(0xe391, LLGH, RXY_a, Z, 0, a2, r1, 0, ld16u, 0) +/* LOAD LOGICAL HALFWORD RELATIVE LONG */ + C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) + C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0cf090262f..840bd6e3a0 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1391,12 +1391,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); @@ -1458,30 +1452,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg8(r1, tmp3); tcg_temp_free_i64(tmp3); break; - case 0x76: /* LB R1,D2(X2,B2) [RXY] */ - case 0x77: /* LGB R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8s(tmp2, addr, get_mem_index(s)); - switch (op) { - case 0x76: - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg32_i64(r1, tmp2); - break; - case 0x77: - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg(r1, tmp2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - break; - case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); @@ -1517,24 +1487,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x90: /* LLGC R1,D2(X2,B2) [RXY] */ - tcg_gen_qemu_ld8u(regs[r1], addr, get_mem_index(s)); - break; - case 0x91: /* LLGH R1,D2(X2,B2) [RXY] */ - tcg_gen_qemu_ld16u(regs[r1], addr, get_mem_index(s)); - break; - case 0x94: /* LLC R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x95: /* LLH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x97: /* DL R1,D2(X2,B2) [RXY] */ /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ @@ -2194,16 +2146,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, s->is_jmp = DISAS_TB_JUMP; tcg_temp_free_i64(tmp); break; - case 0x8: /* lhi r1, i2 */ - tmp32_1 = tcg_const_i32(i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x9: /* lghi r1, i2 */ - tmp = tcg_const_i64(i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2911,12 +2853,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, } tcg_temp_free_i64(tmp); break; - case 0x6: /* LGBR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0xd: /* DSGR R1,R2 [RRE] */ case 0x1d: /* DSGFR R1,R2 [RRE] */ tmp = load_reg(r1 + 1); @@ -2955,18 +2891,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x26: /* LBR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_ext8s_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x27: /* LHR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_ext16s_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -2975,18 +2899,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0x84: /* LLGCR R1,R2 [RRE] */ - tmp = load_reg(r2); - tcg_gen_andi_i64(tmp, tmp, 0xff); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x85: /* LLGHR R1,R2 [RRE] */ - tmp = load_reg(r2); - tcg_gen_andi_i64(tmp, tmp, 0xffff); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0x87: /* DLGR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp = load_reg(r2); @@ -3021,18 +2933,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x94: /* LLCR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xff); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x95: /* LLHR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xffff); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x97: /* DLR R1,R2 [RRE] */ /* reg(r1) = reg(r1, r1+1) % reg(r2) */ /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ @@ -3429,15 +3329,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); s->is_jmp = DISAS_TB_JUMP; break; - case 0x48: /* LH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4366,6 +4257,30 @@ static ExitStatus op_and(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ld8s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld8u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld8u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld16s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld16s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld16u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld16u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + static ExitStatus op_ld32s(DisasContext *s, DisasOps *o) { tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s)); @@ -4676,6 +4591,30 @@ static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in2 = true; } +static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext8s_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext8u_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16s_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r2)]); +} + static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r3)); From 11bf2d73d0dba509e14dbfc2189365410a5a2c06 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 11:03:39 -0700 Subject: [PATCH 025/149] target-s390: Convert LOAD AND TEST Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 37 ++++++++++--------------------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 796185f002..7a8dcbd0f1 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -126,6 +126,13 @@ 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 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) + C(0xb912, LTGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, s64) + C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) + C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) + C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) /* LOAD BYTE */ C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 840bd6e3a0..9239025169 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1349,23 +1349,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, op, r1, x2, b2, d2); addr = get_address(s, x2, b2, d2); switch (op) { - case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ - case 0x4: /* LG r1,d2(x2,b2) */ - tcg_gen_qemu_ld64(regs[r1], addr, get_mem_index(s)); - if (op == 0x2) { - set_cc_s64(s, regs[r1]); - } - break; - case 0x12: /* LT R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_reg32(r1, tmp32_1); - set_cc_s32(s, tmp32_1); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); @@ -3192,16 +3175,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x12: /* LTR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - if (r1 != r2) { - store_reg32(r1, tmp32_1); - } - set_cc_s32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x13: /* LCR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -4395,6 +4368,16 @@ static void cout_nz64(DisasContext *s, DisasOps *o) gen_op_update1_cc_i64(s, CC_OP_NZ, o->out); } +static void cout_s32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_LTGT0_32, o->out); +} + +static void cout_s64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, o->out); +} + static void cout_subs32(DisasContext *s, DisasOps *o) { gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out); From ade9dea429e202eabf87a36a20d1d3bbc34d8910 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 11:20:33 -0700 Subject: [PATCH 026/149] target-s390: Convert LOAD LOGICAL IMMEDIATE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 42 +++++++++++--------------------------- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7a8dcbd0f1..89bc635257 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -168,6 +168,13 @@ /* LOAD LOGICAL HALFWORD RELATIVE LONG */ C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) +/* LOAD LOGICAL IMMEDATE */ + D(0xc00e, LLIHF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32) + D(0xc00f, LLILF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0) + D(0xa50c, LLIHH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 48) + D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) + D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) + D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9239025169..0143758570 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2033,26 +2033,6 @@ static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32); tcg_temp_free_i64(tmp); break; - case 0xc: /* LLIHH R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 48 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xd: /* LLIHL R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 32 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xe: /* LLILH R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 16 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xf: /* LLILL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a5 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3043,16 +3023,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0xe: /* LLIHF R1,I2 [RIL] */ - tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xf: /* LLILF R1,I2 [RIL] */ - tmp = tcg_const_i64((uint32_t)i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -4694,6 +4664,18 @@ static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); } +static void in2_i2_16u_shl(DisasContext *s, DisasFields *f, DisasOps *o) +{ + uint64_t i2 = (uint16_t)get_field(f, i2); + o->in2 = tcg_const_i64(i2 << s->insn->data); +} + +static void in2_i2_32u_shl(DisasContext *s, DisasFields *f, DisasOps *o) +{ + uint64_t i2 = (uint32_t)get_field(f, i2); + o->in2 = tcg_const_i64(i2 << s->insn->data); +} + /* ====================================================================== */ /* Find opc within the table of insns. This is formulated as a switch From b9bca3e57a4570ce2aff46388fa1edc9da5437a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 11:38:37 -0700 Subject: [PATCH 027/149] target-s390: Convert LOAD COMPLIMENT, POSITIVE, NEGATIVE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 12 ++++ target-s390x/translate.c | 142 +++++++++++++------------------------ 2 files changed, 60 insertions(+), 94 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 89bc635257..9507262131 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -138,6 +138,10 @@ C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) +/* LOAD COMPLEMENT */ + C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) + C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) + C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) /* LOAD HALFWORD */ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) @@ -175,6 +179,14 @@ D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) +/* LOAD NEGATIVE */ + C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) + C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) + C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) +/* LOAD POSITIVE */ + C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) + C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) + C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0143758570..2da94f56cd 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -570,42 +570,12 @@ static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr); } -static void set_cc_abs64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_ABS_64, v1); -} - -static void set_cc_nabs64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_NABS_64, v1); -} - static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) { gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr); } -static void set_cc_abs32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1); -} - -static void set_cc_nabs32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_NABS_32, v1); -} - -static void set_cc_comp32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_COMP_32, v1); -} - -static void set_cc_comp64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_COMP_64, v1); -} - static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) { gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); @@ -2779,43 +2749,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x0: /* LPGR R1,R2 [RRE] */ - case 0x1: /* LNGR R1,R2 [RRE] */ - case 0x2: /* LTGR R1,R2 [RRE] */ - case 0x3: /* LCGR R1,R2 [RRE] */ - case 0x10: /* LPGFR R1,R2 [RRE] */ - case 0x11: /* LNFGR R1,R2 [RRE] */ - case 0x12: /* LTGFR R1,R2 [RRE] */ - case 0x13: /* LCGFR R1,R2 [RRE] */ - if (op & 0x10) { - tmp = load_reg32_i64(r2); - } else { - tmp = load_reg(r2); - } - switch (op & 0xf) { - case 0x0: /* LP?GR */ - set_cc_abs64(s, tmp); - gen_helper_abs_i64(tmp, tmp); - store_reg(r1, tmp); - break; - case 0x1: /* LN?GR */ - set_cc_nabs64(s, tmp); - gen_helper_nabs_i64(tmp, tmp); - store_reg(r1, tmp); - break; - case 0x2: /* LT?GR */ - if (r1 != r2) { - store_reg(r1, tmp); - } - set_cc_s64(s, tmp); - break; - case 0x3: /* LC?GR */ - tcg_gen_neg_i64(regs[r1], tmp); - set_cc_comp64(s, regs[r1]); - break; - } - tcg_temp_free_i64(tmp); - break; case 0xd: /* DSGR R1,R2 [RRE] */ case 0x1d: /* DSGFR R1,R2 [RRE] */ tmp = load_reg(r1 + 1); @@ -3127,33 +3060,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x10: /* LPR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - set_cc_abs32(s, tmp32_1); - gen_helper_abs_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x11: /* LNR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - set_cc_nabs32(s, tmp32_1); - gen_helper_nabs_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x13: /* LCR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - tcg_gen_neg_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - set_cc_comp32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -4188,6 +4094,12 @@ struct DisasInsn { /* The operations. These perform the bulk of the work for any insn, usually after the operands have been loaded and output initialized. */ +static ExitStatus op_abs(DisasContext *s, DisasOps *o) +{ + gen_helper_abs_i64(o->out, o->in2); + return NO_EXIT; +} + static ExitStatus op_add(DisasContext *s, DisasOps *o) { tcg_gen_add_i64(o->out, o->in1, o->in2); @@ -4264,6 +4176,18 @@ static ExitStatus op_mul128(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_nabs(DisasContext *s, DisasOps *o) +{ + gen_helper_nabs_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_neg(DisasContext *s, DisasOps *o) +{ + tcg_gen_neg_i64(o->out, o->in2); + return NO_EXIT; +} + static ExitStatus op_or(DisasContext *s, DisasOps *o) { tcg_gen_or_i64(o->out, o->in1, o->in2); @@ -4287,6 +4211,16 @@ static ExitStatus op_xor(DisasContext *s, DisasOps *o) the original inputs), update the various cc data structures in order to be able to compute the new condition code. */ +static void cout_abs32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_ABS_32, o->out); +} + +static void cout_abs64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_ABS_64, o->out); +} + static void cout_adds32(DisasContext *s, DisasOps *o) { gen_op_update3_cc_i64(s, CC_OP_ADD_32, o->in1, o->in2, o->out); @@ -4327,6 +4261,26 @@ static void cout_cmpu64(DisasContext *s, DisasOps *o) gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2); } +static void cout_nabs32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NABS_32, o->out); +} + +static void cout_nabs64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NABS_64, o->out); +} + +static void cout_neg32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_COMP_32, o->out); +} + +static void cout_neg64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_COMP_64, o->out); +} + static void cout_nz32(DisasContext *s, DisasOps *o) { tcg_gen_ext32u_i64(cc_dst, o->out); From facfc8648728b5c5554b3269355a4c13824e664b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 15:01:36 -0700 Subject: [PATCH 028/149] target-s390: Convert AND, OR, XOR, INSERT IMMEDIATE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 25 ++++ target-s390x/translate.c | 237 +++++++++---------------------------- 2 files changed, 82 insertions(+), 180 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 9507262131..705b655a81 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -49,6 +49,13 @@ C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) +/* AND IMMEDIATE */ + D(0xc00a, NIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2020) + D(0xc00b, NILF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2000) + D(0xa504, NIHH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1030) + D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) + D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) + D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) @@ -106,6 +113,17 @@ C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) +/* EXCLUSIVE OR IMMEDIATE */ + D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) + D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) + +/* INSERT IMMEDIATE */ + D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) + D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) + D(0xa500, IIHH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1030) + D(0xa501, IIHL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1020) + D(0xa502, IILH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1010) + D(0xa503, IILL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1000) /* LOAD */ C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) @@ -223,6 +241,13 @@ C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) +/* OR IMMEDIATE */ + D(0xc00c, OIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2020) + D(0xc00d, OILF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2000) + D(0xa508, OIHH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1030) + D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) + D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) + D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2da94f56cd..06db4c5f19 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1875,141 +1875,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(addr); } -static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) -{ - TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32; - LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); - switch (op) { - case 0x0: /* IIHH R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 48, 16); - tcg_temp_free_i64(tmp); - break; - case 0x1: /* IIHL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 32, 16); - tcg_temp_free_i64(tmp); - break; - case 0x2: /* IILH R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 16, 16); - tcg_temp_free_i64(tmp); - break; - case 0x3: /* IILL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 0, 16); - tcg_temp_free_i64(tmp); - break; - case 0x4: /* NIHH R1,I2 [RI] */ - case 0x8: /* OIHH R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x4: - tmp2 = tcg_const_i64((((uint64_t)i2) << 48) - | 0x0000ffffffffffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x8: - tmp2 = tcg_const_i64(((uint64_t)i2) << 48); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp2, tmp, 48); - tcg_gen_trunc_i64_i32(tmp32, tmp2); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x5: /* NIHL R1,I2 [RI] */ - case 0x9: /* OIHL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x5: - tmp2 = tcg_const_i64((((uint64_t)i2) << 32) - | 0xffff0000ffffffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x9: - tmp2 = tcg_const_i64(((uint64_t)i2) << 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp2, tmp, 32); - tcg_gen_trunc_i64_i32(tmp32, tmp2); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x6: /* NILH R1,I2 [RI] */ - case 0xa: /* OILH R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x6: - tmp2 = tcg_const_i64((((uint64_t)i2) << 16) - | 0xffffffff0000ffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0xa: - tmp2 = tcg_const_i64(((uint64_t)i2) << 16); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp, tmp, 16); - tcg_gen_trunc_i64_i32(tmp32, tmp); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x7: /* NILL R1,I2 [RI] */ - case 0xb: /* OILL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x7: - tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0xb: - tmp2 = tcg_const_i64(i2); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_trunc_i64_i32(tmp32, tmp); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); /* signedness should not matter here */ - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - default: - LOG_DISAS("illegal a5 operation 0x%x\n", op); - gen_illegal_opcode(s); - return; - } -} - static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { @@ -2918,44 +2783,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 gen_goto_tb(s, 0, target); s->is_jmp = DISAS_TB_JUMP; break; - case 0x7: /* XILF R1,I2 [RIL] */ - case 0xb: /* NILF R1,I2 [RIL] */ - case 0xd: /* OILF R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - switch (op) { - case 0x7: - tcg_gen_xori_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - case 0xb: - tcg_gen_andi_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - case 0xd: - tcg_gen_ori_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x9: /* IILF R1,I2 [RIL] */ - tmp32_1 = tcg_const_i32((uint32_t)i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0xa: /* NIHF R1,I2 [RIL] */ - tmp = load_reg(r1); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32) - | 0xffffffffULL); - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp, tmp, 32); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3487,13 +3314,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xa5: - insn = ld_code4(env, s->pc); - r1 = (insn >> 20) & 0xf; - op = (insn >> 16) & 0xf; - i2 = insn & 0xffff; - disas_a5(env, s, op, r1, i2); - break; case 0xa7: insn = ld_code4(env, s->pc); r1 = (insn >> 20) & 0xf; @@ -4112,6 +3932,31 @@ static ExitStatus op_and(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_andi(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_ori_i64(o->in2, o->in2, ~mask); + tcg_gen_and_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + +static ExitStatus op_insi(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + tcg_gen_deposit_i64(o->out, o->in1, o->in2, shift, size); + return NO_EXIT; +} + static ExitStatus op_ld8s(DisasContext *s, DisasOps *o) { tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s)); @@ -4194,6 +4039,22 @@ static ExitStatus op_or(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ori(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_or_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); @@ -4206,6 +4067,22 @@ static ExitStatus op_xor(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_xori(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_xor_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + /* ====================================================================== */ /* The "Cc OUTput" generators. Given the generated output (and in some cases the original inputs), update the various cc data structures in order to From 2b280b97085ae90e804c1b31557a79d1da2789a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 16:00:08 -0700 Subject: [PATCH 029/149] target-s390: Convert STORE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 16 +++++++++ target-s390x/translate.c | 67 ++++++++++++++------------------------ 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 705b655a81..f441a66958 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -249,6 +249,22 @@ D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) +/* STORE */ + C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) + C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) + C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) +/* STORE RELATIVE LONG */ + C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) + C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) +/* STORE CHARACTER */ + C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) + C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) +/* STORE HALFWORD */ + C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) + C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) +/* STORE HALFWORD RELATIVE LONG */ + C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 06db4c5f19..f17fa2f74e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1371,9 +1371,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg16(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x24: /* stg r1, d2(x2,b2) */ - tcg_gen_qemu_st64(regs[r1], addr, get_mem_index(s)); - break; case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ tmp32_1 = load_reg32(r1); tmp2 = tcg_temp_new_i64(); @@ -1383,22 +1380,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x50: /* STY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; - case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st8(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp2); - break; case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ tmp3 = tcg_temp_new_i64(); tcg_gen_qemu_ld8u(tmp3, addr, get_mem_index(s)); @@ -2936,22 +2917,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) store_freg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x40: /* STH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st16(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x42: /* STC R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x43: /* IC R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3027,14 +2992,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x50: /* st r1, d2(x2, b2) */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4055,6 +4012,30 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_st8(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st8(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st16(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st16(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st32(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st32(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st64(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st64(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); From 4e4bb43899c4c97e14b59fbd7cd5cb44eea850a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 18:52:33 -0700 Subject: [PATCH 030/149] target-s390: Convert ADD LOGICAL CARRY and SUBTRACT LOGICAL BORROW I'm resonably certain that the carry/borrow-out condition for both helpers was incorrect, failing to take into account the carry-in. Adding the new CC_OP codes also allows removing the awkward interface we used for the slb helpers. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 108 +++++++++++++++------ target-s390x/cpu.h | 8 ++ target-s390x/helper.h | 3 - target-s390x/insn-data.def | 10 ++ target-s390x/int_helper.c | 43 --------- target-s390x/translate.c | 191 ++++++++++++------------------------- 6 files changed, 157 insertions(+), 206 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 19ef145da9..880e3b234d 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -146,22 +146,21 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, } } -static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) { - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } + return (ar != 0) + 2 * (ar < a1); +} + +static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + /* Recover a2 + carry_in. */ + uint64_t a2c = ar - a1; + /* Check for a2+carry_in overflow, then a1+a2c overflow. */ + int carry_out = (a2c < a2) || (ar < a1); + + return (ar != 0) + 2 * carry_out; } static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, @@ -194,6 +193,25 @@ static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, } } +static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + /* We had borrow-in if normal subtraction isn't equal. */ + int borrow_in = ar - (a1 - a2); + int borrow_out; + + /* If a2 was ULONG_MAX, and borrow_in, then a2 is logically 65 bits, + and we must have had borrow out. */ + if (borrow_in && a2 == (uint64_t)-1) { + borrow_out = 1; + } else { + a2 += borrow_in; + borrow_out = (a2 > a1); + } + + return (ar != 0) + 2 * !borrow_out; +} + static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { @@ -240,22 +258,21 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, } } -static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) { - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } + return (ar != 0) + 2 * (ar < a1); +} + +static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + /* Recover a2 + carry_in. */ + uint32_t a2c = ar - a1; + /* Check for a2+carry_in overflow, then a1+a2c overflow. */ + int carry_out = (a2c < a2) || (ar < a1); + + return (ar != 0) + 2 * carry_out; } static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, @@ -288,6 +305,25 @@ static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, } } +static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + /* We had borrow-in if normal subtraction isn't equal. */ + int borrow_in = ar - (a1 - a2); + int borrow_out; + + /* If a2 was UINT_MAX, and borrow_in, then a2 is logically 65 bits, + and we must have had borrow out. */ + if (borrow_in && a2 == (uint32_t)-1) { + borrow_out = 1; + } else { + a2 += borrow_in; + borrow_out = (a2 > a1); + } + + return (ar != 0) + 2 * !borrow_out; +} + static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { @@ -426,12 +462,18 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ADDU_64: r = cc_calc_addu_64(env, src, dst, vr); break; + case CC_OP_ADDC_64: + r = cc_calc_addc_64(env, src, dst, vr); + break; case CC_OP_SUB_64: r = cc_calc_sub_64(env, src, dst, vr); break; case CC_OP_SUBU_64: r = cc_calc_subu_64(env, src, dst, vr); break; + case CC_OP_SUBB_64: + r = cc_calc_subb_64(env, src, dst, vr); + break; case CC_OP_ABS_64: r = cc_calc_abs_64(env, dst); break; @@ -448,12 +490,18 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ADDU_32: r = cc_calc_addu_32(env, src, dst, vr); break; + case CC_OP_ADDC_32: + r = cc_calc_addc_32(env, src, dst, vr); + break; case CC_OP_SUB_32: r = cc_calc_sub_32(env, src, dst, vr); break; case CC_OP_SUBU_32: r = cc_calc_subu_32(env, src, dst, vr); break; + case CC_OP_SUBB_32: + r = cc_calc_subb_32(env, src, dst, vr); + break; case CC_OP_ABS_32: r = cc_calc_abs_64(env, dst); break; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index afe33dc4b8..ea1bc8625e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -449,15 +449,19 @@ enum cc_op { CC_OP_ADD_64, /* overflow on add (64bit) */ CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ + CC_OP_ADDC_64, /* overflow on unsigned add-carry (64bit) */ CC_OP_SUB_64, /* overflow on subtraction (64bit) */ CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */ + CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */ CC_OP_ABS_64, /* sign eval on abs (64bit) */ CC_OP_NABS_64, /* sign eval on nabs (64bit) */ CC_OP_ADD_32, /* overflow on add (32bit) */ CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ + CC_OP_ADDC_32, /* overflow on unsigned add-carry (32bit) */ CC_OP_SUB_32, /* overflow on subtraction (32bit) */ CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */ + CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */ CC_OP_ABS_32, /* sign eval on abs (64bit) */ CC_OP_NABS_32, /* sign eval on nabs (64bit) */ @@ -494,14 +498,18 @@ static const char *cc_names[] = { [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", [CC_OP_ADD_64] = "CC_OP_ADD_64", [CC_OP_ADDU_64] = "CC_OP_ADDU_64", + [CC_OP_ADDC_64] = "CC_OP_ADDC_64", [CC_OP_SUB_64] = "CC_OP_SUB_64", [CC_OP_SUBU_64] = "CC_OP_SUBU_64", + [CC_OP_SUBB_64] = "CC_OP_SUBB_64", [CC_OP_ABS_64] = "CC_OP_ABS_64", [CC_OP_NABS_64] = "CC_OP_NABS_64", [CC_OP_ADD_32] = "CC_OP_ADD_32", [CC_OP_ADDU_32] = "CC_OP_ADDU_32", + [CC_OP_ADDC_32] = "CC_OP_ADDC_32", [CC_OP_SUB_32] = "CC_OP_SUB_32", [CC_OP_SUBU_32] = "CC_OP_SUBU_32", + [CC_OP_SUBB_32] = "CC_OP_SUBB_32", [CC_OP_ABS_32] = "CC_OP_ABS_32", [CC_OP_NABS_32] = "CC_OP_NABS_32", [CC_OP_COMP_32] = "CC_OP_COMP_32", diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 88a065cad3..a45b1c362b 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -26,13 +26,10 @@ DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) -DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) -DEF_HELPER_4(slb, i32, env, i32, i32, i32) -DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) DEF_HELPER_3(cefbr, void, env, i32, s32) DEF_HELPER_3(cdfbr, void, env, i32, s32) DEF_HELPER_3(cxfbr, void, env, i32, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f441a66958..373aa40fd3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -40,6 +40,11 @@ C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* ADD LOGICAL WITH CARRY */ + C(0xb998, ALCR, RRE, Z, r1, r2, new, r1_32, addc, addc32) + C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc, addc64) + C(0xe398, ALC, RXY_a, Z, r1, m2_32u, new, r1_32, addc, addc32) + C(0xe388, ALCG, RXY_a, Z, r1, m2_64, r1, 0, addc, addc64) /* AND */ C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) @@ -291,3 +296,8 @@ /* SUBTRACT LOGICAL IMMEDIATE */ C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32) C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64) +/* SUBTRACT LOGICAL WITH BORROW */ + C(0xb999, SLBR, RRE, Z, r1, r2, new, r1_32, subb, subb32) + C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb, subb64) + C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32) + C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 4f18d29cd4..17c4771e41 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -107,49 +107,6 @@ int64_t HELPER(nabs_i64)(int64_t val) } } -/* add with carry 32-bit unsigned */ -uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) -{ - uint32_t res; - - res = v1 + v2; - if (cc & 2) { - res++; - } - - return res; -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2) -{ - uint32_t v1 = env->regs[r1]; - uint32_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1, - uint64_t v1, uint64_t v2) -{ - uint64_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - /* find leftmost one */ uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f17fa2f74e..6f3a5df678 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -474,15 +474,6 @@ static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, s->cc_op = op; } -static void gen_op_update3_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src, - TCGv_i32 dst, TCGv_i32 vr) -{ - tcg_gen_extu_i32_i64(cc_src, src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_extu_i32_i64(cc_vr, vr); - s->cc_op = op; -} - static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val) { gen_op_update1_cc_i32(s, CC_OP_NZ, val); @@ -564,18 +555,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr); -} - -static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr); -} - static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) { gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); @@ -661,12 +640,16 @@ static void gen_op_calc_cc(DisasContext *s) break; case CC_OP_ADD_64: case CC_OP_ADDU_64: + case CC_OP_ADDC_64: case CC_OP_SUB_64: case CC_OP_SUBU_64: + case CC_OP_SUBB_64: case CC_OP_ADD_32: case CC_OP_ADDU_32: + case CC_OP_ADDC_32: case CC_OP_SUB_32: case CC_OP_SUBU_32: + case CC_OP_SUBB_32: /* 3 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); break; @@ -1313,7 +1296,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { TCGv_i64 addr, tmp, tmp2, tmp3, tmp4; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); @@ -1394,33 +1377,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - tcg_gen_extu_i32_i64(tmp3, cc_op); - tcg_gen_shri_i64(tmp3, tmp3, 1); - tcg_gen_andi_i64(tmp3, tmp3, 1); - tcg_gen_add_i64(tmp3, tmp2, tmp3); - tcg_gen_add_i64(tmp3, regs[r1], tmp3); - store_reg(r1, tmp3); - set_cc_addu64(s, regs[r1], tmp2, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x97: /* DL R1,D2(X2,B2) [RXY] */ /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ @@ -1441,37 +1397,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x98: /* ALC R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - store_reg32(r1, tmp32_3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x99: /* SLB R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2591,7 +2516,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, int r2) { TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1; LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { @@ -2648,33 +2573,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0x88: /* ALCGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = tcg_temp_new_i64(); - gen_op_calc_cc(s); - tcg_gen_extu_i32_i64(tmp3, cc_op); - tcg_gen_shri_i64(tmp3, tmp3, 1); - tcg_gen_andi_i64(tmp3, tmp3, 1); - tcg_gen_add_i64(tmp3, tmp2, tmp3); - tcg_gen_add_i64(tmp3, tmp, tmp3); - store_reg(r1, tmp3); - set_cc_addu64(s, tmp, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x89: /* SLBGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp32_1 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x97: /* DLR R1,R2 [RRE] */ /* reg(r1) = reg(r1, r1+1) % reg(r2) */ /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ @@ -2694,28 +2592,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x98: /* ALCR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - store_reg32(r1, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x99: /* SLBR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp32_2 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal b9 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3883,6 +3759,23 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_addc(DisasContext *s, DisasOps *o) +{ + TCGv_i64 cc; + + tcg_gen_add_i64(o->out, o->in1, o->in2); + + /* XXX possible optimization point */ + gen_op_calc_cc(s); + cc = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(cc, cc_op); + tcg_gen_shri_i64(cc, cc, 1); + + tcg_gen_add_i64(o->out, o->out, cc); + tcg_temp_free_i64(cc); + return NO_EXIT; +} + static ExitStatus op_and(DisasContext *s, DisasOps *o) { tcg_gen_and_i64(o->out, o->in1, o->in2); @@ -4042,6 +3935,24 @@ static ExitStatus op_sub(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_subb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 cc; + + assert(!o->g_in2); + tcg_gen_not_i64(o->in2, o->in2); + tcg_gen_add_i64(o->out, o->in1, o->in2); + + /* XXX possible optimization point */ + gen_op_calc_cc(s); + cc = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(cc, cc_op); + tcg_gen_shri_i64(cc, cc, 1); + tcg_gen_add_i64(o->out, o->out, cc); + tcg_temp_free_i64(cc); + return NO_EXIT; +} + static ExitStatus op_xor(DisasContext *s, DisasOps *o) { tcg_gen_xor_i64(o->out, o->in1, o->in2); @@ -4099,6 +4010,16 @@ static void cout_addu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); } +static void cout_addc32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDC_32, o->in1, o->in2, o->out); +} + +static void cout_addc64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDC_64, o->in1, o->in2, o->out); +} + static void cout_cmps32(DisasContext *s, DisasOps *o) { gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2); @@ -4180,6 +4101,16 @@ static void cout_subu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out); } +static void cout_subb32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBB_32, o->in1, o->in2, o->out); +} + +static void cout_subb64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, o->out); +} + /* ====================================================================== */ /* The "PREPeration" generators. These initialize the DisasOps.OUT fields with the TCG register to which we will write. Used in combination with From 8ac33cdb8bfbf319adea60363cf1ba3e5dbf5c4f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Aug 2012 11:38:19 -0700 Subject: [PATCH 031/149] target-s390: Convert BRANCH AND SAVE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++ target-s390x/translate.c | 102 ++++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 46 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 373aa40fd3..ba78f471d1 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -62,6 +62,13 @@ D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) +/* BRANCH AND SAVE */ + C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) + C(0x4d00, BAS, RX_a, Z, 0, a2, r1, 0, bas, 0) +/* BRANCH RELATIVE AND SAVE */ + C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) + C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) + /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6f3a5df678..6d87d08d26 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -713,20 +713,23 @@ static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2, return get_address(s, 0, *b1, *d1); } +static int use_goto_tb(DisasContext *s, uint64_t dest) +{ + /* NOTE: we handle the case where the TB spans two pages here */ + return (((dest & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) + || (dest & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) + && !s->singlestep_enabled + && !(s->tb->cflags & CF_LAST_IO)); +} + static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc) { - TranslationBlock *tb; - gen_update_cc_op(s); - tb = s->tb; - /* NOTE: we handle the case where the TB spans two pages here */ - if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) || - (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) { - /* jump to same page: we can use a direct jump */ + if (use_goto_tb(s, pc)) { tcg_gen_goto_tb(tb_num); tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb((tcg_target_long)tb + tb_num); + tcg_gen_exit_tb((tcg_target_long)s->tb + tb_num); } else { /* jump to another page: currently not optimized */ tcg_gen_movi_i64(psw_addr, pc); @@ -1817,13 +1820,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, case 0x4: /* brc m1, i2 */ gen_brc(r1, s, i2 * 2LL); return; - case 0x5: /* BRAS R1,I2 [RI] */ - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 4)); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - gen_goto_tb(s, 0, s->pc + i2 * 2LL); - s->is_jmp = DISAS_TB_JUMP; - break; case 0x6: /* BRCT R1,I2 [RI] */ tmp32_1 = load_reg32(r1); tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); @@ -2601,7 +2597,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { - TCGv_i64 tmp; TCGv_i32 tmp32_1, tmp32_2; uint64_t target = s->pc + i2 * 2LL; int l1; @@ -2633,13 +2628,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5: /* brasl r1, i2 */ - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 6)); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - gen_goto_tb(s, 0, target); - s->is_jmp = DISAS_TB_JUMP; - break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2720,19 +2708,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd: /* BASR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 2)); - store_reg(r1, tmp); - if (r2) { - tmp2 = load_reg(r2); - tcg_gen_mov_i64(psw_addr, tmp2); - tcg_temp_free_i64(tmp2); - s->is_jmp = DISAS_JUMP; - } - tcg_temp_free_i64(tmp); - break; case 0xe: /* MVCL R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -2846,16 +2821,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); s->is_jmp = DISAS_TB_JUMP; break; - case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_const_i64(pc_to_link_info(s, s->pc + 4)); - store_reg(r1, tmp2); - tcg_gen_mov_i64(psw_addr, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - s->is_jmp = DISAS_JUMP; - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3743,6 +3708,26 @@ struct DisasInsn { uint64_t data; }; +/* ====================================================================== */ +/* Miscelaneous helpers, used by several operations. */ + +static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) +{ + if (dest == s->next_pc) { + return NO_EXIT; + } + if (use_goto_tb(s, dest)) { + gen_update_cc_op(s); + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, dest); + tcg_gen_exit_tb((tcg_target_long)s->tb); + return EXIT_GOTO_TB; + } else { + tcg_gen_movi_i64(psw_addr, dest); + return EXIT_PC_UPDATED; + } +} + /* ====================================================================== */ /* The operations. These perform the bulk of the work for any insn, usually after the operands have been loaded and output initialized. */ @@ -3799,6 +3784,23 @@ static ExitStatus op_andi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_bas(DisasContext *s, DisasOps *o) +{ + tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); + if (!TCGV_IS_UNUSED_I64(o->in2)) { + tcg_gen_mov_i64(psw_addr, o->in2); + return EXIT_PC_UPDATED; + } else { + return NO_EXIT; + } +} + +static ExitStatus op_basi(DisasContext *s, DisasOps *o) +{ + tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); + return help_goto_direct(s, s->pc + 2 * get_field(s->fields, i2)); +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; @@ -4287,6 +4289,14 @@ static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in2 = true; } +static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r2 = get_field(f, r2); + if (r2 != 0) { + o->in2 = load_reg(r2); + } +} + static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); From 7233f2ed17175eea043faad749143c1fb5ffe0b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 08:28:02 -0700 Subject: [PATCH 032/149] target-s390: Convert BRANCH ON CONDITION Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 + target-s390x/translate.c | 231 ++++++++++++++++++++++--------------- 2 files changed, 142 insertions(+), 95 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ba78f471d1..0bd05abd52 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -68,6 +68,12 @@ /* BRANCH RELATIVE AND SAVE */ C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) +/* BRANCH ON CONDITION */ + C(0x0700, BCR, RR_b, Z, 0, r2_nz, 0, 0, bc, 0) + C(0x4700, BC, RX_b, Z, 0, a2, 0, 0, bc, 0) +/* BRANCH RELATIVE ON CONDITION */ + C(0xa704, BRC, RI_c, Z, 0, 0, 0, 0, bc, 0) + C(0xc004, BRCL, RIL_c, Z, 0, 0, 0, 0, bc, 0) /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6d87d08d26..e663fe5ed8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1021,35 +1021,6 @@ static void gen_jcc(DisasContext *s, uint32_t mask, int skip) free_compare(&c); } -static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, - uint64_t offset) -{ - int skip; - - if (mask == 0xf) { - /* unconditional */ - gen_update_cc_op(s); - tcg_gen_mov_i64(psw_addr, target); - tcg_gen_exit_tb(0); - } else if (mask == 0) { - /* ignore cc and never match */ - gen_goto_tb(s, 0, offset + 2); - } else { - TCGv_i64 new_addr = tcg_temp_local_new_i64(); - - tcg_gen_mov_i64(new_addr, target); - skip = gen_new_label(); - gen_jcc(s, mask, skip); - gen_update_cc_op(s); - tcg_gen_mov_i64(psw_addr, new_addr); - tcg_temp_free_i64(new_addr); - tcg_gen_exit_tb(0); - gen_set_label(skip); - tcg_temp_free_i64(new_addr); - gen_goto_tb(s, 1, offset + 2); - } -} - static void gen_brc(uint32_t mask, DisasContext *s, int32_t offset) { int skip; @@ -2595,46 +2566,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, } } -static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) -{ - TCGv_i32 tmp32_1, tmp32_2; - uint64_t target = s->pc + i2 * 2LL; - int l1; - - LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); - - switch (op) { - case 0x4: /* BRCL M1,I2 [RIL] */ - if (r1 == 15) { /* m1 == r1 */ - gen_goto_tb(s, 0, target); - s->is_jmp = DISAS_TB_JUMP; - break; - } - /* m1 & (1 << (3 - cc)) */ - tmp32_1 = tcg_const_i32(3); - tmp32_2 = tcg_const_i32(1); - gen_op_calc_cc(s); - tcg_gen_sub_i32(tmp32_1, tmp32_1, cc_op); - tcg_gen_shl_i32(tmp32_2, tmp32_2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tmp32_1 = tcg_const_i32(r1); /* m1 == r1 */ - tcg_gen_and_i32(tmp32_1, tmp32_1, tmp32_2); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1); - gen_goto_tb(s, 0, target); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 6); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - default: - LOG_DISAS("illegal c0 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; @@ -2681,18 +2612,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); } break; - case 0x7: /* BCR M1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - if (r2) { - tmp = load_reg(r2); - gen_bcr(s, r1, tmp, s->pc); - tcg_temp_free_i64(tmp); - s->is_jmp = DISAS_TB_JUMP; - } else { - /* XXX: "serialization and checkpoint-synchronization function"? */ - } - break; case 0xa: /* SVC I [RR] */ insn = ld_code2(env, s->pc); debug_insn(insn); @@ -2814,13 +2733,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x47: /* BC M1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - gen_bcr(s, r1, tmp, s->pc + 4); - tcg_temp_free_i64(tmp); - s->is_jmp = DISAS_TB_JUMP; - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3348,13 +3260,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) gen_op_movi_cc(s, 0); } break; - case 0xc0: - insn = ld_code6(env, s->pc); - r1 = (insn >> 36) & 0xf; - op = (insn >> 32) & 0xf; - i2 = (int)insn; - disas_c0(env, s, op, r1, i2); - break; case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ @@ -3728,6 +3633,131 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) } } +static ExitStatus help_branch(DisasContext *s, DisasCompare *c, + bool is_imm, int imm, TCGv_i64 cdest) +{ + ExitStatus ret; + uint64_t dest = s->pc + 2 * imm; + int lab; + + /* Take care of the special cases first. */ + if (c->cond == TCG_COND_NEVER) { + ret = NO_EXIT; + goto egress; + } + if (is_imm) { + if (dest == s->next_pc) { + /* Branch to next. */ + ret = NO_EXIT; + goto egress; + } + if (c->cond == TCG_COND_ALWAYS) { + ret = help_goto_direct(s, dest); + goto egress; + } + } else { + if (TCGV_IS_UNUSED_I64(cdest)) { + /* E.g. bcr %r0 -> no branch. */ + ret = NO_EXIT; + goto egress; + } + if (c->cond == TCG_COND_ALWAYS) { + tcg_gen_mov_i64(psw_addr, cdest); + ret = EXIT_PC_UPDATED; + goto egress; + } + } + + if (use_goto_tb(s, s->next_pc)) { + if (is_imm && use_goto_tb(s, dest)) { + /* Both exits can use goto_tb. */ + gen_update_cc_op(s); + + lab = gen_new_label(); + if (c->is_64) { + tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab); + } + + /* Branch not taken. */ + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, s->next_pc); + tcg_gen_exit_tb((tcg_target_long)s->tb + 0); + + /* Branch taken. */ + gen_set_label(lab); + tcg_gen_goto_tb(1); + tcg_gen_movi_i64(psw_addr, dest); + tcg_gen_exit_tb((tcg_target_long)s->tb + 1); + + ret = EXIT_GOTO_TB; + } else { + /* Fallthru can use goto_tb, but taken branch cannot. */ + /* Store taken branch destination before the brcond. This + avoids having to allocate a new local temp to hold it. + We'll overwrite this in the not taken case anyway. */ + if (!is_imm) { + tcg_gen_mov_i64(psw_addr, cdest); + } + + lab = gen_new_label(); + if (c->is_64) { + tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab); + } + + /* Branch not taken. */ + gen_update_cc_op(s); + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, s->next_pc); + tcg_gen_exit_tb((tcg_target_long)s->tb + 0); + + gen_set_label(lab); + if (is_imm) { + tcg_gen_movi_i64(psw_addr, dest); + } + ret = EXIT_PC_UPDATED; + } + } else { + /* Fallthru cannot use goto_tb. This by itself is vanishingly rare. + Most commonly we're single-stepping or some other condition that + disables all use of goto_tb. Just update the PC and exit. */ + + TCGv_i64 next = tcg_const_i64(s->next_pc); + if (is_imm) { + cdest = tcg_const_i64(dest); + } + + if (c->is_64) { + tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b, + cdest, next); + } else { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 z = tcg_const_i64(0); + tcg_gen_setcond_i32(c->cond, t0, c->u.s32.a, c->u.s32.b); + tcg_gen_extu_i32_i64(t1, t0); + tcg_temp_free_i32(t0); + tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(z); + } + + if (is_imm) { + tcg_temp_free_i64(cdest); + } + tcg_temp_free_i64(next); + + ret = EXIT_PC_UPDATED; + } + + egress: + free_compare(c); + return ret; +} + /* ====================================================================== */ /* The operations. These perform the bulk of the work for any insn, usually after the operands have been loaded and output initialized. */ @@ -3801,6 +3831,17 @@ static ExitStatus op_basi(DisasContext *s, DisasOps *o) return help_goto_direct(s, s->pc + 2 * get_field(s->fields, i2)); } +static ExitStatus op_bc(DisasContext *s, DisasOps *o) +{ + int m1 = get_field(s->fields, m1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + disas_jcc(s, &c, m1); + return help_branch(s, &c, is_imm, imm, o->in2); +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; From c61aad6943cd77046e47cdb5beedad9d035d2216 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 14:22:58 -0700 Subject: [PATCH 033/149] target-s390: Convert BRANCH ON COUNT Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 8 ++ target-s390x/translate.c | 162 ++++++++++--------------------------- 2 files changed, 51 insertions(+), 119 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0bd05abd52..8ea6630c43 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -74,6 +74,14 @@ /* BRANCH RELATIVE ON CONDITION */ C(0xa704, BRC, RI_c, Z, 0, 0, 0, 0, bc, 0) C(0xc004, BRCL, RIL_c, Z, 0, 0, 0, 0, bc, 0) +/* BRANCH ON COUNT */ + C(0x0600, BCTR, RR_a, Z, 0, r2_nz, 0, 0, bct32, 0) + C(0xb946, BCTGR, RRE, Z, 0, r2_nz, 0, 0, bct64, 0) + C(0x4600, BCT, RX_a, Z, 0, a2, 0, 0, bct32, 0) + C(0xe346, BCTG, RXY_a, Z, 0, a2, 0, 0, bct64, 0) +/* BRANCH RELATIVE ON COUNT */ + C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) + C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e663fe5ed8..fdf0129a29 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1004,43 +1004,6 @@ static void free_compare(DisasCompare *c) } } -static void gen_jcc(DisasContext *s, uint32_t mask, int skip) -{ - DisasCompare c; - TCGCond cond; - - disas_jcc(s, &c, mask); - cond = tcg_invert_cond(c.cond); - - if (c.is_64) { - tcg_gen_brcond_i64(cond, c.u.s64.a, c.u.s64.b, skip); - } else { - tcg_gen_brcond_i32(cond, c.u.s32.a, c.u.s32.b, skip); - } - - free_compare(&c); -} - -static void gen_brc(uint32_t mask, DisasContext *s, int32_t offset) -{ - int skip; - - if (mask == 0xf) { - /* unconditional */ - gen_goto_tb(s, 0, s->pc + offset); - } else if (mask == 0) { - /* ignore cc and never match */ - gen_goto_tb(s, 0, s->pc + 4); - } else { - skip = gen_new_label(); - gen_jcc(s, mask, skip); - gen_goto_tb(s, 0, s->pc + offset); - gen_set_label(skip); - gen_goto_tb(s, 1, s->pc + 4); - } - s->is_jmp = DISAS_TB_JUMP; -} - static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) { TCGv_i64 tmp, tmp2; @@ -1759,8 +1722,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32_1; - int l1; LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); switch (op) { @@ -1788,35 +1749,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x4: /* brc m1, i2 */ - gen_brc(r1, s, i2 * 2LL); - return; - case 0x6: /* BRCT R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1); - gen_goto_tb(s, 0, s->pc + (i2 * 2LL)); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 4); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i32(tmp32_1); - break; - case 0x7: /* BRCTG R1,I2 [RI] */ - tmp = load_reg(r1); - tcg_gen_subi_i64(tmp, tmp, 1); - store_reg(r1, tmp); - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1); - gen_goto_tb(s, 0, s->pc + (i2 * 2LL)); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 4); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2574,7 +2506,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; TCGv_i32 vl; - int l1; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -2586,32 +2517,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) /* set addressing mode, but we only do 64bit anyways */ break; #endif - case 0x6: /* BCTR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - - if (r2) { - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1); - - /* not taking the branch, jump to after the instruction */ - gen_goto_tb(s, 0, s->pc + 2); - gen_set_label(l1); - - /* take the branch, move R2 into psw.addr */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_mov_i64(psw_addr, tmp); - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - } - break; case 0xa: /* SVC I [RR] */ insn = ld_code2(env, s->pc); debug_insn(insn); @@ -2709,30 +2614,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x46: /* BCT R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tcg_temp_free_i64(tmp); - - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1); - - /* not taking the branch, jump to after the instruction */ - gen_goto_tb(s, 0, s->pc + 4); - gen_set_label(l1); - - /* take the branch, move R2 into psw.addr */ - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tcg_gen_mov_i64(psw_addr, tmp); - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3842,6 +3723,49 @@ static ExitStatus op_bc(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_bct32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + TCGv_i64 t; + + c.cond = TCG_COND_NE; + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_subi_i64(t, regs[r1], 1); + store_reg32_i64(r1, t); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_const_i32(0); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bct64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + c.cond = TCG_COND_NE; + c.is_64 = true; + c.g1 = true; + c.g2 = false; + + tcg_gen_subi_i64(regs[r1], regs[r1], 1); + c.u.s64.a = regs[r1]; + c.u.s64.b = tcg_const_i64(0); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; From 891452e5e274967ffb87d10791620154f2cdc303 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 14:02:02 -0700 Subject: [PATCH 034/149] target-s390: Convert DIVIDE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 5 +- target-s390x/insn-data.def | 14 +++ target-s390x/int_helper.c | 47 +++++--- target-s390x/translate.c | 215 +++++++++---------------------------- 4 files changed, 103 insertions(+), 178 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index a45b1c362b..dcc3fce502 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -10,7 +10,10 @@ DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_3(dlg, void, env, i32, i64) +DEF_HELPER_3(divs32, s64, env, s64, s64) +DEF_HELPER_3(divu32, i64, env, i64, i64) +DEF_HELPER_3(divs64, s64, env, s64, s64) +DEF_HELPER_4(divu64, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8ea6630c43..921c216b7d 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -131,6 +131,20 @@ C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* DIVIDE */ + C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) + C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) +/* DIVIDE LOGICAL */ + C(0xb997, DLR, RRE, Z, r1_D32, r2_32u, new_P, r1_P32, divu32, 0) + C(0xe397, DL, RXY_a, Z, r1_D32, m2_32u, new_P, r1_P32, divu32, 0) + C(0xb987, DLGR, RRE, Z, 0, r2_o, r1_P, 0, divu64, 0) + C(0xe387, DLG, RXY_a, Z, 0, m2_64, r1_P, 0, divu64, 0) +/* DIVIDE SINGLE */ + C(0xb90d, DSGR, RRE, Z, r1p1, r2, r1_P, 0, divs64, 0) + C(0xb91d, DSGFR, RRE, Z, r1p1, r2_32s, r1_P, 0, divs64, 0) + C(0xe30d, DSG, RXY_a, Z, r1p1, m2_64, r1_P, 0, divs64, 0) + C(0xe31d, DSGF, RXY_a, Z, r1p1, m2_32s, r1_P, 0, divs64, 0) + /* EXCLUSIVE OR */ C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 17c4771e41..80e17f5b1f 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -37,32 +37,51 @@ uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) return reth; } -/* 128 -> 64/64 unsigned division */ -void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +/* 64/32 -> 32 signed division */ +int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b) { - uint64_t divisor = v2; + env->retxl = a % (int32_t)b; + return a / (int32_t)b; +} - if (!env->regs[r1]) { +/* 64/32 -> 32 unsigned division */ +uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b) +{ + env->retxl = a % (uint32_t)b; + return a / (uint32_t)b; +} + +/* 64/64 -> 64 signed division */ +int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) +{ + env->retxl = a % b; + return a / b; +} + +/* 128 -> 64/64 unsigned division */ +uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t b) +{ + uint64_t ret; + if (ah == 0) { /* 64 -> 64/64 case */ - env->regs[r1] = env->regs[r1 + 1] % divisor; - env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; - return; + env->retxl = al % b; + ret = al / b; } else { + /* ??? Move i386 idivq helper to host-utils. */ #if HOST_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ - __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | - (env->regs[r1 + 1]); - __uint128_t quotient = dividend / divisor; - __uint128_t remainder = dividend % divisor; - - env->regs[r1 + 1] = quotient; - env->regs[r1] = remainder; + __uint128_t a = ((__uint128_t)ah << 64) | al; + __uint128_t q = a / b; + env->retxl = a % b; + ret = q; #else /* 32-bit hosts would need special wrapper functionality - just abort if we encounter such a case; it's very unlikely anyways. */ cpu_abort(env, "128 -> 64/64 division not implemented\n"); #endif } + return ret; } /* absolute value 32-bit */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index fdf0129a29..5667155c4a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1232,31 +1232,13 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { - TCGv_i64 addr, tmp, tmp2, tmp3, tmp4; + TCGv_i64 addr, tmp2, tmp3; TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); addr = get_address(s, x2, b2, d2); switch (op) { - case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ - case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0x1d) { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1 + 1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_div_i64(tmp3, tmp4, tmp2); - store_reg(r1 + 1, tmp3); - tcg_gen_rem_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0xf: /* LRVG R1,D2(X2,B2) [RXE] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); @@ -1306,34 +1288,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg8(r1, tmp3); tcg_temp_free_i64(tmp3); break; - case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_dlg(cpu_env, tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x97: /* DL R1,D2(X2,B2) [RXY] */ - /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ - /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ - tmp = load_reg(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp3); - - tcg_gen_rem_i64(tmp3, tmp, tmp2); - tcg_gen_div_i64(tmp, tmp, tmp2); - store_reg32_i64((r1 + 1) & 15, tmp); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2414,31 +2368,11 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, int r2) { - TCGv_i64 tmp, tmp2, tmp3; + TCGv_i64 tmp; TCGv_i32 tmp32_1; LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0xd: /* DSGR R1,R2 [RRE] */ - case 0x1d: /* DSGFR R1,R2 [RRE] */ - tmp = load_reg(r1 + 1); - if (op == 0xd) { - tmp2 = load_reg(r2); - } else { - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - } - tmp3 = tcg_temp_new_i64(); - tcg_gen_div_i64(tmp3, tmp, tmp2); - store_reg(r1 + 1, tmp3); - tcg_gen_rem_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x17: /* LLGTR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tmp = tcg_temp_new_i64(); @@ -2465,32 +2399,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0x87: /* DLGR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - gen_helper_dlg(cpu_env, tmp32_1, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; - case 0x97: /* DLR R1,R2 [RRE] */ - /* reg(r1) = reg(r1, r1+1) % reg(r2) */ - /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp3); - - tcg_gen_rem_i64(tmp3, tmp, tmp2); - tcg_gen_div_i64(tmp, tmp, tmp2); - store_reg32_i64((r1 + 1) & 15, tmp); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; default: LOG_DISAS("illegal b9 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2543,41 +2451,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x1d: /* DR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - tmp32_3 = load_reg32(r2); - - tmp = tcg_temp_new_i64(); /* dividend */ - tmp2 = tcg_temp_new_i64(); /* divisor */ - tmp3 = tcg_temp_new_i64(); - - /* dividend is r(r1 << 32) | r(r1 + 1) */ - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_2); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - - /* divisor is r(r2) */ - tcg_gen_ext_i32_i64(tmp2, tmp32_3); - - tcg_gen_div_i64(tmp3, tmp, tmp2); - tcg_gen_rem_i64(tmp, tmp, tmp2); - - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - tcg_gen_trunc_i64_i32(tmp32_2, tmp3); - - store_reg32(r1, tmp32_1); /* remainder */ - store_reg32(r1 + 1, tmp32_2); /* quotient */ - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x28: /* LDR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -2626,40 +2499,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x5d: /* D R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - /* dividend is r(r1 << 32) | r(r1 + 1) */ - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_2); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - - /* divisor is in memory */ - tcg_gen_qemu_ld32s(tmp2, tmp3, get_mem_index(s)); - - /* XXX divisor == 0 -> FixP divide exception */ - - tcg_gen_div_i64(tmp3, tmp, tmp2); - tcg_gen_rem_i64(tmp, tmp, tmp2); - - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - tcg_gen_trunc_i64_i32(tmp32_2, tmp3); - - store_reg32(r1, tmp32_1); /* remainder */ - store_reg32(r1 + 1, tmp32_2); /* quotient */ - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x60: /* STD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3766,6 +3605,34 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_divs32(DisasContext *s, DisasOps *o) +{ + gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divu32(DisasContext *s, DisasOps *o) +{ + gen_helper_divu32(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divs64(DisasContext *s, DisasOps *o) +{ + gen_helper_divs64(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divu64(DisasContext *s, DisasOps *o) +{ + gen_helper_divu64(o->out2, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out); + return NO_EXIT; +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; @@ -4089,6 +3956,12 @@ static void prep_new(DisasContext *s, DisasFields *f, DisasOps *o) o->out = tcg_temp_new_i64(); } +static void prep_new_P(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = tcg_temp_new_i64(); + o->out2 = tcg_temp_new_i64(); +} + static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = regs[get_field(f, r1)]; @@ -4120,6 +3993,14 @@ static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(get_field(f, r1), o->out); } +static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + store_reg32_i64(r1, o->out); + store_reg32_i64((r1 + 1) & 15, o->out2); +} + static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ @@ -4183,6 +4064,14 @@ static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_ext32u_i64(o->in1, regs[(r1 + 1) & 15]); } +static void in1_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]); +} + static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); From b4e2bd3563af75ba5b9fe809c8cf79d2d34aecf3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 17:27:40 -0700 Subject: [PATCH 035/149] target-s390: Send signals for divide Signed-off-by: Richard Henderson --- target-s390x/cpu.h | 2 ++ target-s390x/int_helper.c | 51 +++++++++++++++++++++++++++++++++----- target-s390x/misc_helper.c | 20 +++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index ea1bc8625e..69269a14ca 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -931,5 +931,7 @@ uint32_t set_cc_nz_f64(float64 v); /* misc_helper.c */ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); +void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, + uintptr_t retaddr); #endif diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 80e17f5b1f..839c0e1500 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -38,22 +38,54 @@ uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) } /* 64/32 -> 32 signed division */ -int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b) +int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) { - env->retxl = a % (int32_t)b; - return a / (int32_t)b; + int32_t ret, b = b64; + int64_t q; + + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + ret = q = a / b; + env->retxl = a % b; + + /* Catch non-representable quotient. */ + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + return ret; } /* 64/32 -> 32 unsigned division */ -uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b) +uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) { - env->retxl = a % (uint32_t)b; - return a / (uint32_t)b; + uint32_t ret, b = b64; + uint64_t q; + + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + ret = q = a / b; + env->retxl = a % b; + + /* Catch non-representable quotient. */ + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + return ret; } /* 64/64 -> 64 signed division */ int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) { + /* Catch divide by zero, and non-representable quotient (MIN / -1). */ + if (b == 0 || (b == -1 && a == (1ll << 63))) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } env->retxl = a % b; return a / b; } @@ -63,6 +95,10 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t b) { uint64_t ret; + /* Signal divide by zero. */ + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } if (ah == 0) { /* 64 -> 64/64 case */ env->retxl = al % b; @@ -75,6 +111,9 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, __uint128_t q = a / b; env->retxl = a % b; ret = q; + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } #else /* 32-bit hosts would need special wrapper functionality - just abort if we encounter such a case; it's very unlikely anyways. */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 2aa1ed0b5e..6dca0ebabd 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -41,6 +41,26 @@ #define HELPER_LOG(x...) #endif +/* Raise an exception dynamically from a helper function. */ +void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, + uintptr_t retaddr) +{ + int t; + + env->exception_index = EXCP_PGM; + env->int_pgm_code = excp; + + /* Use the (ultimate) callers address to find the insn that trapped. */ + cpu_restore_state(env, retaddr); + + /* Advance past the insn. */ + t = cpu_ldub_code(env, env->psw.addr); + env->int_pgm_ilen = t = get_ilen(t); + env->psw.addr += 2 * t; + + cpu_loop_exit(env); +} + /* Raise an exception statically from a TB. */ void HELPER(exception)(CPUS390XState *env, uint32_t excp) { From 00d2dc192fb866d077935f0dd298472d65d87eb6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:20:58 -0700 Subject: [PATCH 036/149] target-s390: Convert TEST UNDER MASK Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 25 +++++-------- target-s390x/insn-data.def | 8 +++++ target-s390x/translate.c | 74 ++++++-------------------------------- 3 files changed, 27 insertions(+), 80 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 880e3b234d..d20342cda0 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "helper.h" +#include "qemu/host-utils.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER @@ -86,13 +87,11 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, } } -static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, - uint32_t mask) +static uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) { - uint16_t r = val & mask; + uint32_t r = val & mask; - HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); - if (r == 0 || mask == 0) { + if (r == 0) { return 0; } else if (r == mask) { return 3; @@ -101,23 +100,17 @@ static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, } } -/* set condition code for test under mask */ -static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, - uint32_t mask) +static uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint64_t mask) { - uint16_t r = val & mask; + uint64_t r = val & mask; - HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); - if (r == 0 || mask == 0) { + if (r == 0) { return 0; } else if (r == mask) { return 3; } else { - while (!(mask & 0x8000)) { - mask <<= 1; - val <<= 1; - } - if (val & 0x8000) { + int top = clz64(mask); + if ((int64_t)(val << top) < 0) { return 2; } else { return 1; diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 921c216b7d..f70ede9bcf 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -336,3 +336,11 @@ C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb, subb64) C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32) C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64) + +/* TEST UNDER MASK */ + C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) + C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) + D(0xa702, TMHH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 48) + D(0xa703, TMHL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 32) + D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) + D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5667155c4a..4e3451964f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1514,16 +1514,6 @@ do_mh: tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x51: /* TMY D1(B1),I2 [SIY] */ - tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ - tmp2 = tcg_const_i64((r1 << 4) | r3); - tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s)); - /* yes, this is a 32 bit operation with 64 bit tcg registers, because - that incurs less conversions */ - cmp_64(s, tmp, tmp2, CC_OP_TM_32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x52: /* MVIY D1(B1),I2 [SIY] */ tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ tmp2 = tcg_const_i64((r1 << 4) | r3); @@ -1672,44 +1662,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(addr); } -static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) -{ - TCGv_i64 tmp, tmp2; - - LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); - switch (op) { - case 0x0: /* TMLH or TMH R1,I2 [RI] */ - case 0x1: /* TMLL or TML R1,I2 [RI] */ - case 0x2: /* TMHH R1,I2 [RI] */ - case 0x3: /* TMHL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64((uint16_t)i2); - switch (op) { - case 0x0: - tcg_gen_shri_i64(tmp, tmp, 16); - break; - case 0x1: - break; - case 0x2: - tcg_gen_shri_i64(tmp, tmp, 48); - break; - case 0x3: - tcg_gen_shri_i64(tmp, tmp, 32); - break; - } - tcg_gen_andi_i64(tmp, tmp, 0xffff); - cmp_64(s, tmp, tmp2, CC_OP_TM_64); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - default: - LOG_DISAS("illegal a7 operation 0x%x\n", op); - gen_illegal_opcode(s); - return; - } -} - static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { @@ -2678,15 +2630,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp3); tcg_temp_free_i64(tmp4); break; - case 0x91: /* TM D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_const_i64(i2); - tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s)); - cmp_64(s, tmp, tmp2, CC_OP_TM_32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x92: /* MVI D1(B1),I2 [SI] */ insn = ld_code4(env, s->pc); tmp = decode_si(s, insn, &i2, &b1, &d1); @@ -2744,13 +2687,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xa7: - insn = ld_code4(env, s->pc); - r1 = (insn >> 20) & 0xf; - op = (insn >> 16) & 0xf; - i2 = (short)insn; - disas_a7(env, s, op, r1, i2); - break; case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -3945,6 +3881,16 @@ static void cout_subb64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, o->out); } +static void cout_tm32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_TM_32, o->in1, o->in2); +} + +static void cout_tm64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_TM_64, o->in1, o->in2); +} + /* ====================================================================== */ /* The "PREPeration" generators. These initialize the DisasOps.OUT fields with the TCG register to which we will write. Used in combination with From d9a39927993a186b039d5be66cc85c0e735a78bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:28:56 -0700 Subject: [PATCH 037/149] target-s390: Convert SET ADDRESSING MODE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f70ede9bcf..69af25dbaa 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -344,3 +344,10 @@ D(0xa703, TMHL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 32) D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) + +#ifndef CONFIG_USER_ONLY +/* SET ADDRESSING MODE */ + /* We only do 64-bit, so accept this as a no-op. + Let SAM24 and SAM31 signal illegal instruction. */ + C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +#endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 4e3451964f..26ca49b28a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2371,12 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { -#ifndef CONFIG_USER_ONLY - case 0x01: /* SAM */ - insn = ld_code2(env, s->pc); - /* set addressing mode, but we only do 64bit anyways */ - break; -#endif case 0xa: /* SVC I [RR] */ insn = ld_code2(env, s->pc); debug_insn(insn); From b9836c1acd4ecb286bd1617857cc52df7b75c414 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:41:05 -0700 Subject: [PATCH 038/149] target-s390: Convert SUPERVISOR CALL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 34 +++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 69af25dbaa..7a0c999194 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -337,6 +337,9 @@ C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32) C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64) +/* SUPERVISOR CALL */ + C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) + /* TEST UNDER MASK */ C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 26ca49b28a..e2b7671de8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2371,21 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0xa: /* SVC I [RR] */ - insn = ld_code2(env, s->pc); - debug_insn(insn); - i = insn & 0xff; - update_psw_addr(s); - gen_op_calc_cc(s); - tmp32_1 = tcg_const_i32(i); - tmp32_2 = tcg_const_i32(s->next_pc - s->pc); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); - tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); - gen_exception(EXCP_SVC); - s->is_jmp = DISAS_EXCP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xe: /* MVCL R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3717,6 +3702,25 @@ static ExitStatus op_subb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_svc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 t; + + update_psw_addr(s); + gen_op_calc_cc(s); + + t = tcg_const_i32(get_field(s->fields, i1) & 0xff); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); + tcg_temp_free_i32(t); + + t = tcg_const_i32(s->next_pc - s->pc); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); + tcg_temp_free_i32(t); + + gen_exception(EXCP_SVC); + return EXIT_NORETURN; +} + static ExitStatus op_xor(DisasContext *s, DisasOps *o) { tcg_gen_xor_i64(o->out, o->in1, o->in2); From e1eaada955aab907b53a091b85421de9e8b8dd9c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:46:49 -0700 Subject: [PATCH 039/149] target-s390: Convert MOVE LONG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 23 ++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7a0c999194..995c0f6e75 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -246,6 +246,9 @@ C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) +/* MOVE LONG */ + C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) + /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e2b7671de8..0437f9b9a4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2371,17 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0xe: /* MVCL R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_mvcl(cc_op, cpu_env, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x28: /* LDR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3607,6 +3596,18 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2)); + potential_page_fault(s); + gen_helper_mvcl(cc_op, cpu_env, r1, r2); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From d764a8d12b24c8b97fe3ff2193aec04079e8db20 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 12:24:24 -0700 Subject: [PATCH 040/149] target-s390: Convert FP LOAD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++ target-s390x/translate.c | 102 ++++++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 35 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 995c0f6e75..c3b1f6f5ef 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -173,6 +173,13 @@ C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) + C(0x2800, LDR, RR_a, Z, 0, f2_o, 0, f1, mov2, 0) + C(0x6800, LD, RX_a, Z, 0, m2_64, 0, f1, mov2, 0) + C(0xed65, LDY, RXY_a, LD, 0, m2_64, 0, f1, mov2, 0) + C(0x3800, LER, RR_a, Z, 0, e2, 0, cond_e1e2, mov2, 0) + C(0x7800, LE, RX_a, Z, 0, m2_32u, 0, e1, mov2, 0) + C(0xed64, LEY, RXY_a, LD, 0, m2_32u, 0, e1, mov2, 0) + C(0xb365, LXR, RRE, Z, 0, x2_o, 0, x1, movx, 0) /* LOAD IMMEDIATE */ C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) /* LOAD RELATIVE LONG */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0437f9b9a4..d459b25170 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -224,6 +224,13 @@ static inline TCGv_i32 load_freg32(int reg) return r; } +static inline TCGv_i64 load_freg32_i64(int reg) +{ + TCGv_i64 r = tcg_temp_new_i64(); + tcg_gen_shri_i64(r, fregs[reg], 32); + return r; +} + static inline TCGv_i32 load_reg32(int reg) { TCGv_i32 r = tcg_temp_new_i32(); @@ -293,6 +300,11 @@ static inline void store_freg32(int reg, TCGv_i32 v) #endif } +static inline void store_freg32_i64(int reg, TCGv_i64 v) +{ + tcg_gen_deposit_i64(fregs[reg], fregs[reg], v, 32, 32); +} + static inline void return_low128(TCGv_i64 dest) { tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); @@ -2371,20 +2383,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x28: /* LDR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp = load_freg(r2); - store_freg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x38: /* LER R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_freg32(r2); - store_freg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x43: /* IC R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -2427,15 +2425,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x68: /* LD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); - store_freg(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x70: /* STE R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -2447,18 +2436,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x78: /* LE R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_freg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ @@ -3596,6 +3573,18 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_movx(DisasContext *s, DisasOps *o) +{ + o->out = o->in1; + o->out2 = o->in2; + o->g_out = o->g_in1; + o->g_out2 = o->g_in2; + TCGV_UNUSED_I64(o->in1); + TCGV_UNUSED_I64(o->in2); + o->g_in1 = o->g_in2 = false; + return NO_EXIT; +} + static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); @@ -3955,6 +3944,23 @@ static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(r1, o->out); } +static void wout_e1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_freg32_i64(get_field(f, r1), o->out); +} + +static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_freg(get_field(f, r1), o->out); +} + +static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int f1 = get_field(s->fields, r1); + store_freg(f1, o->out); + store_freg((f1 + 2) & 15, o->out2); +} + static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) { if (get_field(f, r1) != get_field(f, r2)) { @@ -3962,6 +3968,13 @@ static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) } } +static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + if (get_field(f, r1) != get_field(f, r2)) { + store_freg32_i64(get_field(f, r1), o->out); + } +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); @@ -4137,6 +4150,25 @@ static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]); } +static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_freg32_i64(get_field(f, r2)); +} + +static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = fregs[get_field(f, r2)]; + o->g_in2 = true; +} + +static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int f2 = get_field(f, r2); + o->in1 = fregs[f2]; + o->in2 = fregs[(f2 + 2) & 15]; + o->g_in1 = o->g_in2 = true; +} + static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; From afdc70bea01452367e372db7e2168b71bb3aa9b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 07:12:29 -0700 Subject: [PATCH 041/149] target-s390: Convert INSERT CHARACTER Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 35 +++++++++++++---------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c3b1f6f5ef..f37e69a602 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -157,6 +157,9 @@ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) +/* INSERT CHARACTER */ + C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) + C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) /* INSERT IMMEDIATE */ D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d459b25170..25bbf45f2c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -283,12 +283,6 @@ static inline void store_reg16(int reg, TCGv_i32 v) #endif } -static inline void store_reg8(int reg, TCGv_i64 v) -{ - /* 8 bit register writes keep the upper bytes */ - tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 8); -} - static inline void store_freg32(int reg, TCGv_i32 v) { /* 32 bit register writes keep the lower half */ @@ -1244,7 +1238,7 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { - TCGv_i64 addr, tmp2, tmp3; + TCGv_i64 addr, tmp2; TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", @@ -1294,12 +1288,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp3, addr, get_mem_index(s)); - store_reg8(r1, tmp3); - tcg_temp_free_i64(tmp3); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2383,15 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x43: /* IC R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - store_reg8(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x44: /* EX R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3922,6 +3901,12 @@ static void wout_r1(DisasContext *s, DisasFields *f, DisasOps *o) store_reg(get_field(f, r1), o->out); } +static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8); +} + static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); @@ -4180,6 +4165,12 @@ static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); } +static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s)); +} + static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From 443aaeb8991022f3eadd2b65e14e805093e2a0e6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 12:36:10 -0700 Subject: [PATCH 042/149] target-s390: Cleanup cc computation helpers The inline markers hid the fact that {n}abs_32 were unused because of typos in the main do_calc_cc function. Let the compiler handle auto-inlining here. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 140 +++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 79 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index d20342cda0..3d89fb9dbf 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -29,8 +29,7 @@ #define HELPER_LOG(x...) #endif -static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, - int32_t dst) +static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst) { if (src == dst) { return 0; @@ -41,13 +40,12 @@ static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, } } -static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_ltgt0_32(int32_t dst) { - return cc_calc_ltgt_32(env, dst, 0); + return cc_calc_ltgt_32(dst, 0); } -static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, - int64_t dst) +static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst) { if (src == dst) { return 0; @@ -58,13 +56,12 @@ static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, } } -static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_ltgt0_64(int64_t dst) { - return cc_calc_ltgt_64(env, dst, 0); + return cc_calc_ltgt_64(dst, 0); } -static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, - uint32_t dst) +static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst) { if (src == dst) { return 0; @@ -75,8 +72,7 @@ static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, } } -static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, - uint64_t dst) +static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst) { if (src == dst) { return 0; @@ -87,7 +83,7 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, } } -static uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) +static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask) { uint32_t r = val & mask; @@ -100,7 +96,7 @@ static uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) } } -static uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint64_t mask) +static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask) { uint64_t r = val & mask; @@ -118,13 +114,12 @@ static uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint64_t mask) } } -static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) +static uint32_t cc_calc_nz(uint64_t dst) { return !!dst; } -static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) +static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -139,14 +134,12 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, } } -static uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_addu_64(uint64_t a1, uint64_t a2, uint64_t ar) { return (ar != 0) + 2 * (ar < a1); } -static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_addc_64(uint64_t a1, uint64_t a2, uint64_t ar) { /* Recover a2 + carry_in. */ uint64_t a2c = ar - a1; @@ -156,8 +149,7 @@ static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1, return (ar != 0) + 2 * carry_out; } -static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) +static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -172,8 +164,7 @@ static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, } } -static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar) { if (ar == 0) { return 2; @@ -186,8 +177,7 @@ static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, } } -static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar) { /* We had borrow-in if normal subtraction isn't equal. */ int borrow_in = ar - (a1 - a2); @@ -205,7 +195,7 @@ static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1, return (ar != 0) + 2 * !borrow_out; } -static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_abs_64(int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -216,12 +206,12 @@ static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) } } -static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_nabs_64(int64_t dst) { return !!dst; } -static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_comp_64(int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -235,8 +225,7 @@ static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) } -static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) +static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -251,14 +240,12 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, } } -static uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_addu_32(uint32_t a1, uint32_t a2, uint32_t ar) { return (ar != 0) + 2 * (ar < a1); } -static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_addc_32(uint32_t a1, uint32_t a2, uint32_t ar) { /* Recover a2 + carry_in. */ uint32_t a2c = ar - a1; @@ -268,8 +255,7 @@ static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1, return (ar != 0) + 2 * carry_out; } -static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) +static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -284,8 +270,7 @@ static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, } } -static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar) { if (ar == 0) { return 2; @@ -298,8 +283,7 @@ static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, } } -static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar) { /* We had borrow-in if normal subtraction isn't equal. */ int borrow_in = ar - (a1 - a2); @@ -317,7 +301,7 @@ static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1, return (ar != 0) + 2 * !borrow_out; } -static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_abs_32(int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -328,12 +312,12 @@ static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) } } -static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_nabs_32(int32_t dst) { return !!dst; } -static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_comp_32(int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -347,8 +331,7 @@ static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) } /* calculate condition code for insert character under mask insn */ -static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, - uint32_t val) +static uint32_t cc_calc_icm_32(uint32_t mask, uint32_t val) { uint32_t cc; @@ -379,8 +362,7 @@ static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, return cc; } -static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, - uint64_t shift) +static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) { uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); uint64_t match, r; @@ -409,7 +391,7 @@ static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, } -static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, +static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) { uint32_t r = 0; @@ -423,93 +405,93 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, r = cc_op; break; case CC_OP_LTGT0_32: - r = cc_calc_ltgt0_32(env, dst); + r = cc_calc_ltgt0_32(dst); break; case CC_OP_LTGT0_64: - r = cc_calc_ltgt0_64(env, dst); + r = cc_calc_ltgt0_64(dst); break; case CC_OP_LTGT_32: - r = cc_calc_ltgt_32(env, src, dst); + r = cc_calc_ltgt_32(src, dst); break; case CC_OP_LTGT_64: - r = cc_calc_ltgt_64(env, src, dst); + r = cc_calc_ltgt_64(src, dst); break; case CC_OP_LTUGTU_32: - r = cc_calc_ltugtu_32(env, src, dst); + r = cc_calc_ltugtu_32(src, dst); break; case CC_OP_LTUGTU_64: - r = cc_calc_ltugtu_64(env, src, dst); + r = cc_calc_ltugtu_64(src, dst); break; case CC_OP_TM_32: - r = cc_calc_tm_32(env, src, dst); + r = cc_calc_tm_32(src, dst); break; case CC_OP_TM_64: - r = cc_calc_tm_64(env, src, dst); + r = cc_calc_tm_64(src, dst); break; case CC_OP_NZ: - r = cc_calc_nz(env, dst); + r = cc_calc_nz(dst); break; case CC_OP_ADD_64: - r = cc_calc_add_64(env, src, dst, vr); + r = cc_calc_add_64(src, dst, vr); break; case CC_OP_ADDU_64: - r = cc_calc_addu_64(env, src, dst, vr); + r = cc_calc_addu_64(src, dst, vr); break; case CC_OP_ADDC_64: - r = cc_calc_addc_64(env, src, dst, vr); + r = cc_calc_addc_64(src, dst, vr); break; case CC_OP_SUB_64: - r = cc_calc_sub_64(env, src, dst, vr); + r = cc_calc_sub_64(src, dst, vr); break; case CC_OP_SUBU_64: - r = cc_calc_subu_64(env, src, dst, vr); + r = cc_calc_subu_64(src, dst, vr); break; case CC_OP_SUBB_64: - r = cc_calc_subb_64(env, src, dst, vr); + r = cc_calc_subb_64(src, dst, vr); break; case CC_OP_ABS_64: - r = cc_calc_abs_64(env, dst); + r = cc_calc_abs_64(dst); break; case CC_OP_NABS_64: - r = cc_calc_nabs_64(env, dst); + r = cc_calc_nabs_64(dst); break; case CC_OP_COMP_64: - r = cc_calc_comp_64(env, dst); + r = cc_calc_comp_64(dst); break; case CC_OP_ADD_32: - r = cc_calc_add_32(env, src, dst, vr); + r = cc_calc_add_32(src, dst, vr); break; case CC_OP_ADDU_32: - r = cc_calc_addu_32(env, src, dst, vr); + r = cc_calc_addu_32(src, dst, vr); break; case CC_OP_ADDC_32: - r = cc_calc_addc_32(env, src, dst, vr); + r = cc_calc_addc_32(src, dst, vr); break; case CC_OP_SUB_32: - r = cc_calc_sub_32(env, src, dst, vr); + r = cc_calc_sub_32(src, dst, vr); break; case CC_OP_SUBU_32: - r = cc_calc_subu_32(env, src, dst, vr); + r = cc_calc_subu_32(src, dst, vr); break; case CC_OP_SUBB_32: - r = cc_calc_subb_32(env, src, dst, vr); + r = cc_calc_subb_32(src, dst, vr); break; case CC_OP_ABS_32: - r = cc_calc_abs_64(env, dst); + r = cc_calc_abs_32(dst); break; case CC_OP_NABS_32: - r = cc_calc_nabs_64(env, dst); + r = cc_calc_nabs_32(dst); break; case CC_OP_COMP_32: - r = cc_calc_comp_32(env, dst); + r = cc_calc_comp_32(dst); break; case CC_OP_ICM: - r = cc_calc_icm_32(env, src, dst); + r = cc_calc_icm_32(src, dst); break; case CC_OP_SLAG: - r = cc_calc_slag(env, src, dst); + r = cc_calc_slag(src, dst); break; case CC_OP_LTGT_F32: From 58a9e35bcc23d44142a2a58ddf3fae51749f3f01 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 13:13:09 -0700 Subject: [PATCH 043/149] target-s390: Convert INSERT CHARACTERS UNDER MASK Change the CC handling to be more like TEST UNDER MASK, with val & mask. This lets us handle ICMH much more like ICM. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 31 ++------- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 4 ++ target-s390x/mem_helper.c | 33 --------- target-s390x/translate.c | 136 +++++++++++++++++-------------------- 5 files changed, 74 insertions(+), 131 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 3d89fb9dbf..575f7c3e75 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -331,35 +331,18 @@ static uint32_t cc_calc_comp_32(int32_t dst) } /* calculate condition code for insert character under mask insn */ -static uint32_t cc_calc_icm_32(uint32_t mask, uint32_t val) +static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) { - uint32_t cc; - - HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); - if (mask == 0xf) { - if (!val) { - return 0; - } else if (val & 0x80000000) { + if ((val & mask) == 0) { + return 0; + } else { + int top = clz64(mask); + if ((int64_t)(val << top) < 0) { return 1; } else { return 2; } } - - if (!val || !mask) { - cc = 0; - } else { - while (mask != 1) { - mask >>= 1; - val >>= 8; - } - if (val & 0x80) { - cc = 1; - } else { - cc = 2; - } - } - return cc; } static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) @@ -488,7 +471,7 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, break; case CC_OP_ICM: - r = cc_calc_icm_32(src, dst); + r = cc_calc_icm(src, dst); break; case CC_OP_SLAG: r = cc_calc_slag(src, dst); diff --git a/target-s390x/helper.h b/target-s390x/helper.h index dcc3fce502..5a0f6965a4 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -27,7 +27,6 @@ DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) DEF_HELPER_4(stcmh, void, env, i32, i64, i32) -DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f37e69a602..38a93e3111 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -160,6 +160,10 @@ /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) +/* INSERT CHARACTERS UNDER MASK */ + D(0xbf00, ICM, RS_b, Z, 0, a2, r1, 0, icm, 0, 0) + D(0xeb81, ICMY, RSY_b, LD, 0, a2, r1, 0, icm, 0, 0) + D(0xeb80, ICMH, RSY_b, Z, 0, a2, r1, 0, icm, 0, 32) /* INSERT IMMEDIATE */ D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 7eb3790b40..1b63259351 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -629,39 +629,6 @@ void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, } } -/* insert character under mask high; same as icm, but operates on the - upper half of r1 */ -uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address, - uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - uint64_t rmask = 0xff00000000000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = cpu_ldub_data(env, address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 25bbf45f2c..36d8cdd102 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -32,6 +32,7 @@ #include "disas/disas.h" #include "tcg-op.h" #include "qemu/log.h" +#include "qemu/host-utils.h" /* global register indexes */ static TCGv_ptr cpu_env; @@ -561,11 +562,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); -} - static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) { tcg_gen_extu_i32_i64(cc_src, v1); @@ -896,7 +892,6 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_LTGT0_64: case CC_OP_NZ: - case CC_OP_ICM: c->u.s64.a = cc_dst; c->u.s64.b = tcg_const_i64(0); c->g1 = true; @@ -910,6 +905,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_TM_32: case CC_OP_TM_64: + case CC_OP_ICM: c->u.s64.a = tcg_temp_new_i64(); c->u.s64.b = tcg_const_i64(0); tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); @@ -1521,18 +1517,6 @@ do_mh: tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX split CC calculation out */ - gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2361,7 +2345,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3, tmp32_4; + TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; @@ -2786,60 +2770,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - if (r3 == 15) { - /* effectively a 32-bit load */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = tcg_const_i32(r3); - tcg_gen_qemu_ld32u(tmp, tmp, get_mem_index(s)); - store_reg32_i64(r1, tmp); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - set_cc_icm(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - } else if (r3) { - uint32_t mask = 0x00ffffffUL; - uint32_t shift = 24; - int m3 = r3; - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_const_i32(r3); - tmp32_4 = tcg_const_i32(0); - while (m3) { - if (m3 & 8) { - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - if (shift) { - tcg_gen_shli_i32(tmp32_2, tmp32_2, shift); - } - tcg_gen_andi_i32(tmp32_1, tmp32_1, mask); - tcg_gen_or_i32(tmp32_1, tmp32_1, tmp32_2); - tcg_gen_or_i32(tmp32_4, tmp32_4, tmp32_2); - tcg_gen_addi_i64(tmp, tmp, 1); - } - m3 = (m3 << 1) & 0xf; - mask = (mask >> 8) | 0xff000000UL; - shift -= 8; - } - store_reg32(r1, tmp32_1); - set_cc_icm(s, tmp32_3, tmp32_4); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i32(tmp32_4); - } else { - /* i.e. env->cc = 0 */ - gen_op_movi_cc(s, 0); - } - break; case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ @@ -3493,6 +3423,66 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_icm(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int pos, len, base = s->insn->data; + TCGv_i64 tmp = tcg_temp_new_i64(); + uint64_t ccm; + + switch (m3) { + case 0xf: + /* Effectively a 32-bit load. */ + tcg_gen_qemu_ld32u(tmp, o->in2, get_mem_index(s)); + len = 32; + goto one_insert; + + case 0xc: + case 0x6: + case 0x3: + /* Effectively a 16-bit load. */ + tcg_gen_qemu_ld16u(tmp, o->in2, get_mem_index(s)); + len = 16; + goto one_insert; + + case 0x8: + case 0x4: + case 0x2: + case 0x1: + /* Effectively an 8-bit load. */ + tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); + len = 8; + goto one_insert; + + one_insert: + pos = base + ctz32(m3) * 8; + tcg_gen_deposit_i64(o->out, o->out, tmp, pos, len); + ccm = ((1ull << len) - 1) << pos; + break; + + default: + /* This is going to be a sequence of loads and inserts. */ + pos = base + 32 - 8; + ccm = 0; + while (m3) { + if (m3 & 0x8) { + tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 1); + tcg_gen_deposit_i64(o->out, o->out, tmp, pos, 8); + ccm |= 0xff << pos; + } + m3 = (m3 << 1) & 0xf; + pos -= 8; + } + break; + } + + tcg_gen_movi_i64(tmp, ccm); + gen_op_update2_cc_i64(s, CC_OP_ICM, tmp, o->out); + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; From 6e764e97ca4050f2105b10e158f4fcb2801470be Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 13:48:38 -0700 Subject: [PATCH 044/149] target-s390: Convert EXECUTE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 39 +++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 38a93e3111..0768849266 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -157,6 +157,11 @@ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) +/* EXECUTE */ + C(0x4400, EX, RX_a, Z, r1_o, a2, 0, 0, ex, 0) +/* EXECUTE RELATIVE LONG */ + C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) + /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 36d8cdd102..bece7c56d8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2355,19 +2355,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x44: /* EX R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tmp3 = tcg_const_i64(s->pc + 4); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_ex(cc_op, cpu_env, cc_op, tmp2, tmp, tmp3); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3423,6 +3410,32 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ex(DisasContext *s, DisasOps *o) +{ + /* ??? Perhaps a better way to implement EXECUTE is to set a bit in + tb->flags, (ab)use the tb->cs_base field as the address of + the template in memory, and grab 8 bits of tb->flags/cflags for + the contents of the register. We would then recognize all this + in gen_intermediate_code_internal, generating code for exactly + one instruction. This new TB then gets executed normally. + + On the other hand, this seems to be mostly used for modifying + MVC inside of memcpy, which needs a helper call anyway. So + perhaps this doesn't bear thinking about any further. */ + + TCGv_i64 tmp; + + update_psw_addr(s); + gen_op_calc_cc(s); + + tmp = tcg_const_i64(s->next_pc); + gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); + tcg_temp_free_i64(tmp); + + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_icm(DisasContext *s, DisasOps *o) { int m3 = get_field(s->fields, m3); From 00574261e1fcb318fdd4cc1293238fc1f50de341 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 12:26:53 -0700 Subject: [PATCH 045/149] target-s390: Convert FP STORE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 30 +++++++++++------------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0768849266..6b81f69032 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -315,6 +315,10 @@ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) + C(0x6000, STD, RX_a, Z, f1_o, a2, 0, 0, st64, 0) + C(0xed67, STDY, RXY_a, LD, f1_o, a2, 0, 0, st64, 0) + C(0x7000, STE, RX_a, Z, e1, a2, 0, 0, st32, 0) + C(0xed66, STEY, RXY_a, LD, e1, a2, 0, 0, st32, 0) /* STORE RELATIVE LONG */ C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index bece7c56d8..8728b36d25 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2367,25 +2367,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x60: /* STD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_freg(r1); - tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x70: /* STE R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_freg32(r1); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ @@ -4028,6 +4009,17 @@ static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = load_reg(get_field(f, r3)); } +static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_freg32_i64(get_field(f, r1)); +} + +static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = fregs[get_field(f, r1)]; + o->g_in1 = true; +} + static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); From c49daa51a8e19694a611971206e75bd245768e3c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:05:11 -0700 Subject: [PATCH 046/149] target-s390: Convert CONVERT TO DECIMAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6b81f69032..c5c56144fb 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -131,6 +131,10 @@ C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* CONVERT TO DECIMAL */ + C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) + C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) + /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8728b36d25..9f92954db0 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2355,18 +2355,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp32_1, regs[r1]); - gen_helper_cvd(tmp2, tmp32_1); - tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ @@ -3363,6 +3351,18 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_cvd(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i32 t2 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t2, o->in1); + gen_helper_cvd(t1, t2); + tcg_temp_free_i32(t2); + tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s)); + tcg_temp_free_i64(t1); + return NO_EXIT; +} + static ExitStatus op_divs32(DisasContext *s, DisasOps *o) { gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); From 7d30bb73db3a2fa38a33556430754917d5d70c91 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:12:50 -0700 Subject: [PATCH 047/149] target-s390: Convert SET SYSTEM MASK Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 25 +++++++++---------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c5c56144fb..45c36c1607 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -383,4 +383,6 @@ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +/* SET SYSTEM MASK */ + C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9f92954db0..246d0f0a9a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2356,22 +2356,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) switch (opc) { #ifndef CONFIG_USER_ONLY - case 0x80: /* SSM D2(B2) [S] */ - /* Set System Mask */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_andi_i64(tmp3, psw_mask, ~0xff00000000000000ULL); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - tcg_gen_shli_i64(tmp2, tmp2, 56); - tcg_gen_or_i64(psw_mask, tmp3, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x82: /* LPSW D2(B2) [S] */ /* Load PSW */ check_privileged(s); @@ -3607,6 +3591,15 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_ssm(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); + return NO_EXIT; +} +#endif + static ExitStatus op_st8(DisasContext *s, DisasOps *o) { tcg_gen_qemu_st8(o->in1, o->in2, get_mem_index(s)); From 8b5ff57115e60589d772efeaa0c061ad6701e340 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:33:36 -0700 Subject: [PATCH 048/149] target-s390: Convert LOAD PSW Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 41 +++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 45c36c1607..b0bee9baf0 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -379,6 +379,8 @@ D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) #ifndef CONFIG_USER_ONLY +/* LOAD PSW */ + C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 246d0f0a9a..cbfcf41427 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2356,26 +2356,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) switch (opc) { #ifndef CONFIG_USER_ONLY - case 0x82: /* LPSW D2(B2) [S] */ - /* Load PSW */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_addi_i64(tmp, tmp, 4); - tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); - /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ - tcg_gen_shli_i64(tmp2, tmp2, 32); - gen_helper_load_psw(cpu_env, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - /* we need to keep cc_op intact */ - s->is_jmp = DISAS_JUMP; - break; case 0x83: /* DIAG R1,R3,D2 [RS] */ /* Diagnose call (KVM hypercall) */ check_privileged(s); @@ -3511,6 +3491,27 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1, t2; + + check_privileged(s); + + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 4); + tcg_gen_qemu_ld32u(t2, o->in2, get_mem_index(s)); + /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ + tcg_gen_shli_i64(t1, t1, 32); + gen_helper_load_psw(cpu_env, t1, t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return EXIT_NORETURN; +} +#endif + static ExitStatus op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; From 972e35b9665db113c3d4df7d394ee8cbbf7446ee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:41:36 -0700 Subject: [PATCH 049/149] target-s390: Convert DIAGNOSE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 33 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b0bee9baf0..0a0ec0a0c7 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -379,6 +379,8 @@ D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) #ifndef CONFIG_USER_ONLY +/* DIAGNOSE (KVM hypercall) */ + C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* SET ADDRESSING MODE */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index cbfcf41427..6848e31432 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2355,23 +2355,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { -#ifndef CONFIG_USER_ONLY - case 0x83: /* DIAG R1,R3,D2 [RS] */ - /* Diagnose call (KVM hypercall) */ - check_privileged(s); - potential_page_fault(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp32_1 = tcg_const_i32(insn & 0xfff); - tmp2 = load_reg(2); - tmp3 = load_reg(1); - gen_helper_diag(tmp2, cpu_env, tmp32_1, tmp2, tmp3); - store_reg(2, tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; -#endif case 0x88: /* SRL R1,D2(B2) [RS] */ case 0x89: /* SLL R1,D2(B2) [RS] */ case 0x8a: /* SRA R1,D2(B2) [RS] */ @@ -3327,6 +3310,22 @@ static ExitStatus op_cvd(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_diag(DisasContext *s, DisasOps *o) +{ + TCGv_i32 tmp; + + check_privileged(s); + potential_page_fault(s); + + /* We pretend the format is RX_a so that D2 is the field we want. */ + tmp = tcg_const_i32(get_field(s->fields, d2) & 0xfff); + gen_helper_diag(regs[2], cpu_env, tmp, regs[2], regs[1]); + tcg_temp_free_i32(tmp); + return NO_EXIT; +} +#endif + static ExitStatus op_divs32(DisasContext *s, DisasOps *o) { gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); From cbe24bfa91d21766f2953c2da92c1e3dd13d8387 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 09:15:19 -0700 Subject: [PATCH 050/149] target-s390: Convert SHIFT, ROTATE SINGLE Note that we were missing the 32-bit SLA. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 56 +++++++--- target-s390x/cpu.h | 6 +- target-s390x/insn-data.def | 21 ++++ target-s390x/translate.c | 207 +++++++++++++++++++------------------ 4 files changed, 176 insertions(+), 114 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 575f7c3e75..be4202a78e 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -345,34 +345,59 @@ static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) } } -static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) +static uint32_t cc_calc_sla_32(uint32_t src, int shift) { - uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); - uint64_t match, r; + uint32_t mask = ((1U << shift) - 1U) << (32 - shift); + uint32_t sign = 1U << 31; + uint32_t match; + int32_t r; - /* check if the sign bit stays the same */ - if (src & (1ULL << 63)) { + /* Check if the sign bit stays the same. */ + if (src & sign) { match = mask; } else { match = 0; } - if ((src & mask) != match) { - /* overflow */ + /* Overflow. */ return 3; } - r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); - - if ((int64_t)r == 0) { + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { return 0; - } else if ((int64_t)r < 0) { + } else if (r < 0) { return 1; } - return 2; } +static uint32_t cc_calc_sla_64(uint64_t src, int shift) +{ + uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); + uint64_t sign = 1ULL << 63; + uint64_t match; + int64_t r; + + /* Check if the sign bit stays the same. */ + if (src & sign) { + match = mask; + } else { + match = 0; + } + if ((src & mask) != match) { + /* Overflow. */ + return 3; + } + + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { + return 0; + } else if (r < 0) { + return 1; + } + return 2; +} static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) @@ -473,8 +498,11 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ICM: r = cc_calc_icm(src, dst); break; - case CC_OP_SLAG: - r = cc_calc_slag(src, dst); + case CC_OP_SLA_32: + r = cc_calc_sla_32(src, dst); + break; + case CC_OP_SLA_64: + r = cc_calc_sla_64(src, dst); break; case CC_OP_LTGT_F32: diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 69269a14ca..b8e9037eeb 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -478,7 +478,8 @@ enum cc_op { CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ CC_OP_ICM, /* insert characters under mask */ - CC_OP_SLAG, /* Calculate shift left signed */ + CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ + CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ CC_OP_MAX }; @@ -521,7 +522,8 @@ static const char *cc_names[] = { [CC_OP_NZ_F32] = "CC_OP_NZ_F32", [CC_OP_NZ_F64] = "CC_OP_NZ_F64", [CC_OP_ICM] = "CC_OP_ICM", - [CC_OP_SLAG] = "CC_OP_SLAG", + [CC_OP_SLA_32] = "CC_OP_SLA_32", + [CC_OP_SLA_64] = "CC_OP_SLA_64", }; static inline const char *cc_name(int cc_op) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0a0ec0a0c7..6020e04e0b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -315,6 +315,27 @@ D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) +/* ROTATE LEFT SINGLE LOGICAL */ + C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) + C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) + +/* SHIFT LEFT SINGLE */ + D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) + D(0xebdd, SLAK, RSY_a, DO, r3, sh32, new, r1_32, sla, 0, 31) + D(0xeb0b, SLAG, RSY_a, Z, r3, sh64, r1, 0, sla, 0, 63) +/* SHIFT LEFT SINGLE LOGICAL */ + C(0x8900, SLL, RS_a, Z, r1_o, sh32, new, r1_32, sll, 0) + C(0xebdf, SLLK, RSY_a, DO, r3_o, sh32, new, r1_32, sll, 0) + C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh64, r1, 0, sll, 0) +/* SHIFT RIGHT SINGLE */ + C(0x8a00, SRA, RS_a, Z, r1_32s, sh32, new, r1_32, sra, s32) + C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh32, new, r1_32, sra, s32) + C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh64, r1, 0, sra, s64) +/* SHIFT RIGHT SINGLE LOGICAL */ + C(0x8800, SRL, RS_a, Z, r1_32u, sh32, new, r1_32, srl, 0) + C(0xebde, SRLK, RSY_a, DO, r3_32u, sh32, new, r1_32, srl, 0) + C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh64, r1, 0, srl, 0) + /* STORE */ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6848e31432..bb3721d30b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -636,7 +636,8 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_TM_64: case CC_OP_LTGT_F32: case CC_OP_LTGT_F64: - case CC_OP_SLAG: + case CC_OP_SLA_32: + case CC_OP_SLA_64: /* 2 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; @@ -1330,74 +1331,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); switch (op) { - case 0xc: /* SRLG R1,R3,D2(B2) [RSY] */ - case 0xd: /* SLLG R1,R3,D2(B2) [RSY] */ - case 0xa: /* SRAG R1,R3,D2(B2) [RSY] */ - case 0xb: /* SLAG R1,R3,D2(B2) [RSY] */ - case 0x1c: /* RLLG R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - switch (op) { - case 0xc: - tcg_gen_shr_i64(regs[r1], regs[r3], tmp); - break; - case 0xd: - tcg_gen_shl_i64(regs[r1], regs[r3], tmp); - break; - case 0xa: - tcg_gen_sar_i64(regs[r1], regs[r3], tmp); - break; - case 0xb: - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - gen_op_update2_cc_i64(s, CC_OP_SLAG, regs[r3], tmp); - tcg_gen_shl_i64(tmp2, regs[r3], tmp); - /* override sign bit with source sign */ - tcg_gen_andi_i64(tmp2, tmp2, ~0x8000000000000000ULL); - tcg_gen_andi_i64(tmp3, regs[r3], 0x8000000000000000ULL); - tcg_gen_or_i64(regs[r1], tmp2, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x1c: - tcg_gen_rotl_i64(regs[r1], regs[r3], tmp); - break; - default: - tcg_abort(); - break; - } - if (op == 0xa) { - set_cc_s64(s, regs[r1]); - } - tcg_temp_free_i64(tmp); - break; - case 0x1d: /* RLL R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r3); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - switch (op) { - case 0x1d: - tcg_gen_rotl_i32(tmp32_1, tmp32_2, tmp32_1); - break; - default: - tcg_abort(); - break; - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x4: /* LMG R1,R3,D2(B2) [RSE] */ case 0x24: /* STMG R1,R3,D2(B2) [RSE] */ stm_len = 8; @@ -2355,35 +2288,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x88: /* SRL R1,D2(B2) [RS] */ - case 0x89: /* SLL R1,D2(B2) [RS] */ - case 0x8a: /* SRA R1,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp32_2, tmp); - tcg_gen_andi_i32(tmp32_2, tmp32_2, 0x3f); - switch (opc) { - case 0x88: - tcg_gen_shr_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x89: - tcg_gen_shl_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x8a: - tcg_gen_sar_i32(tmp32_1, tmp32_1, tmp32_2); - set_cc_s32(s, tmp32_1); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x8c: /* SRDL R1,D2(B2) [RS] */ case 0x8d: /* SLDL R1,D2(B2) [RS] */ case 0x8e: /* SRDA R1,D2(B2) [RS] */ @@ -3029,6 +2933,20 @@ struct DisasInsn { /* ====================================================================== */ /* Miscelaneous helpers, used by several operations. */ +static void help_l2_shift(DisasContext *s, DisasFields *f, + DisasOps *o, int mask) +{ + int b2 = get_field(f, b2); + int d2 = get_field(f, d2); + + if (b2 == 0) { + o->in2 = tcg_const_i64(d2 & mask); + } else { + o->in2 = get_address(s, 0, b2, d2); + tcg_gen_andi_i64(o->in2, o->in2, mask); + } +} + static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) { if (dest == s->next_pc) { @@ -3591,6 +3509,59 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_rll32(DisasContext *s, DisasOps *o) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 to = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, o->in1); + tcg_gen_trunc_i64_i32(t2, o->in2); + tcg_gen_rotl_i32(to, t1, t2); + tcg_gen_extu_i32_i64(o->out, to); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(to); + return NO_EXIT; +} + +static ExitStatus op_rll64(DisasContext *s, DisasOps *o) +{ + tcg_gen_rotl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sla(DisasContext *s, DisasOps *o) +{ + uint64_t sign = 1ull << s->insn->data; + enum cc_op cco = s->insn->data == 31 ? CC_OP_SLA_32 : CC_OP_SLA_64; + gen_op_update2_cc_i64(s, cco, o->in1, o->in2); + tcg_gen_shl_i64(o->out, o->in1, o->in2); + /* The arithmetic left shift is curious in that it does not affect + the sign bit. Copy that over from the source unchanged. */ + tcg_gen_andi_i64(o->out, o->out, ~sign); + tcg_gen_andi_i64(o->in1, o->in1, sign); + tcg_gen_or_i64(o->out, o->out, o->in1); + return NO_EXIT; +} + +static ExitStatus op_sll(DisasContext *s, DisasOps *o) +{ + tcg_gen_shl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sra(DisasContext *s, DisasOps *o) +{ + tcg_gen_sar_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_srl(DisasContext *s, DisasOps *o) +{ + tcg_gen_shr_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { @@ -3961,6 +3932,18 @@ static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_r1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1)]); +} + +static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); +} + static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ @@ -4002,6 +3985,24 @@ static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = load_reg(get_field(f, r3)); } +static void in1_r3_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = regs[get_field(f, r3)]; + o->g_in1 = true; +} + +static void in1_r3_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r3)]); +} + +static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r3)]); +} + static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_freg32_i64(get_field(f, r1)); @@ -4153,6 +4154,16 @@ static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); } +static void in2_sh32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 31); +} + +static void in2_sh64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 63); +} + static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From a79ba3398a0aa7fdd544ce28d2950b4eeb3c16a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 09:22:23 -0700 Subject: [PATCH 051/149] target-s390: Convert SHIFT DOUBLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 8 ++++++++ target-s390x/translate.c | 30 ------------------------------ 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6020e04e0b..50a176476c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -335,6 +335,14 @@ C(0x8800, SRL, RS_a, Z, r1_32u, sh32, new, r1_32, srl, 0) C(0xebde, SRLK, RSY_a, DO, r3_32u, sh32, new, r1_32, srl, 0) C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh64, r1, 0, srl, 0) +/* SHIFT LEFT DOUBLE */ + D(0x8f00, SLDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sla, 0, 31) +/* SHIFT LEFT DOUBLE LOGICAL */ + C(0x8d00, SLDL, RS_a, Z, r1_D32, sh64, new, r1_D32, sll, 0) +/* SHIFT RIGHT DOUBLE */ + C(0x8e00, SRDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sra, s64) +/* SHIFT RIGHT DOUBLE LOGICAL */ + C(0x8c00, SRDL, RS_a, Z, r1_D32, sh64, new, r1_D32, srl, 0) /* STORE */ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index bb3721d30b..54cd2fa1de 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2288,36 +2288,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x8c: /* SRDL R1,D2(B2) [RS] */ - case 0x8d: /* SLDL R1,D2(B2) [RS] */ - case 0x8e: /* SRDA R1,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); /* shift */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - tcg_gen_concat_i32_i64(tmp2, tmp32_2, tmp32_1); /* operand */ - switch (opc) { - case 0x8c: - tcg_gen_shr_i64(tmp2, tmp2, tmp); - break; - case 0x8d: - tcg_gen_shl_i64(tmp2, tmp2, tmp); - break; - case 0x8e: - tcg_gen_sar_i64(tmp2, tmp2, tmp); - set_cc_s64(s, tmp2); - break; - } - tcg_gen_shri_i64(tmp, tmp2, 32); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - store_reg32(r1, tmp32_1); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - store_reg32(r1 + 1, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x98: /* LM R1,R3,D2(B2) [RS] */ case 0x90: /* STM R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); From 77f8d6c3ed89ee02847709da6508cd4dcc1d2f2d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 09:49:37 -0700 Subject: [PATCH 052/149] target-s390: Convert LOAD, STORE MULTIPLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 14 +++ target-s390x/translate.c | 212 +++++++++++++++++++++---------------- 2 files changed, 137 insertions(+), 89 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 50a176476c..393b425f21 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -269,6 +269,13 @@ C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) +/* LOAD MULTIPLE */ + C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) + C(0xeb98, LMY, RSY_a, LD, 0, a2, 0, 0, lm32, 0) + C(0xeb04, LMG, RSY_a, Z, 0, a2, 0, 0, lm64, 0) +/* LOAD MULTIPLE HIGH */ + C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) + /* MOVE LONG */ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) @@ -364,6 +371,13 @@ /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE MULTIPLE */ + D(0x9000, STM, RS_a, Z, 0, a2, 0, 0, stm, 0, 4) + D(0xeb90, STMY, RSY_a, LD, 0, a2, 0, 0, stm, 0, 4) + D(0xeb24, STMG, RSY_a, Z, 0, a2, 0, 0, stm, 0, 8) +/* STORE MULTIPLE HIGH */ + C(0xeb26, STMH, RSY_a, Z, 0, a2, 0, 0, stmh, 0) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 54cd2fa1de..118f832141 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -273,6 +273,11 @@ static inline void store_reg32_i64(int reg, TCGv_i64 v) tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); } +static inline void store_reg32h_i64(int reg, TCGv_i64 v) +{ + tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); +} + static inline void store_reg16(int reg, TCGv_i32 v) { /* 16 bit register writes keep the upper bytes */ @@ -1324,65 +1329,12 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, int r3, int b2, int d2) { - TCGv_i64 tmp, tmp2, tmp3, tmp4; + TCGv_i64 tmp, tmp2; TCGv_i32 tmp32_1, tmp32_2; - int i, stm_len; LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); switch (op) { - case 0x4: /* LMG R1,R3,D2(B2) [RSE] */ - case 0x24: /* STMG R1,R3,D2(B2) [RSE] */ - stm_len = 8; - goto do_mh; - case 0x26: /* STMH R1,R3,D2(B2) [RSE] */ - case 0x96: /* LMH R1,R3,D2(B2) [RSE] */ - stm_len = 4; -do_mh: - /* Apparently, unrolling lmg/stmg of any size gains performance - - even for very long ones... */ - tmp = get_address(s, 0, b2, d2); - tmp3 = tcg_const_i64(stm_len); - tmp4 = tcg_const_i64(op == 0x26 ? 32 : 4); - for (i = r1;; i = (i + 1) % 16) { - switch (op) { - case 0x4: - tcg_gen_qemu_ld64(regs[i], tmp, get_mem_index(s)); - break; - case 0x96: - tmp2 = tcg_temp_new_i64(); -#if HOST_LONG_BITS == 32 - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(TCGV_HIGH(regs[i]), tmp2); -#else - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_shl_i64(tmp2, tmp2, tmp4); - tcg_gen_ext32u_i64(regs[i], regs[i]); - tcg_gen_or_i64(regs[i], regs[i], tmp2); -#endif - tcg_temp_free_i64(tmp2); - break; - case 0x24: - tcg_gen_qemu_st64(regs[i], tmp, get_mem_index(s)); - break; - case 0x26: - tmp2 = tcg_temp_new_i64(); - tcg_gen_shr_i64(tmp2, regs[i], tmp4); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; - default: - tcg_abort(); - } - if (i == r3) { - break; - } - tcg_gen_add_i64(tmp, tmp, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); @@ -2277,44 +2229,17 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { - TCGv_i64 tmp, tmp2, tmp3, tmp4; + TCGv_i64 tmp, tmp2; TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; + int op, r1, r2, r3, d1, d2, x2, b1, b2, i2, r1b; TCGv_i32 vl; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x98: /* LM R1,R3,D2(B2) [RS] */ - case 0x90: /* STM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_const_i64(4); - tmp4 = tcg_const_i64(0xffffffff00000000ULL); - for (i = r1;; i = (i + 1) % 16) { - if (opc == 0x98) { - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_and_i64(regs[i], regs[i], tmp4); - tcg_gen_or_i64(regs[i], regs[i], tmp2); - } else { - tcg_gen_qemu_st32(regs[i], tmp, get_mem_index(s)); - } - if (i == r3) { - break; - } - tcg_gen_add_i64(tmp, tmp, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0x92: /* MVI D1(B1),I2 [SI] */ insn = ld_code4(env, s->pc); tmp = decode_si(s, insn, &i2, &b1, &d1); @@ -2611,19 +2536,17 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) d1 = (insn >> 16) & 0xfff; b2 = (insn >> 12) & 0xf; d2 = insn & 0xfff; - tmp = load_reg(r1); /* XXX key in r3 */ - tmp2 = get_address(s, 0, b1, d1); - tmp3 = get_address(s, 0, b2, d2); + tmp = get_address(s, 0, b1, d1); + tmp2 = get_address(s, 0, b2, d2); if (opc == 0xda) { - gen_helper_mvcp(cc_op, cpu_env, tmp, tmp2, tmp3); + gen_helper_mvcp(cc_op, cpu_env, regs[r1], tmp, tmp2); } else { - gen_helper_mvcs(cc_op, cpu_env, tmp, tmp2, tmp3); + gen_helper_mvcs(cc_op, cpu_env, regs[r1], tmp, tmp2); } set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); break; #endif case 0xe3: @@ -3399,6 +3322,69 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_lm32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + + while (1) { + tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); + store_reg32_i64(r1, t); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + return NO_EXIT; +} + +static ExitStatus op_lmh(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + + while (1) { + tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); + store_reg32h_i64(r1, t); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + return NO_EXIT; +} + +static ExitStatus op_lm64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t8 = tcg_const_i64(8); + + while (1) { + tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t8); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t8); + return NO_EXIT; +} + static ExitStatus op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; @@ -3565,6 +3551,54 @@ static ExitStatus op_st64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stm(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + int size = s->insn->data; + TCGv_i64 tsize = tcg_const_i64(size); + + while (1) { + if (size == 8) { + tcg_gen_qemu_st64(regs[r1], o->in2, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(regs[r1], o->in2, get_mem_index(s)); + } + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, tsize); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(tsize); + return NO_EXIT; +} + +static ExitStatus op_stmh(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 t32 = tcg_const_i64(32); + + while (1) { + tcg_gen_shl_i64(t, regs[r1], t32); + tcg_gen_qemu_st32(t, o->in2, get_mem_index(s)); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + tcg_temp_free_i64(t32); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); From 6a04d76a815c7daeb9f27b7503ebddce311958fe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 10:22:28 -0700 Subject: [PATCH 053/149] target-s390: Convert MOVE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 ++++++ target-s390x/translate.c | 27 +++++++++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 393b425f21..c971308585 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -276,6 +276,12 @@ /* LOAD MULTIPLE HIGH */ C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) +/* MOVE */ + C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) + C(0xe54c, MVHI, SIL, GIE, la1, i2, 0, m1_32, mov2, 0) + C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) + C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0) + C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) /* MOVE LONG */ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 118f832141..0ea50431c4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1329,7 +1329,7 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, int r3, int b2, int d2) { - TCGv_i64 tmp, tmp2; + TCGv_i64 tmp; TCGv_i32 tmp32_1, tmp32_2; LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", @@ -1395,13 +1395,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x52: /* MVIY D1(B1),I2 [SIY] */ - tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ - tmp2 = tcg_const_i64((r1 << 4) | r3); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2240,14 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x92: /* MVI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_const_i64(i2); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x94: /* NI D1(B1),I2 [SI] */ case 0x96: /* OI D1(B1),I2 [SI] */ case 0x97: /* XI D1(B1),I2 [SI] */ @@ -3912,6 +3897,16 @@ static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) } } +static void wout_m1_8(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s)); +} + +static void wout_m1_16(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s)); +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); From a05d2b6b83544dd0ae915112d7a4565e8a3871f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 10:57:56 -0700 Subject: [PATCH 054/149] target-s390: Convert NI, XI, OI Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 ++++++ target-s390x/translate.c | 25 ------------------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c971308585..2383a366b3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -61,6 +61,8 @@ D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) + C(0x9400, NI, SI, Z, m1_8u, i2_8u, new, m1_8, and, nz64) + C(0xeb54, NIY, SIY, LD, m1_8u, i2_8u, new, m1_8, and, nz64) /* BRANCH AND SAVE */ C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) @@ -160,6 +162,8 @@ /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) + C(0x9700, XI, SI, Z, m1_8u, i2_8u, new, m1_8, xor, nz64) + C(0xeb57, XIY, SIY, LD, m1_8u, i2_8u, new, m1_8, xor, nz64) /* EXECUTE */ C(0x4400, EX, RX_a, Z, r1_o, a2, 0, 0, ex, 0) @@ -327,6 +331,8 @@ D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) + C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) + C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) /* ROTATE LEFT SINGLE LOGICAL */ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0ea50431c4..78c29cf70b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2233,31 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x94: /* NI D1(B1),I2 [SI] */ - case 0x96: /* OI D1(B1),I2 [SI] */ - case 0x97: /* XI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - switch (opc) { - case 0x94: - tcg_gen_andi_i64(tmp2, tmp2, i2); - break; - case 0x96: - tcg_gen_ori_i64(tmp2, tmp2, i2); - break; - case 0x97: - tcg_gen_xori_i64(tmp2, tmp2, i2); - break; - default: - tcg_abort(); - } - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - set_cc_nz_u64(s, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); From 145cdb401995707d1261735da7f6be3d4a91d377 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:08:40 -0700 Subject: [PATCH 055/149] target-s390: Convert STNSM, STOSM Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 43 ++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2383a366b3..9859b3b701 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -444,4 +444,8 @@ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) +/* STORE THEN AND SYSTEM MASK */ + C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* STORE THEN OR SYSTEM MASK */ + C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 78c29cf70b..8425c51be2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2226,7 +2226,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d1, d2, x2, b1, b2, i2, r1b; + int op, r1, r2, r3, d1, d2, x2, b1, b2, r1b; TCGv_i32 vl; opc = cpu_ldub_code(env, s->pc); @@ -2284,23 +2284,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_2); break; #ifndef CONFIG_USER_ONLY - case 0xac: /* STNSM D1(B1),I2 [SI] */ - case 0xad: /* STOSM D1(B1),I2 [SI] */ - check_privileged(s); - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_shri_i64(tmp2, psw_mask, 56); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - if (opc == 0xac) { - tcg_gen_andi_i64(psw_mask, psw_mask, - ((uint64_t)i2 << 56) | 0x00ffffffffffffffULL); - } else { - tcg_gen_ori_i64(psw_mask, psw_mask, (uint64_t)i2 << 56); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ check_privileged(s); insn = ld_code4(env, s->pc); @@ -3485,6 +3468,30 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); return NO_EXIT; } + +static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) +{ + uint64_t i2 = get_field(s->fields, i2); + TCGv_i64 t; + + check_privileged(s); + + /* It is important to do what the instruction name says: STORE THEN. + If we let the output hook perform the store then if we fault and + restart, we'll have the wrong SYSTEM MASK in place. */ + t = tcg_temp_new_i64(); + tcg_gen_shri_i64(t, psw_mask, 56); + tcg_gen_qemu_st8(t, o->addr1, get_mem_index(s)); + tcg_temp_free_i64(t); + + if (s->fields->op == 0xac) { + tcg_gen_andi_i64(psw_mask, psw_mask, + (i2 << 56) | 0x00ffffffffffffffull); + } else { + tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56); + } + return NO_EXIT; +} #endif static ExitStatus op_st8(DisasContext *s, DisasOps *o) From 7df3e93aa953148841bd8a086cb3230f3d01a14c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 09:38:22 -0700 Subject: [PATCH 056/149] target-s390: Convert LAM, STAM Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 +++++ target-s390x/translate.c | 46 ++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 9859b3b701..2e09838ba8 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -279,6 +279,9 @@ C(0xeb04, LMG, RSY_a, Z, 0, a2, 0, 0, lm64, 0) /* LOAD MULTIPLE HIGH */ C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) +/* LOAD ACCESS MULTIPLE */ + C(0x9a00, LAM, RS_a, Z, 0, a2, 0, 0, lam, 0) + C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) /* MOVE */ C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) @@ -389,6 +392,9 @@ D(0xeb24, STMG, RSY_a, Z, 0, a2, 0, 0, stm, 0, 8) /* STORE MULTIPLE HIGH */ C(0xeb26, STMH, RSY_a, Z, 0, a2, 0, 0, stmh, 0) +/* STORE ACCESS MULTIPLE */ + C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0) + C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0) /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8425c51be2..b2a258f5ce 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2233,30 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lam(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x9b: /* STAM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stam(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -3265,6 +3241,17 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_lam(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_lam(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_lm32(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); @@ -3518,6 +3505,17 @@ static ExitStatus op_st64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stam(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_stam(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_stm(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); From eb66e6a96904e50a9d0d1a76aecfe8675f4d8673 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:24:25 -0700 Subject: [PATCH 057/149] target-s390: Convert CLCLE, MVCLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 +++ target-s390x/translate.c | 50 ++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2e09838ba8..4d7f862e29 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -132,6 +132,8 @@ C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL LONG EXTENDED */ + C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) @@ -291,6 +293,8 @@ C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) /* MOVE LONG */ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) +/* MOVE LONG EXTENDED */ + C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b2a258f5ce..38eeeadf7f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2233,32 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_mvcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xa9: /* CLCLE R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_clcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; #ifndef CONFIG_USER_ONLY case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ check_privileged(s); @@ -3028,6 +3002,18 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_clcle(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_clcle(cc_op, cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_cvd(DisasContext *s, DisasOps *o) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -3348,6 +3334,18 @@ static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_mvcle(cc_op, cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From af9e5a04ea63b7ebbe7af2bb3553dc0e8a158d12 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:43:06 -0700 Subject: [PATCH 058/149] target-s390: Convert MVC The code that was in gen_op_mvc was a bit confused wrt what lengths it wanted to handle. I also disbelieve that the inline memset is worthwhile. Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 1 + target-s390x/translate.c | 177 ++----------------------------------- 2 files changed, 10 insertions(+), 168 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4d7f862e29..a8056a87c9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -286,6 +286,7 @@ C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) /* MOVE */ + C(0xd200, MVC, SS_a, Z, la1, a2, 0, 0, mvc, 0) C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) C(0xe54c, MVHI, SIL, GIE, la1, i2, 0, m1_32, mov2, 0) C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 38eeeadf7f..294cb92fe2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1012,170 +1012,6 @@ static void free_compare(DisasCompare *c) } } -static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) -{ - TCGv_i64 tmp, tmp2; - int i; - int l_memset = gen_new_label(); - int l_out = gen_new_label(); - TCGv_i64 dest = tcg_temp_local_new_i64(); - TCGv_i64 src = tcg_temp_local_new_i64(); - TCGv_i32 vl; - - /* Find out if we should use the inline version of mvc */ - switch (l) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 11: - case 15: - /* use inline */ - break; - default: - /* Fall back to helper */ - vl = tcg_const_i32(l); - potential_page_fault(s); - gen_helper_mvc(cpu_env, vl, s1, s2); - tcg_temp_free_i32(vl); - return; - } - - tcg_gen_mov_i64(dest, s1); - tcg_gen_mov_i64(src, s2); - - if (!(s->tb->flags & FLAG_MASK_64)) { - /* XXX what if we overflow while moving? */ - tcg_gen_andi_i64(dest, dest, 0x7fffffffUL); - tcg_gen_andi_i64(src, src, 0x7fffffffUL); - } - - tmp = tcg_temp_new_i64(); - tcg_gen_addi_i64(tmp, src, 1); - tcg_gen_brcond_i64(TCG_COND_EQ, dest, tmp, l_memset); - tcg_temp_free_i64(tmp); - - switch (l) { - case 0: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - case 1: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld16u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st16(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - case 3: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st32(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - case 4: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s)); - tcg_gen_addi_i64(src, src, 4); - tcg_gen_qemu_ld8u(tmp2, src, get_mem_index(s)); - tcg_gen_qemu_st32(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 4); - tcg_gen_qemu_st8(tmp2, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 7: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld64(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - default: - /* The inline version can become too big for too uneven numbers, only - use it on known good lengths */ - tmp = tcg_temp_new_i64(); - tmp2 = tcg_const_i64(8); - for (i = 0; (i + 7) <= l; i += 8) { - tcg_gen_qemu_ld64(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - - tcg_gen_add_i64(src, src, tmp2); - tcg_gen_add_i64(dest, dest, tmp2); - } - - tcg_temp_free_i64(tmp2); - tmp2 = tcg_const_i64(1); - - for (; i <= l; i++) { - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); - - tcg_gen_add_i64(src, src, tmp2); - tcg_gen_add_i64(dest, dest, tmp2); - } - - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; - } - - tcg_gen_br(l_out); - - gen_set_label(l_memset); - /* memset case (dest == (src + 1)) */ - - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - /* fill tmp with the byte */ - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_shli_i64(tmp2, tmp, 8); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_gen_shli_i64(tmp2, tmp, 16); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_gen_shli_i64(tmp2, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_temp_free_i64(tmp2); - - tmp2 = tcg_const_i64(8); - - for (i = 0; (i + 7) <= l; i += 8) { - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 8); - } - - tcg_temp_free_i64(tmp2); - tmp2 = tcg_const_i64(1); - - for (; i <= l; i++) { - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 1); - } - - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - - gen_set_label(l_out); - - tcg_temp_free(dest); - tcg_temp_free(src); -} - static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) { TCGv_i64 tmp; @@ -2365,7 +2201,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ @@ -2381,9 +2216,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tmp = get_address(s, 0, b1, d1); tmp2 = get_address(s, 0, b2, d2); switch (opc) { - case 0xd2: - gen_op_mvc(s, (insn >> 32) & 0xff, tmp, tmp2); - break; case 0xd4: potential_page_fault(s); gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); @@ -3322,6 +3154,15 @@ static ExitStatus op_movx(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_mvc(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From 0a949039596edf43e5e32dc7cb0cb4e994497e4b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:54:19 -0700 Subject: [PATCH 059/149] target-s390: Convert NC, XC, OC, TR, UNPK Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 11 +++++ target-s390x/translate.c | 88 ++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a8056a87c9..015a7f52ce 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -54,6 +54,7 @@ C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) + C(0xd400, NC, SS_a, Z, la1, a2, 0, 0, nc, 0) /* AND IMMEDIATE */ D(0xc00a, NIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2020) D(0xc00b, NILF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2000) @@ -161,6 +162,7 @@ C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) + C(0xd700, XC, SS_a, Z, la1, a2, 0, 0, xc, 0) /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) @@ -332,6 +334,7 @@ C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) + C(0xd600, OC, SS_a, Z, la1, a2, 0, 0, oc, 0) /* OR IMMEDIATE */ D(0xc00c, OIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2020) D(0xc00d, OILF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2000) @@ -444,6 +447,14 @@ D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) +/* TRANSLATE */ + C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0) + +/* UNPACK */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) + #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 294cb92fe2..36705a2f8f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2063,7 +2063,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) unsigned char opc; uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, r1b; - TCGv_i32 vl; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -2201,51 +2200,15 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ - case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ - case 0xd7: /* XC D1(L,B1),D2(B2) [SS] */ - case 0xdc: /* TR D1(L,B1),D2(B2) [SS] */ - case 0xf3: /* UNPK D1(L1,B1),D2(L2,B2) [SS] */ insn = ld_code6(env, s->pc); - vl = tcg_const_i32((insn >> 32) & 0xff); b1 = (insn >> 28) & 0xf; b2 = (insn >> 12) & 0xf; d1 = (insn >> 16) & 0xfff; d2 = insn & 0xfff; tmp = get_address(s, 0, b1, d1); tmp2 = get_address(s, 0, b2, d2); - switch (opc) { - case 0xd4: - potential_page_fault(s); - gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xd5: - gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2); - break; - case 0xd6: - potential_page_fault(s); - gen_helper_oc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xd7: - potential_page_fault(s); - gen_helper_xc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xdc: - potential_page_fault(s); - gen_helper_tr(cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xf3: - potential_page_fault(s); - gen_helper_unpk(cpu_env, vl, tmp, tmp2); - break; - default: - tcg_abort(); - } + gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; @@ -3206,12 +3169,32 @@ static ExitStatus op_nabs(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_nc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_neg(DisasContext *s, DisasOps *o) { tcg_gen_neg_i64(o->out, o->in2); return NO_EXIT; } +static ExitStatus op_oc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_or(DisasContext *s, DisasOps *o) { tcg_gen_or_i64(o->out, o->in1, o->in2); @@ -3446,6 +3429,35 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) return EXIT_NORETURN; } +static ExitStatus op_tr(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_tr(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_unpk(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_unpk(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + +static ExitStatus op_xc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_xc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_xor(DisasContext *s, DisasOps *o) { tcg_gen_xor_i64(o->out, o->in1, o->in2); From 4f7403d52b1c682df15c862f5e7ca0712b66089f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 12:54:07 -0700 Subject: [PATCH 060/149] target-s390: Convert CLC Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 1 + target-s390x/translate.c | 107 ++++++++++++------------------------- 2 files changed, 35 insertions(+), 73 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 015a7f52ce..ff8f57fe2b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -119,6 +119,7 @@ C(0xb931, CLGFR, RRE, Z, r1, r2_32u, 0, 0, 0, cmpu64) C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) + C(0xd500, CLC, SS_a, Z, la1, a2, 0, 0, clc, 0) /* COMPARE LOGICAL IMMEDIATE */ C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 36705a2f8f..8a7cfafb9f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1012,67 +1012,6 @@ static void free_compare(DisasCompare *c) } } -static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) -{ - TCGv_i64 tmp; - TCGv_i64 tmp2; - TCGv_i32 vl; - - /* check for simple 32bit or 64bit match */ - switch (l) { - case 0: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld8u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld8u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 1: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld16u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld16u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 3: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld32u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld32u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 7: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld64(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld64(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - } - - potential_page_fault(s); - vl = tcg_const_i32(l); - gen_helper_clc(cc_op, cpu_env, vl, s1, s2); - tcg_temp_free_i32(vl); - set_cc_static(s); -} - static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { @@ -2200,18 +2139,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ - insn = ld_code6(env, s->pc); - b1 = (insn >> 28) & 0xf; - b2 = (insn >> 12) & 0xf; - d1 = (insn >> 16) & 0xfff; - d2 = insn & 0xfff; - tmp = get_address(s, 0, b1, d1); - tmp2 = get_address(s, 0, b2, d2); - gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; #ifndef CONFIG_USER_ONLY case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ @@ -2797,6 +2724,40 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_clc(DisasContext *s, DisasOps *o) +{ + int l = get_field(s->fields, l1); + TCGv_i32 vl; + + switch (l + 1) { + case 1: + tcg_gen_qemu_ld8u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld8u(cc_dst, o->in2, get_mem_index(s)); + break; + case 2: + tcg_gen_qemu_ld16u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld16u(cc_dst, o->in2, get_mem_index(s)); + break; + case 4: + tcg_gen_qemu_ld32u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld32u(cc_dst, o->in2, get_mem_index(s)); + break; + case 8: + tcg_gen_qemu_ld64(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s)); + break; + default: + potential_page_fault(s); + vl = tcg_const_i32(l); + gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2); + tcg_temp_free_i32(vl); + set_cc_static(s); + return NO_EXIT; + } + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, cc_src, cc_dst); + return NO_EXIT; +} + static ExitStatus op_clcle(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From 97c3ab61c46c1c0194657b8bead3d499600d8aab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 13:00:27 -0700 Subject: [PATCH 061/149] target-s390: Convert MVCP, MVCS Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 49 ++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ff8f57fe2b..65f0bfd768 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -461,6 +461,10 @@ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) +/* MOVE TO PRIMARY */ + C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) +/* MOVE TO SECONDARY */ + C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8a7cfafb9f..070da1e817 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2001,7 +2001,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d1, d2, x2, b1, b2, r1b; + int op, r1, r2, r3, d2, x2, b2, r1b; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -2139,31 +2139,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; -#ifndef CONFIG_USER_ONLY - case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ - case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ - check_privileged(s); - potential_page_fault(s); - insn = ld_code6(env, s->pc); - r1 = (insn >> 36) & 0xf; - r3 = (insn >> 32) & 0xf; - b1 = (insn >> 28) & 0xf; - d1 = (insn >> 16) & 0xfff; - b2 = (insn >> 12) & 0xf; - d2 = insn & 0xfff; - /* XXX key in r3 */ - tmp = get_address(s, 0, b1, d1); - tmp2 = get_address(s, 0, b2, d2); - if (opc == 0xda) { - gen_helper_mvcp(cc_op, cpu_env, regs[r1], tmp, tmp2); - } else { - gen_helper_mvcs(cc_op, cpu_env, regs[r1], tmp, tmp2); - } - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; -#endif case 0xe3: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -3111,6 +3086,28 @@ static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_mvcp(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, l1); + check_privileged(s); + potential_page_fault(s); + gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, l1); + check_privileged(s); + potential_page_fault(s); + gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From d8fe4a9c284f244679ab251637bff81126d91dfe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 13:15:10 -0700 Subject: [PATCH 062/149] target-s390: Convert LRA Note that truncating the store to r1 based on PSW_MASK_64 is incorrect. We always modify the entire register. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 4 ++++ target-s390x/mem_helper.c | 13 +++---------- target-s390x/translate.c | 20 +++++++++----------- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 5a0f6965a4..0bb6d57cbc 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -131,7 +131,7 @@ DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) -DEF_HELPER_3(lra, i32, env, i64, i32) +DEF_HELPER_2(lra, i64, env, i64) DEF_HELPER_3(stura, void, env, i64, i32) #endif diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 65f0bfd768..a83ce95459 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -461,6 +461,10 @@ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) +/* LOAD REAL ADDRESS */ + C(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0) + C(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0) + C(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0) /* MOVE TO PRIMARY */ C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) /* MOVE TO SECONDARY */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 1b63259351..dcaa5a59d7 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1127,7 +1127,7 @@ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) } /* load real address */ -uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) +uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) { uint32_t cc = 0; int old_exc = env->exception_index; @@ -1151,14 +1151,7 @@ uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) } env->exception_index = old_exc; - if (!(env->psw.mask & PSW_MASK_64)) { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - (ret & 0xffffffffULL); - } else { - env->regs[r1] = ret; - } - - return cc; + env->cc_op = cc; + return ret; } - #endif diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 070da1e817..227b77d02b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2022,17 +2022,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ - check_privileged(s); - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = tcg_const_i32(r1); - potential_page_fault(s); - gen_helper_lra(cc_op, cpu_env, tmp, tmp32_1); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; #endif case 0xb2: insn = ld_code4(env, s->pc); @@ -2938,6 +2927,15 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_lra(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_lra(o->out, cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) { TCGv_i64 t1, t2; From 0c2400155bc47dcfb7216f586457940a9f342462 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 13:52:23 -0700 Subject: [PATCH 063/149] target-s390: Convert SIGP Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 28 ++++++++++++---------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a83ce95459..899c6a5aa8 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -475,6 +475,8 @@ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) +/* SIGNAL PROCESSOR */ + C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 227b77d02b..e0879412c4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2007,22 +2007,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { -#ifndef CONFIG_USER_ONLY - case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = load_reg(r3); - tmp32_1 = tcg_const_i32(r1); - potential_page_fault(s); - gen_helper_sigp(cc_op, cpu_env, tmp, tmp32_1, tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; -#endif case 0xb2: insn = ld_code4(env, s->pc); op = (insn >> 16) & 0xff; @@ -3194,6 +3178,18 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_sigp(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + check_privileged(s); + potential_page_fault(s); + gen_helper_sigp(cc_op, cpu_env, o->in2, r1, o->in1); + tcg_temp_free_i32(r1); + return NO_EXIT; +} +#endif + static ExitStatus op_sla(DisasContext *s, DisasOps *o) { uint64_t sign = 1ull << s->insn->data; From ea20490fdd9faacf9768363edcda3c76fed703ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:09:05 -0700 Subject: [PATCH 064/149] target-s390: Convert EFPC, STFPC Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 ++++++ target-s390x/translate.c | 38 +++++++++++++------------------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 899c6a5aa8..819c3f5274 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -175,6 +175,9 @@ /* EXECUTE RELATIVE LONG */ C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) +/* EXTRACT FPC */ + C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) + /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) @@ -395,6 +398,9 @@ /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE FPC */ + C(0xb29c, STFPC, S, Z, 0, a2, new, m2_32, efpc, 0) + /* STORE MULTIPLE */ D(0x9000, STM, RS_a, Z, 0, a2, 0, 0, stm, 0, 4) D(0xeb90, STMY, RSY_a, LD, 0, a2, 0, 0, stm, 0, 4) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e0879412c4..9e648d62d2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1839,12 +1839,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); tcg_temp_free_i32(tmp32_1); break; - case 0x8c: /* EFPC R1 [RRE] */ - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x94: /* CEFBR R1,R2 [RRE] */ case 0x95: /* CDFBR R1,R2 [RRE] */ case 0x96: /* CXFBR R1,R2 [RRE] */ @@ -1997,7 +1991,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { - TCGv_i64 tmp, tmp2; + TCGv_i64 tmp; TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; @@ -2010,24 +2004,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) case 0xb2: insn = ld_code4(env, s->pc); op = (insn >> 16) & 0xff; - switch (op) { - case 0x9c: /* STFPC D2(B2) [S] */ - d2 = insn & 0xfff; - b2 = (insn >> 12) & 0xf; - tmp32_1 = tcg_temp_new_i32(); - tmp = tcg_temp_new_i64(); - tmp2 = get_address(s, 0, b2, d2); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_qemu_st32(tmp, tmp2, get_mem_index(s)); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - default: - disas_b2(env, s, op, insn); - break; - } + disas_b2(env, s, op, insn); break; case 0xb3: insn = ld_code4(env, s->pc); @@ -2774,6 +2751,12 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_efpc(DisasContext *s, DisasOps *o) +{ + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); + return NO_EXIT; +} + static ExitStatus op_ex(DisasContext *s, DisasOps *o) { /* ??? Perhaps a better way to implement EXECUTE is to set a bit in @@ -3700,6 +3683,11 @@ static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s)); } +static void wout_m2_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s)); +} + /* ====================================================================== */ /* The "INput 1" generators. These load the first operand to an insn. */ From 504488b82770e053aa31861fd7ef31afdb874f27 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:17:58 -0700 Subject: [PATCH 065/149] target-s390: Convert LCTL, STCTL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 +++ target-s390x/translate.c | 54 +++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 819c3f5274..6fff22aa5a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -465,6 +465,8 @@ #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) +/* LOAD CONTROL */ + C(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* LOAD REAL ADDRESS */ @@ -483,6 +485,8 @@ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) +/* STORE CONTROL */ + C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9e648d62d2..265fc26800 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2014,36 +2014,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) r2 = insn & 0xf; disas_b3(env, s, op, r3, r1, r2); break; -#ifndef CONFIG_USER_ONLY - case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ - /* Store Control */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stctl(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ - /* Load Control */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lctl(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; -#endif case 0xb9: insn = ld_code4(env, s->pc); r1 = (insn >> 4) & 0xf; @@ -2894,6 +2864,18 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_lctl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_lctl(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_lra(DisasContext *s, DisasOps *o) { check_privileged(s); @@ -3213,6 +3195,18 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stctl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_stctl(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From f3de39c485027a6b47bffb741f5209aa44052b71 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:46:55 -0700 Subject: [PATCH 066/149] target-s390: Convert COMPARE AND SWAP Signed-off-by: Richard Henderson --- target-s390x/helper.h | 4 +- target-s390x/insn-data.def | 9 +++++ target-s390x/mem_helper.c | 33 +++++++--------- target-s390x/translate.c | 78 ++++++++++++++++++++------------------ 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 0bb6d57cbc..c653c1182c 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -18,9 +18,9 @@ DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) DEF_HELPER_4(mvst, void, env, i32, i32, i32) -DEF_HELPER_4(csg, i32, env, i32, i64, i32) +DEF_HELPER_4(csg, i64, env, i64, i64, i64) DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) -DEF_HELPER_4(cs, i32, env, i32, i64, i32) +DEF_HELPER_4(cs, i64, env, i64, i64, i64) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6fff22aa5a..4714095f10 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -137,6 +137,15 @@ /* COMPARE LOGICAL LONG EXTENDED */ C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) +/* COMPARE AND SWAP */ + C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) + C(0xeb14, CSY, RSY_a, LD, r1_o, a2, new, r1_32, cs, 0) + C(0xeb30, CSG, RSY_a, Z, r1_o, a2, r1, 0, csg, 0) +/* COMPARE DOUBLE AND SWAP */ + C(0xbb00, CDS, RS_a, Z, r1_D32, a2, new, r1_D32, cds, 0) + C(0xeb31, CDSY, RSY_a, LD, r1_D32, a2, new, r1_D32, cds, 0) + C(0xeb3e, CDSG, RSY_a, Z, 0, a2, 0, 0, cdsg, 0) + /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index dcaa5a59d7..44c740f1c9 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -457,20 +457,18 @@ void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) } /* compare and swap 64-bit */ -uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) { /* FIXME: locking? */ - uint32_t cc; uint64_t v2 = cpu_ldq_data(env, a2); - - if (env->regs[r1] == v2) { - cc = 0; - cpu_stq_data(env, a2, env->regs[r3]); + if (r1 == v2) { + cpu_stq_data(env, a2, r3); + env->cc_op = 0; + return r1; } else { - cc = 1; - env->regs[r1] = v2; + env->cc_op = 1; + return v2; } - return cc; } /* compare double and swap 64-bit */ @@ -497,21 +495,18 @@ uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) } /* compare and swap 32-bit */ -uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) { /* FIXME: locking? */ - uint32_t cc; uint32_t v2 = cpu_ldl_data(env, a2); - - HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); - if (((uint32_t)env->regs[r1]) == v2) { - cc = 0; - cpu_stl_data(env, a2, (uint32_t)env->regs[r3]); + if ((uint32_t)r1 == v2) { + cpu_stl_data(env, a2, (uint32_t)r3); + env->cc_op = 0; + return r1; } else { - cc = 1; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; + env->cc_op = 1; + return v2; } - return cc; } static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 265fc26800..a99d3503f2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1146,30 +1146,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_2); break; #endif - case 0x30: /* CSG R1,R3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_csg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_cdsg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2021,19 +1997,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xba: /* CS R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_cs(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2665,6 +2628,47 @@ static ExitStatus op_clcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cs(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + potential_page_fault(s); + gen_helper_cs(o->out, cpu_env, o->in1, o->in2, regs[r3]); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_csg(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + potential_page_fault(s); + gen_helper_csg(o->out, cpu_env, o->in1, o->in2, regs[r3]); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cds(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + TCGv_i64 in3 = tcg_temp_new_i64(); + tcg_gen_deposit_i64(in3, regs[r3 + 1], regs[r3], 32, 32); + potential_page_fault(s); + gen_helper_csg(o->out, cpu_env, o->in1, o->in2, in3); + tcg_temp_free_i64(in3); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + /* XXX rewrite in tcg */ + gen_helper_cdsg(cc_op, cpu_env, r1, o->in2, r3); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_cvd(DisasContext *s, DisasOps *o) { TCGv_i64 t1 = tcg_temp_new_i64(); From 32a44d5882ae82364a8e957a5e21cbeaaacc71a3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:59:22 -0700 Subject: [PATCH 067/149] target-s390: Convert CLM Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 32 +++++++++++++++++++------------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4714095f10..15ded9785b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -136,6 +136,10 @@ C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) /* COMPARE LOGICAL LONG EXTENDED */ C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) +/* COMPARE LOGICAL CHARACTERS UNDER MASK */ + C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) + C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) + C(0xeb20, CLMH, RSY_b, Z, r1_sr32, a2, 0, 0, clm, 0) /* COMPARE AND SWAP */ C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a99d3503f2..47576fac7f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1997,19 +1997,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_clm(cc_op, cpu_env, tmp32_1, tmp32_2, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2628,6 +2615,19 @@ static ExitStatus op_clcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clm(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, o->in1); + potential_page_fault(s); + gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2); + set_cc_static(s); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + static ExitStatus op_cs(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); @@ -3712,6 +3712,12 @@ static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); } +static void in1_r1_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in1, regs[get_field(f, r1)], 32); +} + static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ From 2ae680590667b5a8e4eb667a726b5d16d6553cb9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:11:53 -0700 Subject: [PATCH 068/149] target-s390: Convert STCM Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 -- target-s390x/insn-data.def | 4 +++ target-s390x/mem_helper.c | 37 ------------------- target-s390x/translate.c | 73 +++++++++++++++++++++++++------------- 4 files changed, 53 insertions(+), 63 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c653c1182c..8cf9186b8b 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -8,7 +8,6 @@ DEF_HELPER_4(mvc, void, env, i32, i64, i64) DEF_HELPER_4(clc, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) -DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_3(divs32, s64, env, s64, s64) DEF_HELPER_3(divu32, i64, env, i64, i64) @@ -26,7 +25,6 @@ DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) -DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 15ded9785b..6c2f455d86 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -405,6 +405,10 @@ /* STORE CHARACTER */ C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) +/* STORE CHARACTERS UNDER MASK */ + D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2c, STCMH, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 32) /* STORE HALFWORD */ C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 44c740f1c9..9c3ade816c 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -304,27 +304,6 @@ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, return cc; } -/* store character under mask */ -void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask, - uint64_t addr) -{ - uint8_t r; - - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, - addr); - while (mask) { - if (mask & 8) { - r = (r1 & 0xff000000UL) >> 24; - cpu_stb_data(env, addr, r); - HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); - addr++; - } - mask = (mask << 1) & 0xf; - r1 <<= 8; - } - HELPER_LOG("\n"); -} - static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) { uint64_t r = d2; @@ -608,22 +587,6 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, return cc; } -/* store character under mask high operates on the upper half of r1 */ -void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, - uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - - while (mask) { - if (mask & 8) { - cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff); - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - } -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 47576fac7f..9f20955137 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1110,16 +1110,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); switch (op) { - case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stcmh(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; #ifndef CONFIG_USER_ONLY case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ /* Load Control */ @@ -1967,8 +1957,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; int op, r1, r2, r3, d2, x2, b2, r1b; @@ -1997,18 +1985,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stcm(cpu_env, tmp32_1, tmp32_2, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xe3: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -3271,6 +3247,55 @@ static ExitStatus op_stam(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stcm(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int pos, base = s->insn->data; + TCGv_i64 tmp = tcg_temp_new_i64(); + + pos = base + ctz32(m3) * 8; + switch (m3) { + case 0xf: + /* Effectively a 32-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st32(tmp, o->in2, get_mem_index(s)); + break; + + case 0xc: + case 0x6: + case 0x3: + /* Effectively a 16-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st16(tmp, o->in2, get_mem_index(s)); + break; + + case 0x8: + case 0x4: + case 0x2: + case 0x1: + /* Effectively an 8-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s)); + break; + + default: + /* This is going to be a sequence of shifts and stores. */ + pos = base + 32 - 8; + while (m3) { + if (m3 & 0x8) { + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 1); + } + m3 = (m3 << 1) & 0xf; + pos -= 8; + } + break; + } + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + static ExitStatus op_stm(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); From 112bf0791d615060ff9235318e13fd4725146ff8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:15:59 -0700 Subject: [PATCH 069/149] target-s390: Convert TPROT Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 47 ++++++++------------------------------ 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6c2f455d86..8bfc6f99c6 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -508,4 +508,6 @@ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* TEST PROTECTION */ + C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9f20955137..274c5e7573 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1073,34 +1073,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(addr); } -#ifndef CONFIG_USER_ONLY -static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) -{ - TCGv_i64 tmp, tmp2; - int op = (insn >> 32) & 0xff; - - tmp = get_address(s, 0, (insn >> 28) & 0xf, (insn >> 16) & 0xfff); - tmp2 = get_address(s, 0, (insn >> 12) & 0xf, insn & 0xfff); - - LOG_DISAS("disas_e5: insn %" PRIx64 "\n", insn); - switch (op) { - case 0x01: /* TPROT D1(B1),D2(B2) [SSE] */ - /* Test Protection */ - potential_page_fault(s); - gen_helper_tprot(cc_op, tmp, tmp2); - set_cc_static(s); - break; - default: - LOG_DISAS("illegal e5 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); -} -#endif - static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, int r3, int b2, int d2) { @@ -1996,15 +1968,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) | ((insn << 4) & 0xff000)) << 12)) >> 12; disas_e3(env, s, op, r1, x2, b2, d2 ); break; -#ifndef CONFIG_USER_ONLY - case 0xe5: - /* Test Protection */ - check_privileged(s); - insn = ld_code6(env, s->pc); - debug_insn(insn); - disas_e5(env, s, insn); - break; -#endif case 0xeb: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -3387,6 +3350,16 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) return EXIT_NORETURN; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_tprot(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_tprot(cc_op, o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_tr(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); From 3e398cf9c2ffdee0c8f61d3bc8966357d0b8e095 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 2 Sep 2012 10:12:48 -0700 Subject: [PATCH 070/149] target-s390: Convert LOAD CONTROL, part 2 Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 + target-s390x/translate.c | 76 ++++++++++++-------------------------- 2 files changed, 25 insertions(+), 53 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8bfc6f99c6..a8dffcdcd5 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -484,6 +484,7 @@ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD CONTROL */ C(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0) + C(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* LOAD REAL ADDRESS */ @@ -504,6 +505,7 @@ C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) + C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 274c5e7573..0afc25f25b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1073,48 +1073,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(addr); } -static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, - int r3, int b2, int d2) -{ - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2; - - LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", - op, r1, r3, b2, d2); - switch (op) { -#ifndef CONFIG_USER_ONLY - case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ - /* Load Control */ - check_privileged(s); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lctlg(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ - /* Store Control */ - check_privileged(s); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stctg(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; -#endif - default: - LOG_DISAS("illegal eb operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { @@ -1968,17 +1926,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) | ((insn << 4) & 0xff000)) << 12)) >> 12; disas_e3(env, s, op, r1, x2, b2, d2 ); break; - case 0xeb: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - r3 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = ((int)((((insn >> 16) & 0xfff) - | ((insn << 4) & 0xff000)) << 12)) >> 12; - disas_eb(env, s, op, r1, r3, b2, d2); - break; case 0xed: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -2819,6 +2766,17 @@ static ExitStatus op_lctl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_lctlg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_lctlg(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} static ExitStatus op_lra(DisasContext *s, DisasOps *o) { check_privileged(s); @@ -3138,6 +3096,18 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stctg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_stctg(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_stctl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From d54f58654187f8bafb4523a286a9baf46c531d06 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:35:40 -0700 Subject: [PATCH 071/149] target-s390: Convert LOAD REVERSED Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 +++ target-s390x/translate.c | 77 +++++++++++++++----------------------- 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a8dffcdcd5..1ee0d42930 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -293,6 +293,12 @@ C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) +/* LOAD REVERSED */ + C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) + C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) + C(0xe31f, LRVH, RXY_a, Z, 0, m2_16u, new, r1_16, rev16, 0) + C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) + C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) /* LOAD MULTIPLE */ C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0afc25f25b..397511ca44 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -278,17 +278,6 @@ static inline void store_reg32h_i64(int reg, TCGv_i64 v) tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); } -static inline void store_reg16(int reg, TCGv_i32 v) -{ - /* 16 bit register writes keep the upper bytes */ -#if HOST_LONG_BITS == 32 - tcg_gen_deposit_i32(TCGV_LOW(regs[reg]), TCGV_LOW(regs[reg]), v, 0, 16); -#else - tcg_gen_deposit_i64(regs[reg], regs[reg], - MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 16); -#endif -} - static inline void store_freg32(int reg, TCGv_i32 v) { /* 32 bit register writes keep the lower half */ @@ -1022,13 +1011,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, op, r1, x2, b2, d2); addr = get_address(s, x2, b2, d2); switch (op) { - case 0xf: /* LRVG R1,D2(X2,B2) [RXE] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - tcg_gen_bswap64_i64(tmp2, tmp2); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); @@ -1036,26 +1018,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x1f: /* LRVH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_bswap16_i32(tmp32_1, tmp32_1); - store_reg16(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ tmp32_1 = load_reg32(r1); tmp2 = tcg_temp_new_i64(); @@ -1861,15 +1823,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x0f: /* LRVGR R1,R2 [RRE] */ - tcg_gen_bswap64_i64(regs[r1], regs[r2]); - break; - case 0x1f: /* LRVR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -3023,6 +2976,24 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_rev16(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap16_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_rev32(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap32_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_rev64(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap64_i64(o->out, o->in2); + return NO_EXIT; +} + static ExitStatus op_rll32(DisasContext *s, DisasOps *o) { TCGv_i32 t1 = tcg_temp_new_i32(); @@ -3576,6 +3547,12 @@ static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8); } +static void wout_r1_16(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16); +} + static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); @@ -3918,6 +3895,12 @@ static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s)); } +static void in2_m2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); +} + static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From e025e52aba7063c8137b7812e10d69500efb1fbb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:52:55 -0700 Subject: [PATCH 072/149] target-s390: Convert STORE REVERSED Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 1ee0d42930..fa3ee0063c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -420,6 +420,10 @@ C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE REVERSED */ + C(0xe33f, STRVH, RXY_a, Z, la2, r1_16u, new, m1_16, rev16, 0) + C(0xe33e, STRV, RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) + C(0xe32f, STRVG, RXY_a, Z, la2, r1_o, new, m1_64, rev64, 0) /* STORE FPC */ C(0xb29c, STFPC, S, Z, 0, a2, new, m2_32, efpc, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 397511ca44..f8c1ea7727 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1005,7 +1005,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { TCGv_i64 addr, tmp2; - TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); @@ -1018,15 +1017,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3738,6 +3728,12 @@ static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); } +static void in1_la2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int x2 = have_field(f, x2) ? get_field(f, x2) : 0; + o->addr1 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); +} + static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) { in1_la1(s, f, o); @@ -3783,6 +3779,24 @@ static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) /* ====================================================================== */ /* The "INput 2" generators. These load the second operand to an insn. */ +static void in2_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = regs[get_field(f, r1)]; + o->g_in2 = true; +} + +static void in2_r1_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r1)]); +} + +static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r1)]); +} + static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r2)); From 7691c23b1f7b508f3f5391e8f362579544be6980 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:59:19 -0700 Subject: [PATCH 073/149] target-s390: Convert LLGT Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 50 +++++--------------------------------- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index fa3ee0063c..8914d341f7 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -285,6 +285,9 @@ D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) +/* LOAD LOGICAL THIRTY ONE BITS */ + C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) + C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) /* LOAD NEGATIVE */ C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f8c1ea7727..033f93e3ef 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1001,30 +1001,6 @@ static void free_compare(DisasCompare *c) } } -static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, - int x2, int b2, int d2) -{ - TCGv_i64 addr, tmp2; - - LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", - op, r1, x2, b2, d2); - addr = get_address(s, x2, b2, d2); - switch (op) { - case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - default: - LOG_DISAS("illegal e3 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } - tcg_temp_free_i64(addr); -} - static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { @@ -1804,15 +1780,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x17: /* LLGTR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0x7fffffffUL); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -1858,17 +1825,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xe3: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - x2 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = ((int)((((insn >> 16) & 0xfff) - | ((insn << 4) & 0xff000)) << 12)) >> 12; - disas_e3(env, s, op, r1, x2, b2, d2 ); - break; case 0xed: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -2654,6 +2610,12 @@ static ExitStatus op_insi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_llgt(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); + return NO_EXIT; +} + static ExitStatus op_ld8s(DisasContext *s, DisasOps *o) { tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s)); From 587626f8da5e2ee15bbf9f636c78991d6c953387 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 10:48:20 -0700 Subject: [PATCH 074/149] target-s390: Convert FP ADD, COMPARE, LOAD TEST/ROUND/LENGTHENED Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 9 +- target-s390x/cpu.h | 10 +- target-s390x/fpu_helper.c | 298 ++++++++++++++----------------------- target-s390x/helper.h | 37 ++--- target-s390x/insn-data.def | 25 ++++ target-s390x/translate.c | 217 +++++++++++++++------------ 6 files changed, 281 insertions(+), 315 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index be4202a78e..f1038be1b5 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -505,18 +505,15 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, r = cc_calc_sla_64(src, dst); break; - case CC_OP_LTGT_F32: - r = set_cc_f32(env, src, dst); - break; - case CC_OP_LTGT_F64: - r = set_cc_f64(env, src, dst); - break; case CC_OP_NZ_F32: r = set_cc_nz_f32(dst); break; case CC_OP_NZ_F64: r = set_cc_nz_f64(dst); break; + case CC_OP_NZ_F128: + r = set_cc_nz_f128(make_float128(src, dst)); + break; default: cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index b8e9037eeb..f1d4dc67f4 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -471,11 +471,9 @@ enum cc_op { CC_OP_TM_32, /* test under mask (32bit) */ CC_OP_TM_64, /* test under mask (64bit) */ - CC_OP_LTGT_F32, /* FP compare (32bit) */ - CC_OP_LTGT_F64, /* FP compare (64bit) */ - CC_OP_NZ_F32, /* FP dst != 0 (32bit) */ CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ + CC_OP_NZ_F128, /* FP dst != 0 (128bit) */ CC_OP_ICM, /* insert characters under mask */ CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ @@ -517,10 +515,9 @@ static const char *cc_names[] = { [CC_OP_COMP_64] = "CC_OP_COMP_64", [CC_OP_TM_32] = "CC_OP_TM_32", [CC_OP_TM_64] = "CC_OP_TM_64", - [CC_OP_LTGT_F32] = "CC_OP_LTGT_F32", - [CC_OP_LTGT_F64] = "CC_OP_LTGT_F64", [CC_OP_NZ_F32] = "CC_OP_NZ_F32", [CC_OP_NZ_F64] = "CC_OP_NZ_F64", + [CC_OP_NZ_F128] = "CC_OP_NZ_F128", [CC_OP_ICM] = "CC_OP_ICM", [CC_OP_SLA_32] = "CC_OP_SLA_32", [CC_OP_SLA_64] = "CC_OP_SLA_64", @@ -926,10 +923,9 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) } /* fpu_helper.c */ -uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2); -uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2); uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); +uint32_t set_cc_nz_f128(float128 v); /* misc_helper.c */ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 173f820428..92458ce8da 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -32,6 +32,52 @@ #define HELPER_LOG(x...) #endif +#define RET128(F) (env->retxl = F.low, F.high) + +#define convert_bit(mask, from, to) \ + (to < from \ + ? (mask / (from / to)) & to \ + : (mask & from) * (to / from)) + +static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr) +{ + /* Install the DXC code. */ + env->fpc = (env->fpc & ~0xff00) | (dxc << 8); + /* Trap. */ + runtime_exception(env, PGM_DATA, retaddr); +} + +/* Should be called after any operation that may raise IEEE exceptions. */ +static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr) +{ + unsigned s390_exc, qemu_exc; + + /* Get the exceptions raised by the current operation. Reset the + fpu_status contents so that the next operation has a clean slate. */ + qemu_exc = env->fpu_status.float_exception_flags; + if (qemu_exc == 0) { + return; + } + env->fpu_status.float_exception_flags = 0; + + /* Convert softfloat exception bits to s390 exception bits. */ + s390_exc = 0; + s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80); + s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40); + s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20); + s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10); + s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08); + + /* Install the exceptions that we raised. */ + env->fpc |= s390_exc << 16; + + /* Send signals for enabled exceptions. */ + s390_exc &= env->fpc >> 24; + if (s390_exc) { + ieee_exception(env, s390_exc, retaddr); + } +} + static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) { switch (float_compare) { @@ -48,19 +94,6 @@ static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) } } -/* condition codes for binary FP ops */ -uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2) -{ - return float_comp_to_cc(env, float32_compare_quiet(v1, v2, - &env->fpu_status)); -} - -uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2) -{ - return float_comp_to_cc(env, float64_compare_quiet(v1, v2, - &env->fpu_status)); -} - /* condition codes for unary FP ops */ uint32_t set_cc_nz_f32(float32 v) { @@ -88,7 +121,7 @@ uint32_t set_cc_nz_f64(float64 v) } } -static uint32_t set_cc_nz_f128(float128 v) +uint32_t set_cc_nz_f128(float128 v) { if (float128_is_any_nan(v)) { return 3; @@ -152,27 +185,31 @@ void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) env->fregs[f1].l.upper, f1); } -/* 32-bit FP addition RR */ -uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP addition */ +uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); + float32 ret = float32_add(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP addition RR */ -uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP addition */ +uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, - env->fregs[f2].d, env->fregs[f1].d, f1); + float64 ret = float64_add(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - return set_cc_nz_f64(env->fregs[f1].d); +/* 128-bit FP addition */ +uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_add(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* 32-bit FP subtraction RR */ @@ -246,50 +283,51 @@ void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) } /* convert 32-bit float to 64-bit float */ -void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) { - env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, - &env->fpu_status); + float64 ret = float32_to_float64(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 64-bit float */ -void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al) { - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); + float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 64-bit float to 128-bit float */ -void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) { - CPU_QuadU res; + float128 ret = float64_to_float128(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} - res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; +/* convert 32-bit float to 128-bit float */ +uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) +{ + float128 ret = float32_to_float128(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* convert 64-bit float to 32-bit float */ -void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2) { - float64 d2 = env->fregs[f2].d; - - env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); + float32 ret = float64_to_float32(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 32-bit float */ -void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) { - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); + float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* absolute value of 32-bit float */ @@ -328,32 +366,6 @@ uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(v1.q); } -/* load and test 64-bit float */ -uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = env->fregs[f2].d; - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load and test 32-bit float */ -uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = env->fregs[f2].l.upper; - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load and test 128-bit float */ -uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU x; - - x.ll.upper = env->fregs[f2].ll; - x.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 2].ll = x.ll.lower; - return set_cc_nz_f128(x.q); -} - /* load complement of 32-bit float */ uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { @@ -383,18 +395,6 @@ uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(x1.q); } -/* 32-bit FP addition RM */ -void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); -} - /* 32-bit FP division RM */ void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) { @@ -419,66 +419,31 @@ void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); } -/* 32-bit FP compare RR */ -uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP compare */ +uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - float32 v1 = env->fregs[f1].l.upper; - float32 v2 = env->fregs[f2].l.upper; - - HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2); - return set_cc_f32(env, v1, v2); + int cmp = float32_compare_quiet(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } -/* 64-bit FP compare RR */ -uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP compare */ +uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - float64 v1 = env->fregs[f1].d; - float64 v2 = env->fregs[f2].d; - - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, - v1, f1, v2); - return set_cc_f64(env, v1, v2); + int cmp = float64_compare_quiet(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } -/* 128-bit FP compare RR */ -uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 128-bit FP compare */ +uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) { - CPU_QuadU v1; - CPU_QuadU v2; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - - return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q, - &env->fpu_status)); -} - -/* 64-bit FP compare RM */ -uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, - f1, v2.d); - return set_cc_f64(env, v1, v2.d); -} - -/* 64-bit FP addition RM */ -uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); + int cmp = float128_compare_quiet(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } /* 32-bit FP subtraction RM */ @@ -672,23 +637,6 @@ uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(res.q); } -/* 128-bit FP addition RR */ -uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_add(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - /* 32-bit FP multiplication RR */ void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { @@ -747,28 +695,6 @@ void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) &env->fpu_status); } -/* convert 32-bit float to 64-bit float */ -void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - uint32_t v2; - - v2 = cpu_ldl_data(env, a2); - env->fregs[f1].d = float32_to_float64(v2, - &env->fpu_status); -} - -/* convert 64-bit float to 128-bit float */ -void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - CPU_DoubleU v2; - CPU_QuadU v1; - - v2.ll = cpu_ldq_data(env, a2); - v1.q = float64_to_float128(v2.d, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - /* test data class 32-bit */ uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 8cf9186b8b..2e6443321f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -36,40 +36,36 @@ DEF_HELPER_3(cxfbr, void, env, i32, s32) DEF_HELPER_3(cegbr, void, env, i32, s64) DEF_HELPER_3(cdgbr, void, env, i32, s64) DEF_HELPER_3(cxgbr, void, env, i32, s64) -DEF_HELPER_3(adbr, i32, env, i32, i32) -DEF_HELPER_3(aebr, i32, env, i32, i32) +DEF_HELPER_3(aeb, i64, env, i64, i64) +DEF_HELPER_3(adb, i64, env, i64, i64) +DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(sebr, i32, env, i32, i32) DEF_HELPER_3(sdbr, i32, env, i32, i32) DEF_HELPER_3(debr, void, env, i32, i32) DEF_HELPER_3(dxbr, void, env, i32, i32) DEF_HELPER_3(mdbr, void, env, i32, i32) DEF_HELPER_3(mxbr, void, env, i32, i32) -DEF_HELPER_3(ldebr, void, env, i32, i32) -DEF_HELPER_3(ldxbr, void, env, i32, i32) -DEF_HELPER_3(lxdbr, void, env, i32, i32) -DEF_HELPER_3(ledbr, void, env, i32, i32) -DEF_HELPER_3(lexbr, void, env, i32, i32) +DEF_HELPER_2(ldeb, i64, env, i64) +DEF_HELPER_3(ldxb, i64, env, i64, i64) +DEF_HELPER_2(lxdb, i64, env, i64) +DEF_HELPER_2(lxeb, i64, env, i64) +DEF_HELPER_2(ledb, i64, env, i64) +DEF_HELPER_3(lexb, i64, env, i64, i64) DEF_HELPER_3(lpebr, i32, env, i32, i32) DEF_HELPER_3(lpdbr, i32, env, i32, i32) DEF_HELPER_3(lpxbr, i32, env, i32, i32) -DEF_HELPER_3(ltebr, i32, env, i32, i32) -DEF_HELPER_3(ltdbr, i32, env, i32, i32) -DEF_HELPER_3(ltxbr, i32, env, i32, i32) DEF_HELPER_3(lcebr, i32, env, i32, i32) DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) -DEF_HELPER_3(aeb, void, env, i32, i32) DEF_HELPER_3(deb, void, env, i32, i32) DEF_HELPER_3(meeb, void, env, i32, i32) -DEF_HELPER_3(cdb, i32, env, i32, i64) -DEF_HELPER_3(adb, i32, env, i32, i64) DEF_HELPER_3(seb, void, env, i32, i32) DEF_HELPER_3(sdb, i32, env, i32, i64) DEF_HELPER_3(mdb, void, env, i32, i64) DEF_HELPER_3(ddb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(cebr, TCG_CALL_NO_SE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_NO_SE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_NO_SE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) +DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) +DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) @@ -79,7 +75,6 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_3(axbr, i32, env, i32, i32) DEF_HELPER_3(sxbr, i32, env, i32, i32) DEF_HELPER_3(meebr, void, env, i32, i32) DEF_HELPER_3(ddbr, void, env, i32, i32) @@ -87,11 +82,9 @@ DEF_HELPER_4(madb, void, env, i32, i64, i32) DEF_HELPER_4(maebr, void, env, i32, i32, i32) DEF_HELPER_4(madbr, void, env, i32, i32, i32) DEF_HELPER_4(msdbr, void, env, i32, i32, i32) -DEF_HELPER_3(ldeb, void, env, i32, i64) -DEF_HELPER_3(lxdb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8914d341f7..f1c37e8939 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -8,6 +8,11 @@ C(0xb9e8, AGRK, RRF_a, DO, r2, r3, r1, 0, add, adds64) C(0xe308, AG, RXY_a, Z, r1, m2_64, r1, 0, add, adds64) C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) + C(0xb30a, AEBR, RRE, Z, e1, e2, new, e1, aeb, f32) + C(0xb31a, ADBR, RRE, Z, f1_o, f2_o, f1, 0, adb, f64) + C(0xb34a, AXBR, RRE, Z, 0, x2_o, x1, 0, axb, f128) + C(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32) + C(0xed1a, ADB, RXE, Z, f1_o, m2_64, f1, 0, adb, f64) /* ADD IMMEDIATE */ C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32) @@ -94,6 +99,11 @@ C(0xb930, CGFR, RRE, Z, r1_o, r2_32s, 0, 0, 0, cmps64) C(0xe320, CG, RXY_a, Z, r1_o, m2_64, 0, 0, 0, cmps64) C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) + C(0xb309, CEBR, RRE, Z, e1, e2, 0, 0, ceb, 0) + C(0xb319, CDBR, RRE, Z, f1_o, f2_o, 0, 0, cdb, 0) + C(0xb349, CXBR, RRE, Z, x1_o, x2_o, 0, 0, cxb, 0) + C(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0) + C(0xed19, CDB, RXE, Z, f1_o, m2_64, 0, 0, cdb, 0) /* COMPARE IMMEDIATE */ C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) @@ -239,6 +249,9 @@ C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) + C(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32) + C(0xb312, LTDBR, RRE, Z, 0, f2_o, 0, f1, mov2, f64) + C(0xb342, LTXBR, RRE, Z, 0, x2_o, 0, x1, movx, f128) /* LOAD BYTE */ C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) @@ -303,6 +316,18 @@ C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) +/* LOAD LENGTHENED */ + C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) + C(0xb305, LXDBR, RRE, Z, 0, f2_o, x1, 0, lxdb, 0) + C(0xb306, LXEBR, RRE, Z, 0, e2, x1, 0, lxeb, 0) + C(0xed04, LDEB, RXE, Z, 0, m2_32u, f1, 0, ldeb, 0) + C(0xed05, LXDB, RXE, Z, 0, m2_64, x1, 0, lxdb, 0) + C(0xed06, LXEB, RXE, Z, 0, m2_32u, x1, 0, lxeb, 0) +/* LOAD ROUNDED */ + C(0xb344, LEDBR, RRE, Z, 0, f2_o, new, e1, ledb, 0) + C(0xb345, LDXBR, RRE, Z, 0, x2_o, f1, 0, ldxb, 0) + C(0xb346, LEXBR, RRE, Z, 0, x2_o, new, e1, lexb, 0) + /* LOAD MULTIPLE */ C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) C(0xeb98, LMY, RSY_a, LD, 0, a2, 0, 0, lm32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 033f93e3ef..f62e4f0431 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -556,14 +556,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) -{ - tcg_gen_extu_i32_i64(cc_src, v1); - tcg_gen_mov_i64(cc_dst, v2); - tcg_gen_discard_i64(cc_vr); - s->cc_op = CC_OP_LTGT_F32; -} - static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); @@ -628,10 +620,9 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_LTUGTU_64: case CC_OP_TM_32: case CC_OP_TM_64: - case CC_OP_LTGT_F32: - case CC_OP_LTGT_F64: case CC_OP_SLA_32: case CC_OP_SLA_64: + case CC_OP_NZ_F128: /* 2 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; @@ -1009,35 +1000,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { - case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_ldeb(cpu_env, tmp_r1, addr); - break; - case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_lxdb(cpu_env, tmp_r1, addr); - break; - case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = load_freg32(r1); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - set_cc_cmp_f32_i64(s, tmp32, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; - case 0xa: /* AEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_aeb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - - tmp32 = load_freg32(r1); - gen_set_cc_nz_f32(s, tmp32); - tcg_temp_free_i32(tmp32); - break; case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ tmp = tcg_temp_new_i64(); tmp32 = tcg_temp_new_i32(); @@ -1084,16 +1046,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; - case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_adb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); @@ -1524,24 +1476,9 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x0: /* LPEBR R1,R2 [RRE] */ FP_HELPER_CC(lpebr); break; - case 0x2: /* LTEBR R1,R2 [RRE] */ - FP_HELPER_CC(ltebr); - break; case 0x3: /* LCEBR R1,R2 [RRE] */ FP_HELPER_CC(lcebr); break; - case 0x4: /* LDEBR R1,R2 [RRE] */ - FP_HELPER(ldebr); - break; - case 0x5: /* LXDBR R1,R2 [RRE] */ - FP_HELPER(lxdbr); - break; - case 0x9: /* CEBR R1,R2 [RRE] */ - FP_HELPER_CC(cebr); - break; - case 0xa: /* AEBR R1,R2 [RRE] */ - FP_HELPER_CC(aebr); - break; case 0xb: /* SEBR R1,R2 [RRE] */ FP_HELPER_CC(sebr); break; @@ -1551,9 +1488,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x10: /* LPDBR R1,R2 [RRE] */ FP_HELPER_CC(lpdbr); break; - case 0x12: /* LTDBR R1,R2 [RRE] */ - FP_HELPER_CC(ltdbr); - break; case 0x13: /* LCDBR R1,R2 [RRE] */ FP_HELPER_CC(lcdbr); break; @@ -1563,12 +1497,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x17: /* MEEBR R1,R2 [RRE] */ FP_HELPER(meebr); break; - case 0x19: /* CDBR R1,R2 [RRE] */ - FP_HELPER_CC(cdbr); - break; - case 0x1a: /* ADBR R1,R2 [RRE] */ - FP_HELPER_CC(adbr); - break; case 0x1b: /* SDBR R1,R2 [RRE] */ FP_HELPER_CC(sdbr); break; @@ -1605,27 +1533,9 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x40: /* LPXBR R1,R2 [RRE] */ FP_HELPER_CC(lpxbr); break; - case 0x42: /* LTXBR R1,R2 [RRE] */ - FP_HELPER_CC(ltxbr); - break; case 0x43: /* LCXBR R1,R2 [RRE] */ FP_HELPER_CC(lcxbr); break; - case 0x44: /* LEDBR R1,R2 [RRE] */ - FP_HELPER(ledbr); - break; - case 0x45: /* LDXBR R1,R2 [RRE] */ - FP_HELPER(ldxbr); - break; - case 0x46: /* LEXBR R1,R2 [RRE] */ - FP_HELPER(lexbr); - break; - case 0x49: /* CXBR R1,R2 [RRE] */ - FP_HELPER_CC(cxbr); - break; - case 0x4a: /* AXBR R1,R2 [RRE] */ - FP_HELPER_CC(axbr); - break; case 0x4b: /* SXBR R1,R2 [RRE] */ FP_HELPER_CC(sxbr); break; @@ -2260,6 +2170,25 @@ static ExitStatus op_addc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_aeb(DisasContext *s, DisasOps *o) +{ + gen_helper_aeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_adb(DisasContext *s, DisasOps *o) +{ + gen_helper_adb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_axb(DisasContext *s, DisasOps *o) +{ + gen_helper_axb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_and(DisasContext *s, DisasOps *o) { tcg_gen_and_i64(o->out, o->in1, o->in2); @@ -2354,6 +2283,27 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_ceb(DisasContext *s, DisasOps *o) +{ + gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cdb(DisasContext *s, DisasOps *o) +{ + gen_helper_cdb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cxb(DisasContext *s, DisasOps *o) +{ + gen_helper_cxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); @@ -2610,6 +2560,44 @@ static ExitStatus op_insi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) +{ + gen_helper_ldeb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ledb(DisasContext *s, DisasOps *o) +{ + gen_helper_ledb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ldxb(DisasContext *s, DisasOps *o) +{ + gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_lexb(DisasContext *s, DisasOps *o) +{ + gen_helper_lexb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_lxdb(DisasContext *s, DisasOps *o) +{ + gen_helper_lxdb(o->out, cpu_env, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_lxeb(DisasContext *s, DisasOps *o) +{ + gen_helper_lxeb(o->out, cpu_env, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_llgt(DisasContext *s, DisasOps *o) { tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); @@ -3369,6 +3357,21 @@ static void cout_cmpu64(DisasContext *s, DisasOps *o) gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2); } +static void cout_f32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F32, o->out); +} + +static void cout_f64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F64, o->out); +} + +static void cout_f128(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_NZ_F128, o->out, o->out2); +} + static void cout_nabs32(DisasContext *s, DisasOps *o) { gen_op_update1_cc_i64(s, CC_OP_NABS_32, o->out); @@ -3482,6 +3485,21 @@ static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) o->g_out = o->g_out2 = true; } +static void prep_f1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = fregs[get_field(f, r1)]; + o->g_out = true; +} + +static void prep_x1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be < 14. */ + int r1 = get_field(f, r1); + o->out = fregs[r1]; + o->out2 = fregs[(r1 + 2) & 15]; + o->g_out = o->g_out2 = true; +} + /* ====================================================================== */ /* The "Write OUTput" generators. These generally perform some non-trivial copy of data to TCG globals, or to main memory. The trivial cases are @@ -3539,6 +3557,7 @@ static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o) static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o) { + /* ??? Specification exception: r1 must be < 14. */ int f1 = get_field(s->fields, r1); store_freg(f1, o->out); store_freg((f1 + 2) & 15, o->out2); @@ -3685,6 +3704,15 @@ static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be < 14. */ + int r1 = get_field(f, r1); + o->out = fregs[r1]; + o->out2 = fregs[(r1 + 2) & 15]; + o->g_out = o->g_out2 = true; +} + static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); @@ -3832,9 +3860,10 @@ static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o) static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) { - int f2 = get_field(f, r2); - o->in1 = fregs[f2]; - o->in2 = fregs[(f2 + 2) & 15]; + /* ??? Specification exception: r1 must be < 14. */ + int r2 = get_field(f, r2); + o->in1 = fregs[r2]; + o->in2 = fregs[(r2 + 2) & 15]; o->g_in1 = o->g_in2 = true; } From 1a800a2dcee541dee4f51aed5110ca9d5811c5e8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 11:05:03 -0700 Subject: [PATCH 075/149] target-s390: Convert FP SUBTRACT Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 74 +++++++++++--------------------------- target-s390x/helper.h | 8 ++--- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 51 ++++++++++---------------- 4 files changed, 47 insertions(+), 91 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 92458ce8da..ea61936571 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -212,27 +212,31 @@ uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, return RET128(ret); } -/* 32-bit FP subtraction RR */ -uint32_t HELPER(sebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP subtraction */ +uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); + float32 ret = float32_sub(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP subtraction RR */ -uint32_t HELPER(sdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP subtraction */ +uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", - __func__, env->fregs[f2].d, env->fregs[f1].d, f1); + float64 ret = float64_sub(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - return set_cc_nz_f64(env->fregs[f1].d); +/* 128-bit FP subtraction */ +uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_sub(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* 32-bit FP division RR */ @@ -446,27 +450,6 @@ uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return float_comp_to_cc(env, cmp); } -/* 32-bit FP subtraction RM */ -void HELPER(seb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); -} - -/* 64-bit FP subtraction RM */ -uint32_t HELPER(sdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); -} - /* 64-bit FP multiplication RM */ void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { @@ -620,23 +603,6 @@ void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) env->fregs[f1 + 1].ll = x.ll.lower; } -/* 128-bit FP subtraction RR */ -uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_sub(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - /* 32-bit FP multiplication RR */ void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 2e6443321f..4fca4c5c9e 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -39,8 +39,9 @@ DEF_HELPER_3(cxgbr, void, env, i32, s64) DEF_HELPER_3(aeb, i64, env, i64, i64) DEF_HELPER_3(adb, i64, env, i64, i64) DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(sebr, i32, env, i32, i32) -DEF_HELPER_3(sdbr, i32, env, i32, i32) +DEF_HELPER_3(seb, i64, env, i64, i64) +DEF_HELPER_3(sdb, i64, env, i64, i64) +DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(debr, void, env, i32, i32) DEF_HELPER_3(dxbr, void, env, i32, i32) DEF_HELPER_3(mdbr, void, env, i32, i32) @@ -59,8 +60,6 @@ DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) DEF_HELPER_3(deb, void, env, i32, i32) DEF_HELPER_3(meeb, void, env, i32, i32) -DEF_HELPER_3(seb, void, env, i32, i32) -DEF_HELPER_3(sdb, i32, env, i32, i64) DEF_HELPER_3(mdb, void, env, i32, i64) DEF_HELPER_3(ddb, void, env, i32, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) @@ -75,7 +74,6 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_3(sxbr, i32, env, i32, i32) DEF_HELPER_3(meebr, void, env, i32, i32) DEF_HELPER_3(ddbr, void, env, i32, i32) DEF_HELPER_4(madb, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f1c37e8939..fdfcffc470 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -476,6 +476,11 @@ C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) + C(0xb30b, SEBR, RRE, Z, e1, e2, new, e1, seb, f32) + C(0xb31b, SDBR, RRE, Z, f1_o, f2_o, f1, 0, sdb, f64) + C(0xb34b, SXBR, RRE, Z, 0, x2_o, x1, 0, sxb, f128) + C(0xed0b, SEB, RXE, Z, e1, m2_32u, new, e1, seb, f32) + C(0xed1b, SDB, RXE, Z, f1_o, m2_64, f1, 0, sdb, f64) /* SUBTRACT HALFWORD */ C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f62e4f0431..2b3b0fc789 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -556,11 +556,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); -} - /* CC value is in env->cc_op */ static inline void set_cc_static(DisasContext *s) { @@ -1000,19 +995,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { - case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_seb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - - tmp32 = load_freg32(r1); - gen_set_cc_nz_f32(s, tmp32); - tcg_temp_free_i32(tmp32); - break; case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ tmp = tcg_temp_new_i64(); tmp32 = tcg_temp_new_i32(); @@ -1046,11 +1028,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; - case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); gen_helper_mdb(cpu_env, tmp_r1, addr); @@ -1479,9 +1456,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x3: /* LCEBR R1,R2 [RRE] */ FP_HELPER_CC(lcebr); break; - case 0xb: /* SEBR R1,R2 [RRE] */ - FP_HELPER_CC(sebr); - break; case 0xd: /* DEBR R1,R2 [RRE] */ FP_HELPER(debr); break; @@ -1497,9 +1471,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x17: /* MEEBR R1,R2 [RRE] */ FP_HELPER(meebr); break; - case 0x1b: /* SDBR R1,R2 [RRE] */ - FP_HELPER_CC(sdbr); - break; case 0x1c: /* MDBR R1,R2 [RRE] */ FP_HELPER(mdbr); break; @@ -1536,9 +1507,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x43: /* LCXBR R1,R2 [RRE] */ FP_HELPER_CC(lcxbr); break; - case 0x4b: /* SXBR R1,R2 [RRE] */ - FP_HELPER_CC(sxbr); - break; case 0x4c: /* MXBR R1,R2 [RRE] */ FP_HELPER(mxbr); break; @@ -2955,6 +2923,25 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_seb(DisasContext *s, DisasOps *o) +{ + gen_helper_seb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sdb(DisasContext *s, DisasOps *o) +{ + gen_helper_sdb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sxb(DisasContext *s, DisasOps *o) +{ + gen_helper_sxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_sigp(DisasContext *s, DisasOps *o) { From f08a5c311d3047f2cafe72e3e377674e7f8acdcb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 7 Sep 2012 11:41:12 -0700 Subject: [PATCH 076/149] target-s390: Convert FP DIVIDE Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 68 +++++++++++--------------------------- target-s390x/helper.h | 8 ++--- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 41 +++++++++++------------ 4 files changed, 47 insertions(+), 75 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index ea61936571..b0c18ee7c2 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -239,28 +239,31 @@ uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return RET128(ret); } -/* 32-bit FP division RR */ -void HELPER(debr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP division */ +uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); + float32 ret = float32_div(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 128-bit FP division RR */ -void HELPER(dxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP division */ +uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; + float64 ret = float64_div(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_div(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; +/* 128-bit FP division */ +uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_div(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* 64-bit FP multiplication RR */ @@ -399,18 +402,6 @@ uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(x1.q); } -/* 32-bit FP division RM */ -void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); -} - /* 32-bit FP multiplication RM */ void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) { @@ -462,18 +453,6 @@ void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); } -/* 64-bit FP division RM */ -void HELPER(ddb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); -} - static void set_round_mode(CPUS390XState *env, int m3) { switch (m3) { @@ -611,13 +590,6 @@ void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) &env->fpu_status); } -/* 64-bit FP division RR */ -void HELPER(ddbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); -} - /* 64-bit FP multiply and add RM */ void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 4fca4c5c9e..bb094c0fb0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -42,8 +42,9 @@ DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(seb, i64, env, i64, i64) DEF_HELPER_3(sdb, i64, env, i64, i64) DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(debr, void, env, i32, i32) -DEF_HELPER_3(dxbr, void, env, i32, i32) +DEF_HELPER_3(deb, i64, env, i64, i64) +DEF_HELPER_3(ddb, i64, env, i64, i64) +DEF_HELPER_5(dxb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(mdbr, void, env, i32, i32) DEF_HELPER_3(mxbr, void, env, i32, i32) DEF_HELPER_2(ldeb, i64, env, i64) @@ -58,10 +59,8 @@ DEF_HELPER_3(lpxbr, i32, env, i32, i32) DEF_HELPER_3(lcebr, i32, env, i32, i32) DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) -DEF_HELPER_3(deb, void, env, i32, i32) DEF_HELPER_3(meeb, void, env, i32, i32) DEF_HELPER_3(mdb, void, env, i32, i64) -DEF_HELPER_3(ddb, void, env, i32, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) @@ -75,7 +74,6 @@ DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) DEF_HELPER_3(meebr, void, env, i32, i32) -DEF_HELPER_3(ddbr, void, env, i32, i32) DEF_HELPER_4(madb, void, env, i32, i64, i32) DEF_HELPER_4(maebr, void, env, i32, i32, i32) DEF_HELPER_4(madbr, void, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index fdfcffc470..14dcd12417 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -167,6 +167,11 @@ /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) + C(0xb30d, DEBR, RRE, Z, e1, e2, new, e1, deb, 0) + C(0xb31d, DDBR, RRE, Z, f1_o, f2_o, f1, 0, ddb, 0) + C(0xb34d, DXBR, RRE, Z, 0, x2_o, x1, 0, dxb, 0) + C(0xed0d, DEB, RXE, Z, e1, m2_32u, new, e1, deb, 0) + C(0xed1d, DDB, RXE, Z, f1_o, m2_64, f1, 0, ddb, 0) /* DIVIDE LOGICAL */ C(0xb997, DLR, RRE, Z, r1_D32, r2_32u, new_P, r1_P32, divu32, 0) C(0xe397, DL, RXY_a, Z, r1_D32, m2_32u, new_P, r1_P32, divu32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2b3b0fc789..c00992db55 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -995,15 +995,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { - case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_deb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); @@ -1032,10 +1023,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, potential_page_fault(s); gen_helper_mdb(cpu_env, tmp_r1, addr); break; - case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_ddb(cpu_env, tmp_r1, addr); - break; case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ /* for RXF insns, r1 is R3 and r1b is R1 */ tmp32 = tcg_const_i32(r1b); @@ -1456,9 +1443,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x3: /* LCEBR R1,R2 [RRE] */ FP_HELPER_CC(lcebr); break; - case 0xd: /* DEBR R1,R2 [RRE] */ - FP_HELPER(debr); - break; case 0x10: /* LPDBR R1,R2 [RRE] */ FP_HELPER_CC(lpdbr); break; @@ -1474,9 +1458,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x1c: /* MDBR R1,R2 [RRE] */ FP_HELPER(mdbr); break; - case 0x1d: /* DDBR R1,R2 [RRE] */ - FP_HELPER(ddbr); - break; case 0xe: /* MAEBR R1,R3,R2 [RRF] */ case 0x1e: /* MADBR R1,R3,R2 [RRF] */ case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ @@ -1510,9 +1491,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x4c: /* MXBR R1,R2 [RRE] */ FP_HELPER(mxbr); break; - case 0x4d: /* DXBR R1,R2 [RRE] */ - FP_HELPER(dxbr); - break; case 0x65: /* LXR R1,R2 [RRE] */ tmp = load_freg(r2); store_freg(r1, tmp); @@ -2428,6 +2406,25 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_deb(DisasContext *s, DisasOps *o) +{ + gen_helper_deb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ddb(DisasContext *s, DisasOps *o) +{ + gen_helper_ddb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_dxb(DisasContext *s, DisasOps *o) +{ + gen_helper_dxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_efpc(DisasContext *s, DisasOps *o) { tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); From 83b00736f3d8033861c27b80c9d3fc7c44bbec99 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 12:02:38 -0700 Subject: [PATCH 077/149] target-s390: Convert FP MULTIPLY Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 87 +++++++++++++++++--------------------- target-s390x/helper.h | 10 ++--- target-s390x/insn-data.def | 9 ++++ target-s390x/translate.c | 56 ++++++++++++++---------- 4 files changed, 86 insertions(+), 76 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b0c18ee7c2..9805026c6a 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -266,27 +266,50 @@ uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return RET128(ret); } -/* 64-bit FP multiplication RR */ -void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP multiplication */ +uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); + float32 ret = float32_mul(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 128-bit FP multiplication RR */ -void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP multiplication */ +uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; + float64 ret = float64_mul(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_mul(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; +/* 64/32-bit FP multiplication */ +uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) +{ + float64 ret = float32_to_float64(f2, &env->fpu_status); + ret = float64_mul(f1, ret, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* 128-bit FP multiplication */ +uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_mul(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + +/* 128/64-bit FP multiplication */ +uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t f2) +{ + float128 ret = float64_to_float128(f2, &env->fpu_status); + ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* convert 32-bit float to 64-bit float */ @@ -402,18 +425,6 @@ uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(x1.q); } -/* 32-bit FP multiplication RM */ -void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); -} - /* 32-bit FP compare */ uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { @@ -441,18 +452,6 @@ uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return float_comp_to_cc(env, cmp); } -/* 64-bit FP multiplication RM */ -void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); -} - static void set_round_mode(CPUS390XState *env, int m3) { switch (m3) { @@ -582,14 +581,6 @@ void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) env->fregs[f1 + 1].ll = x.ll.lower; } -/* 32-bit FP multiplication RR */ -void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); -} - /* 64-bit FP multiply and add RM */ void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index bb094c0fb0..36316c3959 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -45,8 +45,11 @@ DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(deb, i64, env, i64, i64) DEF_HELPER_3(ddb, i64, env, i64, i64) DEF_HELPER_5(dxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(mdbr, void, env, i32, i32) -DEF_HELPER_3(mxbr, void, env, i32, i32) +DEF_HELPER_3(meeb, i64, env, i64, i64) +DEF_HELPER_3(mdeb, i64, env, i64, i64) +DEF_HELPER_3(mdb, i64, env, i64, i64) +DEF_HELPER_5(mxb, i64, env, i64, i64, i64, i64) +DEF_HELPER_4(mxdb, i64, env, i64, i64, i64) DEF_HELPER_2(ldeb, i64, env, i64) DEF_HELPER_3(ldxb, i64, env, i64, i64) DEF_HELPER_2(lxdb, i64, env, i64) @@ -59,8 +62,6 @@ DEF_HELPER_3(lpxbr, i32, env, i32, i32) DEF_HELPER_3(lcebr, i32, env, i32, i32) DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) -DEF_HELPER_3(meeb, void, env, i32, i32) -DEF_HELPER_3(mdb, void, env, i32, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) @@ -73,7 +74,6 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_3(meebr, void, env, i32, i32) DEF_HELPER_4(madb, void, env, i32, i64, i32) DEF_HELPER_4(maebr, void, env, i32, i32, i32) DEF_HELPER_4(madbr, void, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 14dcd12417..89f71acebb 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -359,6 +359,15 @@ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0) + C(0xb31c, MDBR, RRE, Z, f1_o, f2_o, f1, 0, mdb, 0) + C(0xb34c, MXBR, RRE, Z, 0, x2_o, x1, 0, mxb, 0) + C(0xb30c, MDEBR, RRE, Z, f1_o, e2, f1, 0, mdeb, 0) + C(0xb307, MXDBR, RRE, Z, 0, f2_o, x1, 0, mxdb, 0) + C(0xed17, MEEB, RXE, Z, e1, m2_32u, new, e1, meeb, 0) + C(0xed1c, MDB, RXE, Z, f1_o, m2_64, f1, 0, mdb, 0) + C(0xed0c, MDEB, RXE, Z, f1_o, m2_32u, f1, 0, mdeb, 0) + C(0xed07, MXDB, RXE, Z, 0, m2_64, x1, 0, mxdb, 0) /* MULTIPLY HALFWORD */ C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c00992db55..10bf3a0abe 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -991,7 +991,7 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { TCGv_i32 tmp_r1, tmp32; - TCGv_i64 addr, tmp; + TCGv_i64 addr; addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { @@ -1010,19 +1010,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; - case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_meeb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; - case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_mdb(cpu_env, tmp_r1, addr); - break; case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ /* for RXF insns, r1 is R3 and r1b is R1 */ tmp32 = tcg_const_i32(r1b); @@ -1452,12 +1439,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x15: /* SQBDR R1,R2 [RRE] */ FP_HELPER(sqdbr); break; - case 0x17: /* MEEBR R1,R2 [RRE] */ - FP_HELPER(meebr); - break; - case 0x1c: /* MDBR R1,R2 [RRE] */ - FP_HELPER(mdbr); - break; case 0xe: /* MAEBR R1,R3,R2 [RRF] */ case 0x1e: /* MADBR R1,R3,R2 [RRF] */ case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ @@ -1488,9 +1469,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x43: /* LCXBR R1,R2 [RRE] */ FP_HELPER_CC(lcxbr); break; - case 0x4c: /* MXBR R1,R2 [RRE] */ - FP_HELPER(mxbr); - break; case 0x65: /* LXR R1,R2 [RRE] */ tmp = load_freg(r2); store_freg(r1, tmp); @@ -2827,6 +2805,38 @@ static ExitStatus op_mul128(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_meeb(DisasContext *s, DisasOps *o) +{ + gen_helper_meeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mdeb(DisasContext *s, DisasOps *o) +{ + gen_helper_mdeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mdb(DisasContext *s, DisasOps *o) +{ + gen_helper_mdb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mxb(DisasContext *s, DisasOps *o) +{ + gen_helper_mxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_mxdb(DisasContext *s, DisasOps *o) +{ + gen_helper_mxdb(o->out, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_nabs(DisasContext *s, DisasOps *o) { gen_helper_nabs_i64(o->out, o->in2); From 722bfec331504bf873a5e4ec4f232c4ed116dda2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 12:30:12 -0700 Subject: [PATCH 078/149] target-s390: Convert MULTIPLY AND ADD, SUBTRACT Use the new float*_muladd interface to softfloat. Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 57 ++++++++++++++++------------------ target-s390x/helper.h | 8 ++--- target-s390x/insn-data.def | 11 +++++++ target-s390x/translate.c | 63 +++++++++++++++++++------------------- 4 files changed, 72 insertions(+), 67 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 9805026c6a..8f2c504beb 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -581,47 +581,42 @@ void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) env->fregs[f1 + 1].ll = x.ll.lower; } -/* 64-bit FP multiply and add RM */ -void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) +/* 32-bit FP multiply and add */ +uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - CPU_DoubleU v2; - - HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); - v2.ll = cpu_ldq_data(env, a2); - env->fregs[f1].d = float64_add(env->fregs[f1].d, - float64_mul(v2.d, env->fregs[f3].d, - &env->fpu_status), - &env->fpu_status); + float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiply and add RR */ -void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* 64-bit FP multiply and add */ +uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); + float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiply and subtract RR */ -void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* 32-bit FP multiply and subtract */ +uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); + float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, + &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 32-bit FP multiply and add RR */ -void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* 64-bit FP multiply and subtract */ +uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - float32_mul(env->fregs[f2].l.upper, - env->fregs[f3].l.upper, - &env->fpu_status), - &env->fpu_status); + float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, + &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* test data class 32-bit */ diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 36316c3959..21158493c8 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -74,10 +74,10 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_4(madb, void, env, i32, i64, i32) -DEF_HELPER_4(maebr, void, env, i32, i32, i32) -DEF_HELPER_4(madbr, void, env, i32, i32, i32) -DEF_HELPER_4(msdbr, void, env, i32, i32, i32) +DEF_HELPER_4(maeb, i64, env, i64, i64, i64) +DEF_HELPER_4(madb, i64, env, i64, i64, i64) +DEF_HELPER_4(mseb, i64, env, i64, i64, i64) +DEF_HELPER_4(msdb, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 89f71acebb..a924a93f7b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -391,6 +391,17 @@ C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY AND ADD */ + C(0xb30e, MAEBR, RRD, Z, e1, e2, new, e1, maeb, 0) + C(0xb31e, MADBR, RRD, Z, f1_o, f2_o, f1, 0, madb, 0) + C(0xed0e, MAEB, RXF, Z, e1, m2_32u, new, e1, maeb, 0) + C(0xed1e, MADB, RXF, Z, f1_o, m2_64, f1, 0, madb, 0) +/* MULTIPLY AND SUBTRACT */ + C(0xb30f, MSEBR, RRD, Z, e1, e2, new, e1, mseb, 0) + C(0xb31f, MSDBR, RRD, Z, f1_o, f2_o, f1, 0, msdb, 0) + C(0xed0f, MSEB, RXF, Z, e1, m2_32u, new, e1, mseb, 0) + C(0xed1f, MSDB, RXF, Z, f1_o, m2_64, f1, 0, msdb, 0) + /* OR */ C(0x1600, OR, RR_a, Z, r1, r2, new, r1_32, or, nz32) C(0xb9f6, ORK, RRF_a, DO, r2, r3, new, r1_32, or, nz32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 10bf3a0abe..faf979fe3c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -990,7 +990,7 @@ static void free_compare(DisasCompare *c) static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { - TCGv_i32 tmp_r1, tmp32; + TCGv_i32 tmp_r1; TCGv_i64 addr; addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); @@ -1010,13 +1010,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; - case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ - /* for RXF insns, r1 is R3 and r1b is R1 */ - tmp32 = tcg_const_i32(r1b); - potential_page_fault(s); - gen_helper_madb(cpu_env, tmp32, addr, tmp_r1); - tcg_temp_free_i32(tmp32); - break; default: LOG_DISAS("illegal ed operation 0x%x\n", op); gen_illegal_opcode(s); @@ -1439,30 +1432,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x15: /* SQBDR R1,R2 [RRE] */ FP_HELPER(sqdbr); break; - case 0xe: /* MAEBR R1,R3,R2 [RRF] */ - case 0x1e: /* MADBR R1,R3,R2 [RRF] */ - case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ - /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */ - tmp32_1 = tcg_const_i32(m3); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(r1); - switch (op) { - case 0xe: - gen_helper_maebr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - case 0x1e: - gen_helper_madbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - case 0x1f: - gen_helper_msdbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x40: /* LPXBR R1,R2 [RRE] */ FP_HELPER_CC(lpxbr); break; @@ -2837,6 +2806,36 @@ static ExitStatus op_mxdb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_maeb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 r3 = load_freg32_i64(get_field(s->fields, r3)); + gen_helper_maeb(o->out, cpu_env, o->in1, o->in2, r3); + tcg_temp_free_i64(r3); + return NO_EXIT; +} + +static ExitStatus op_madb(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + gen_helper_madb(o->out, cpu_env, o->in1, o->in2, fregs[r3]); + return NO_EXIT; +} + +static ExitStatus op_mseb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 r3 = load_freg32_i64(get_field(s->fields, r3)); + gen_helper_mseb(o->out, cpu_env, o->in1, o->in2, r3); + tcg_temp_free_i64(r3); + return NO_EXIT; +} + +static ExitStatus op_msdb(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + gen_helper_msdb(o->out, cpu_env, o->in1, o->in2, fregs[r3]); + return NO_EXIT; +} + static ExitStatus op_nabs(DisasContext *s, DisasOps *o) { gen_helper_nabs_i64(o->out, o->in2); From 31aa97d1ed87853835a2df4ea9db1566f85c57a2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 12:40:09 -0700 Subject: [PATCH 079/149] target-s390: Convert TEST DATA CLASS Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 28 ++++++---------- target-s390x/helper.h | 6 ++-- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 66 +++++++++++++------------------------- 4 files changed, 40 insertions(+), 65 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 8f2c504beb..7638a0d4a8 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -620,13 +620,12 @@ uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, } /* test data class 32-bit */ -uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tceb)(uint64_t f1, uint64_t m2) { - float32 v1 = env->fregs[f1].l.upper; + float32 v1 = f1; int neg = float32_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -636,19 +635,16 @@ uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) /* assume normalized number */ cc = 1; } - /* FIXME: denormalized? */ return cc; } /* test data class 64-bit */ -uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tcdb)(uint64_t v1, uint64_t m2) { - float64 v1 = env->fregs[f1].d; int neg = float64_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -663,20 +659,16 @@ uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) } /* test data class 128-bit */ -uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tcxb)(uint64_t ah, uint64_t al, uint64_t m2) { - CPU_QuadU v1; + float128 v1 = make_float128(ah, al); + int neg = float128_is_neg(v1); uint32_t cc = 0; - int neg; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - - neg = float128_is_neg(v1.q); - if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || - (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || - (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || - (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { + if ((float128_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float128_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float128_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || + (float128_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { cc = 1; } else if (m2 & (1 << (9-neg))) { /* assume normalized number */ diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 21158493c8..71dcdb5f3d 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -78,9 +78,9 @@ DEF_HELPER_4(maeb, i64, env, i64, i64, i64) DEF_HELPER_4(madb, i64, env, i64, i64, i64) DEF_HELPER_4(mseb, i64, env, i64, i64, i64) DEF_HELPER_4(msdb, i64, env, i64, i64, i64) -DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a924a93f7b..54b75e13b4 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -531,6 +531,11 @@ /* SUPERVISOR CALL */ C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) +/* TEST DATA CLASS */ + C(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0) + C(0xed11, TCDB, RXE, Z, f1_o, a2, 0, 0, tcdb, 0) + C(0xed12, TCXB, RXE, Z, x1_o, a2, 0, 0, tcxb, 0) + /* TEST UNDER MASK */ C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index faf979fe3c..6593d88c68 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -987,38 +987,6 @@ static void free_compare(DisasCompare *c) } } -static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, - int x2, int b2, int d2, int r1b) -{ - TCGv_i32 tmp_r1; - TCGv_i64 addr; - addr = get_address(s, x2, b2, d2); - tmp_r1 = tcg_const_i32(r1); - switch (op) { - case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tcdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - default: - LOG_DISAS("illegal ed operation 0x%x\n", op); - gen_illegal_opcode(s); - return; - } - tcg_temp_free_i32(tmp_r1); - tcg_temp_free_i64(addr); -} - static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { @@ -1602,7 +1570,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d2, x2, b2, r1b; + int op, r1, r2, r3; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -1628,17 +1596,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xed: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - x2 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = (short)((insn >> 16) & 0xfff); - r1b = (insn >> 12) & 0xf; - disas_ed(env, s, op, r1, x2, b2, d2, r1b); - break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); gen_illegal_opcode(s); @@ -3224,6 +3181,27 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) return EXIT_NORETURN; } +static ExitStatus op_tceb(DisasContext *s, DisasOps *o) +{ + gen_helper_tceb(cc_op, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_tcdb(DisasContext *s, DisasOps *o) +{ + gen_helper_tcdb(cc_op, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_tcxb(DisasContext *s, DisasOps *o) +{ + gen_helper_tcxb(cc_op, o->out, o->out2, o->in2); + set_cc_static(s); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_tprot(DisasContext *s, DisasOps *o) { From 5d7fd045cafeac1831c1999cb9e1251b7906c6b2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 15:58:27 -0700 Subject: [PATCH 080/149] target-s390: Convert FP LOAD COMPLIMENT, NEGATIVE, POSITIVE Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 65 ----------------------------- target-s390x/helper.h | 6 --- target-s390x/insn-data.def | 9 +++++ target-s390x/translate.c | 83 ++++++++++++++++++++++++++------------ 4 files changed, 66 insertions(+), 97 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 7638a0d4a8..b46dd02178 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -360,71 +360,6 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) return ret; } -/* absolute value of 32-bit float */ -uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float32 v1; - float32 v2 = env->fregs[f2].d; - - v1 = float32_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f32(v1); -} - -/* absolute value of 64-bit float */ -uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float64 v1; - float64 v2 = env->fregs[f2].d; - - v1 = float64_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f64(v1); -} - -/* absolute value of 128-bit float */ -uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - v1.q = float128_abs(v2.q); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; - return set_cc_nz_f128(v1.q); -} - -/* load complement of 32-bit float */ -uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load complement of 64-bit float */ -uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_chs(env->fregs[f2].d); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load complement of 128-bit float */ -uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU x1, x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - x1.q = float128_chs(x2.q); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; - return set_cc_nz_f128(x1.q); -} - /* 32-bit FP compare */ uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 71dcdb5f3d..4d2b0530ce 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -56,12 +56,6 @@ DEF_HELPER_2(lxdb, i64, env, i64) DEF_HELPER_2(lxeb, i64, env, i64) DEF_HELPER_2(ledb, i64, env, i64) DEF_HELPER_3(lexb, i64, env, i64, i64) -DEF_HELPER_3(lpebr, i32, env, i32, i32) -DEF_HELPER_3(lpdbr, i32, env, i32, i32) -DEF_HELPER_3(lpxbr, i32, env, i32, i32) -DEF_HELPER_3(lcebr, i32, env, i32, i32) -DEF_HELPER_3(lcdbr, i32, env, i32, i32) -DEF_HELPER_3(lcxbr, i32, env, i32, i32) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 54b75e13b4..74bc9945e9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -266,6 +266,9 @@ C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) + C(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32) + C(0xb313, LCDBR, RRE, Z, 0, f2_o, f1, 0, negf64, f64) + C(0xb343, LCXBR, RRE, Z, 0, x2_o, x1, 0, negf128, f128) /* LOAD HALFWORD */ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) @@ -310,10 +313,16 @@ C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) + C(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32) + C(0xb311, LNDBR, RRE, Z, 0, f2_o, f1, 0, nabsf64, f64) + C(0xb341, LNXBR, RRE, Z, 0, x2_o, x1, 0, nabsf128, f128) /* LOAD POSITIVE */ C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) + C(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32) + C(0xb310, LPDBR, RRE, Z, 0, f2_o, f1, 0, absf64, f64) + C(0xb340, LPXBR, RRE, Z, 0, x2_o, x1, 0, absf128, f128) /* LOAD REVERSED */ C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6593d88c68..b6043d6701 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1385,35 +1385,9 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_2); switch (op) { - case 0x0: /* LPEBR R1,R2 [RRE] */ - FP_HELPER_CC(lpebr); - break; - case 0x3: /* LCEBR R1,R2 [RRE] */ - FP_HELPER_CC(lcebr); - break; - case 0x10: /* LPDBR R1,R2 [RRE] */ - FP_HELPER_CC(lpdbr); - break; - case 0x13: /* LCDBR R1,R2 [RRE] */ - FP_HELPER_CC(lcdbr); - break; case 0x15: /* SQBDR R1,R2 [RRE] */ FP_HELPER(sqdbr); break; - case 0x40: /* LPXBR R1,R2 [RRE] */ - FP_HELPER_CC(lpxbr); - break; - case 0x43: /* LCXBR R1,R2 [RRE] */ - FP_HELPER_CC(lcxbr); - break; - case 0x65: /* LXR R1,R2 [RRE] */ - tmp = load_freg(r2); - store_freg(r1, tmp); - tcg_temp_free_i64(tmp); - tmp = load_freg(r2 + 2); - store_freg(r1 + 2, tmp); - tcg_temp_free_i64(tmp); - break; case 0x74: /* LZER R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); gen_helper_lzer(cpu_env, tmp32_1); @@ -1997,6 +1971,25 @@ static ExitStatus op_abs(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_absf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffull); + return NO_EXIT; +} + +static ExitStatus op_absf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull); + return NO_EXIT; +} + +static ExitStatus op_absf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in1, 0x7fffffffffffffffull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + static ExitStatus op_add(DisasContext *s, DisasOps *o) { tcg_gen_add_i64(o->out, o->in1, o->in2); @@ -2799,6 +2792,25 @@ static ExitStatus op_nabs(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_nabsf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in2, 0x80000000ull); + return NO_EXIT; +} + +static ExitStatus op_nabsf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in2, 0x8000000000000000ull); + return NO_EXIT; +} + +static ExitStatus op_nabsf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in1, 0x8000000000000000ull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + static ExitStatus op_nc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); @@ -2815,6 +2827,25 @@ static ExitStatus op_neg(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_negf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in2, 0x80000000ull); + return NO_EXIT; +} + +static ExitStatus op_negf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in2, 0x8000000000000000ull); + return NO_EXIT; +} + +static ExitStatus op_negf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in1, 0x8000000000000000ull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + static ExitStatus op_oc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); From 16d7b2a43b3325882d51677d76a0a3f082844f2b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 14:33:03 -0700 Subject: [PATCH 081/149] target-s390: Convert FP SQUARE ROOT Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 24 +++++++++++++++++++++--- target-s390x/helper.h | 4 +++- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 22 +++++++++++++++++++--- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b46dd02178..3b28ccb620 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -613,8 +613,26 @@ uint32_t HELPER(tcxb)(uint64_t ah, uint64_t al, uint64_t m2) return cc; } -/* square root 64-bit RR */ -void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* square root 32-bit */ +uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) { - env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); + float32 ret = float32_sqrt(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* square root 64-bit */ +uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) +{ + float64 ret = float64_sqrt(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* square root 128-bit */ +uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) +{ + float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 4d2b0530ce..eb8d663cc7 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -76,7 +76,9 @@ DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) -DEF_HELPER_3(sqdbr, void, env, i32, i32) +DEF_HELPER_2(sqeb, i64, env, i64) +DEF_HELPER_2(sqdb, i64, env, i64) +DEF_HELPER_3(sqxb, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 74bc9945e9..93fd3cab19 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -459,6 +459,13 @@ /* SHIFT RIGHT DOUBLE LOGICAL */ C(0x8c00, SRDL, RS_a, Z, r1_D32, sh64, new, r1_D32, srl, 0) +/* SQUARE ROOT */ + C(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0) + C(0xb315, SQDBR, RRE, Z, 0, f2_o, f1, 0, sqdb, 0) + C(0xb316, SQXBR, RRE, Z, 0, x2_o, x1, 0, sqxb, 0) + C(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0) + C(0xed15, SQDB, RXE, Z, 0, m2_64, f1, 0, sqdb, 0) + /* STORE */ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b6043d6701..dd77998201 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1385,9 +1385,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_2); switch (op) { - case 0x15: /* SQBDR R1,R2 [RRE] */ - FP_HELPER(sqdbr); - break; case 0x74: /* LZER R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); gen_helper_lzer(cpu_env, tmp32_1); @@ -2936,6 +2933,25 @@ static ExitStatus op_sxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sqeb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqeb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sqdb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqdb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sqxb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqxb(o->out, cpu_env, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_sigp(DisasContext *s, DisasOps *o) { From 24db8412ec58a63556fb51fb157497342f1b08b8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:14:24 -0700 Subject: [PATCH 082/149] target-s390: Convert LOAD ZERO Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 22 ---------------------- target-s390x/helper.h | 3 --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 29 ++++++++++++++--------------- 4 files changed, 18 insertions(+), 40 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 3b28ccb620..b735c2c384 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -494,28 +494,6 @@ uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, return set_cc_nz_f128(v2.q); } -/* load 32-bit FP zero */ -void HELPER(lzer)(CPUS390XState *env, uint32_t f1) -{ - env->fregs[f1].l.upper = float32_zero; -} - -/* load 64-bit FP zero */ -void HELPER(lzdr)(CPUS390XState *env, uint32_t f1) -{ - env->fregs[f1].d = float64_zero; -} - -/* load 128-bit FP zero */ -void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) -{ - CPU_QuadU x; - - x.q = float64_to_float128(float64_zero, &env->fpu_status); - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 1].ll = x.ll.lower; -} - /* 32-bit FP multiply and add */ uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index eb8d663cc7..89a3218e4d 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -62,9 +62,6 @@ DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) -DEF_HELPER_2(lzer, void, env, i32) -DEF_HELPER_2(lzdr, void, env, i32) -DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 93fd3cab19..e6b9a5aa7f 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -329,6 +329,10 @@ C(0xe31f, LRVH, RXY_a, Z, 0, m2_16u, new, r1_16, rev16, 0) C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) +/* LOAD ZERO */ + C(0xb374, LZER, RRE, Z, 0, 0, 0, e1, zero, 0) + C(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0) + C(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0) /* LOAD LENGTHENED */ C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dd77998201..b1bcfd393b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1385,21 +1385,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_2); switch (op) { - case 0x74: /* LZER R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzer(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x75: /* LZDR R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzdr(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x76: /* LZXR R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzxr(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x84: /* SFPC R1 [RRE] */ tmp32_1 = load_reg32(r1); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); @@ -3310,6 +3295,20 @@ static ExitStatus op_xori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_zero(DisasContext *s, DisasOps *o) +{ + o->out = tcg_const_i64(0); + return NO_EXIT; +} + +static ExitStatus op_zero2(DisasContext *s, DisasOps *o) +{ + o->out = tcg_const_i64(0); + o->out2 = o->out; + o->g_out2 = true; + return NO_EXIT; +} + /* ====================================================================== */ /* The "Cc OUTput" generators. Given the generated output (and in some cases the original inputs), update the various cc data structures in order to From 68c8bd93ccb0ee441d62b5b8b8911cf5c38663f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 15:17:35 -0700 Subject: [PATCH 083/149] target-s390: Convert CONVERT TO FIXED Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 98 ++++++++++++----------------- target-s390x/helper.h | 12 ++-- target-s390x/insn-data.def | 7 +++ target-s390x/translate.c | 125 +++++++++++++++++++++---------------- 4 files changed, 124 insertions(+), 118 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b735c2c384..ff3b435e89 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -387,8 +387,9 @@ uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return float_comp_to_cc(env, cmp); } -static void set_round_mode(CPUS390XState *env, int m3) +static int swap_round_mode(CPUS390XState *env, int m3) { + int ret = env->fpu_status.float_rounding_mode; switch (m3) { case 0: /* current mode */ @@ -412,86 +413,69 @@ static void set_round_mode(CPUS390XState *env, int m3) set_float_rounding_mode(float_round_down, &env->fpu_status); break; } + return ret; } /* convert 32-bit float to 64-bit int */ -uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(env, m3); - env->regs[r1] = float32_to_int64(v2, &env->fpu_status); - return set_cc_nz_f32(v2); + int hold = swap_round_mode(env, m3); + int64_t ret = float32_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 64-bit float to 64-bit int */ -uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float64 v2 = env->fregs[f2].d; - - set_round_mode(env, m3); - env->regs[r1] = float64_to_int64(v2, &env->fpu_status); - return set_cc_nz_f64(v2); + int hold = swap_round_mode(env, m3); + int64_t ret = float64_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 64-bit int */ -uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) { - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - set_round_mode(env, m3); - env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); - if (float128_is_any_nan(v2.q)) { - return 3; - } else if (float128_is_zero(v2.q)) { - return 0; - } else if (float128_is_neg(v2.q)) { - return 1; - } else { - return 2; - } + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + int64_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 32-bit float to 32-bit int */ -uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(env, m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float32_to_int32(v2, &env->fpu_status); - return set_cc_nz_f32(v2); + int hold = swap_round_mode(env, m3); + int32_t ret = float32_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 64-bit float to 32-bit int */ -uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float64 v2 = env->fregs[f2].d; - - set_round_mode(env, m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float64_to_int32(v2, &env->fpu_status); - return set_cc_nz_f64(v2); + int hold = swap_round_mode(env, m3); + int32_t ret = float64_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 32-bit int */ -uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) { - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float128_to_int32(v2.q, &env->fpu_status); - return set_cc_nz_f128(v2.q); + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + int32_t ret = float128_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* 32-bit FP multiply and add */ diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 89a3218e4d..1439b5ed1f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -59,12 +59,12 @@ DEF_HELPER_3(lexb, i64, env, i64, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) -DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) -DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) +DEF_HELPER_3(cgeb, i64, env, i64, i32) +DEF_HELPER_3(cgdb, i64, env, i64, i32) +DEF_HELPER_4(cgxb, i64, env, i64, i64, i32) +DEF_HELPER_3(cfeb, i64, env, i64, i32) +DEF_HELPER_3(cfdb, i64, env, i64, i32) +DEF_HELPER_4(cfxb, i64, env, i64, i64, i32) DEF_HELPER_4(maeb, i64, env, i64, i64, i64) DEF_HELPER_4(madb, i64, env, i64, i64, i64) DEF_HELPER_4(mseb, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e6b9a5aa7f..2d88b70474 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -163,6 +163,13 @@ /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) +/* CONVERT TO FIXED */ + C(0xb398, CFEBR, RRF_e, Z, 0, e2, new, r1_32, cfeb, 0) + C(0xb399, CFDBR, RRF_e, Z, 0, f2_o, new, r1_32, cfdb, 0) + C(0xb39a, CFXBR, RRF_e, Z, 0, x2_o, new, r1_32, cfxb, 0) + C(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0) + C(0xb3a9, CGDBR, RRF_e, Z, 0, f2_o, r1, 0, cgdb, 0) + C(0xb3aa, CGXBR, RRF_e, Z, 0, x2_o, r1, 0, cgxb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b1bcfd393b..03fae68b10 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -485,6 +485,21 @@ static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_NZ, val); } +static inline void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val); +} + +static inline void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val); +} + +static inline void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) +{ + gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl); +} + static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, enum cc_op cond) { @@ -1367,7 +1382,7 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, int r1, int r2) { TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1, tmp32_2; LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); #define FP_HELPER(i) \ tmp32_1 = tcg_const_i32(r1); \ @@ -1411,30 +1426,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x98: /* CFEBR R1,R2 [RRE] */ - case 0x99: /* CFDBR R1,R2 [RRE] */ - case 0x9a: /* CFXBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - switch (op) { - case 0x98: - gen_helper_cfebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x99: - gen_helper_cfdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x9a: - gen_helper_cfxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0xa4: /* CEGBR R1,R2 [RRE] */ case 0xa5: /* CDGBR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); @@ -1459,36 +1450,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0xa8: /* CGEBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xa9: /* CGDBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xaa: /* CGXBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; default: LOG_DISAS("illegal b3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2129,6 +2090,60 @@ static ExitStatus op_cxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cfeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cfdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cfxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cgeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cgdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cgxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); From 683bb9a8889cd00e69b05ba78bd5ba27f2e4e958 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 21:08:22 -0700 Subject: [PATCH 084/149] target-s390: Convert CONVERT FROM FIXED Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 81 ++++++++++++++------------------------ target-s390x/helper.h | 9 ++--- target-s390x/insn-data.def | 7 ++++ target-s390x/translate.c | 73 ++++++++++++---------------------- 4 files changed, 66 insertions(+), 104 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index ff3b435e89..ac530e9700 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -134,57 +134,6 @@ uint32_t set_cc_nz_f128(float128 v) } } -/* convert 32-bit int to 64-bit float */ -void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) -{ - HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); -} - -/* convert 32-bit int to 128-bit float */ -void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) -{ - CPU_QuadU v1; - - v1.q = int32_to_float128(v2, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - -/* convert 64-bit int to 32-bit float */ -void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); -} - -/* convert 64-bit int to 64-bit float */ -void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); -} - -/* convert 64-bit int to 128-bit float */ -void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) -{ - CPU_QuadU x1; - - x1.q = int64_to_float128(v2, &env->fpu_status); - HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, - x1.ll.upper, x1.ll.lower); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; -} - -/* convert 32-bit int to 32-bit float */ -void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) -{ - env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); - HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, - env->fregs[f1].l.upper, f1); -} - /* 32-bit FP addition */ uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { @@ -416,6 +365,36 @@ static int swap_round_mode(CPUS390XState *env, int m3) return ret; } +/* convert 64-bit int to 32-bit float */ +uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float32 ret = int64_to_float32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit int to 64-bit float */ +uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float64 ret = int64_to_float64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit int to 128-bit float */ +uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 ret = int64_to_float128(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + /* convert 32-bit float to 64-bit int */ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 1439b5ed1f..d9f630ecc3 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -30,12 +30,9 @@ DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) -DEF_HELPER_3(cefbr, void, env, i32, s32) -DEF_HELPER_3(cdfbr, void, env, i32, s32) -DEF_HELPER_3(cxfbr, void, env, i32, s32) -DEF_HELPER_3(cegbr, void, env, i32, s64) -DEF_HELPER_3(cdgbr, void, env, i32, s64) -DEF_HELPER_3(cxgbr, void, env, i32, s64) +DEF_HELPER_3(cegb, i64, env, s64, i32) +DEF_HELPER_3(cdgb, i64, env, s64, i32) +DEF_HELPER_3(cxgb, i64, env, s64, i32) DEF_HELPER_3(aeb, i64, env, i64, i64) DEF_HELPER_3(adb, i64, env, i64, i64) DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2d88b70474..d5e1c5c1cd 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -170,6 +170,13 @@ C(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0) C(0xb3a9, CGDBR, RRF_e, Z, 0, f2_o, r1, 0, cgdb, 0) C(0xb3aa, CGXBR, RRF_e, Z, 0, x2_o, r1, 0, cgxb, 0) +/* CONVERT FROM FIXED */ + C(0xb394, CEFBR, RRF_e, Z, 0, r2_32s, new, e1, cegb, 0) + C(0xb395, CDFBR, RRF_e, Z, 0, r2_32s, f1, 0, cdgb, 0) + C(0xb396, CXFBR, RRF_e, Z, 0, r2_32s, x1, 0, cxgb, 0) + C(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0) + C(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, f1, 0, cdgb, 0) + C(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, x1, 0, cxgb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 03fae68b10..47ccc6740a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1381,8 +1381,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, int r1, int r2) { - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2; + TCGv_i32 tmp32_1; LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); #define FP_HELPER(i) \ tmp32_1 = tcg_const_i32(r1); \ @@ -1405,51 +1404,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); tcg_temp_free_i32(tmp32_1); break; - case 0x94: /* CEFBR R1,R2 [RRE] */ - case 0x95: /* CDFBR R1,R2 [RRE] */ - case 0x96: /* CXFBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = load_reg32(r2); - switch (op) { - case 0x94: - gen_helper_cefbr(cpu_env, tmp32_1, tmp32_2); - break; - case 0x95: - gen_helper_cdfbr(cpu_env, tmp32_1, tmp32_2); - break; - case 0x96: - gen_helper_cxfbr(cpu_env, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xa4: /* CEGBR R1,R2 [RRE] */ - case 0xa5: /* CDGBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - switch (op) { - case 0xa4: - gen_helper_cegbr(cpu_env, tmp32_1, tmp); - break; - case 0xa5: - gen_helper_cdgbr(cpu_env, tmp32_1, tmp); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0xa6: /* CXGBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - gen_helper_cxgbr(cpu_env, tmp32_1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal b3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2144,6 +2098,31 @@ static ExitStatus op_cgxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cegb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cegb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cdgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cdgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cxgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); From 102bf2c63535122cba0d7917ed8cfb8cc1c7b14c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 07:39:11 -0700 Subject: [PATCH 085/149] target-s390: Convert FLOGR Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 8 +++++ target-s390x/cpu.h | 2 ++ target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 ++ target-s390x/int_helper.c | 22 ++----------- target-s390x/translate.c | 66 +++++++++++++++++++++----------------- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index f1038be1b5..e3bed16bd3 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -399,6 +399,11 @@ static uint32_t cc_calc_sla_64(uint64_t src, int shift) return 2; } +static uint32_t cc_calc_flogr(uint64_t dst) +{ + return dst ? 2 : 0; +} + static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) { @@ -504,6 +509,9 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_SLA_64: r = cc_calc_sla_64(src, dst); break; + case CC_OP_FLOGR: + r = cc_calc_flogr(dst); + break; case CC_OP_NZ_F32: r = set_cc_nz_f32(dst); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index f1d4dc67f4..dc7bbc67f6 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -478,6 +478,7 @@ enum cc_op { CC_OP_ICM, /* insert characters under mask */ CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ + CC_OP_FLOGR, /* find leftmost one */ CC_OP_MAX }; @@ -521,6 +522,7 @@ static const char *cc_names[] = { [CC_OP_ICM] = "CC_OP_ICM", [CC_OP_SLA_32] = "CC_OP_SLA_32", [CC_OP_SLA_64] = "CC_OP_SLA_64", + [CC_OP_FLOGR] = "CC_OP_FLOGR", }; static inline const char *cc_name(int cc_op) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index d9f630ecc3..e64b46d755 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -69,7 +69,7 @@ DEF_HELPER_4(msdb, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_3(flogr, i32, env, i32, i64) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_2(sqeb, i64, env, i64) DEF_HELPER_2(sqdb, i64, env, i64) DEF_HELPER_3(sqxb, i64, env, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index d5e1c5c1cd..771baafa37 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -220,6 +220,9 @@ /* EXTRACT FPC */ C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) +/* FIND LEFTMOST ONE */ + C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0) + /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 839c0e1500..dc16de206c 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -165,26 +165,10 @@ int64_t HELPER(nabs_i64)(int64_t val) } } -/* find leftmost one */ -uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) +/* count leading zeros, for find leftmost one */ +uint64_t HELPER(clz)(uint64_t v) { - uint64_t res = 0; - uint64_t ov2 = v2; - - while (!(v2 & 0x8000000000000000ULL) && v2) { - v2 <<= 1; - res++; - } - - if (!v2) { - env->regs[r1] = 64; - env->regs[r1 + 1] = 0; - return 0; - } else { - env->regs[r1] = res; - env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); - return 2; - } + return clz64(v); } uint64_t HELPER(cvd)(int32_t bin) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 47ccc6740a..e674c93ffe 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -620,6 +620,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_COMP_64: case CC_OP_NZ_F32: case CC_OP_NZ_F64: + case CC_OP_FLOGR: /* 1 argument */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; @@ -852,6 +853,20 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) account_inline_branch(s, old_cc_op); break; + case CC_OP_FLOGR: + switch (mask & 0xa) { + case 8: /* src == 0 -> no one bit found */ + cond = TCG_COND_EQ; + break; + case 2: /* src != 0 -> one bit found */ + cond = TCG_COND_NE; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + default: do_dynamic: /* Calculate cc value. */ @@ -888,6 +903,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_LTGT0_64: case CC_OP_NZ: + case CC_OP_FLOGR: c->u.s64.a = cc_dst; c->u.s64.b = tcg_const_i64(0); c->g1 = true; @@ -1414,29 +1430,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, #undef FP_HELPER } -static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, - int r2) -{ - TCGv_i64 tmp; - TCGv_i32 tmp32_1; - - LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); - switch (op) { - case 0x83: /* FLOGR R1,R2 [RRE] */ - tmp = load_reg(r2); - tmp32_1 = tcg_const_i32(r1); - gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; - default: - LOG_DISAS("illegal b9 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { unsigned char opc; @@ -1460,13 +1453,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) r2 = insn & 0xf; disas_b3(env, s, op, r3, r1, r2); break; - case 0xb9: - insn = ld_code4(env, s->pc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - op = (insn >> 16) & 0xff; - disas_b9(env, s, op, r1, r2); - break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); gen_illegal_opcode(s); @@ -2330,6 +2316,26 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_flogr(DisasContext *s, DisasOps *o) +{ + /* We'll use the original input for cc computation, since we get to + compare that against 0, which ought to be better than comparing + the real output against 64. It also lets cc_dst be a convenient + temporary during our computation. */ + gen_op_update1_cc_i64(s, CC_OP_FLOGR, o->in2); + + /* R1 = IN ? CLZ(IN) : 64. */ + gen_helper_clz(o->out, o->in2); + + /* R1+1 = IN & ~(found bit). Note that we may attempt to shift this + value by 64, which is undefined. But since the shift is 64 iff the + input is zero, we still get the correct result after and'ing. */ + tcg_gen_movi_i64(o->out2, 0x8000000000000000ull); + tcg_gen_shr_i64(o->out2, o->out2, o->out); + tcg_gen_andc_i64(o->out2, cc_dst, o->out2); + return NO_EXIT; +} + static ExitStatus op_icm(DisasContext *s, DisasOps *o) { int m3 = get_field(s->fields, m3); From 8379bfdbca195af9df1e6ecf67f04402bd80d471 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 07:44:43 -0700 Subject: [PATCH 086/149] target-s390: Convert LFPC, SFPC Note that we were failing to set the rounding mode in fpu_status. Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 17 ++++++++++ target-s390x/helper.h | 1 + target-s390x/insn-data.def | 6 ++++ target-s390x/translate.c | 64 +++++--------------------------------- 4 files changed, 31 insertions(+), 57 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index ac530e9700..74b94f290f 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -577,3 +577,20 @@ uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) handle_exceptions(env, GETPC()); return RET128(ret); } + +/* set fpc */ +void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) +{ + static const int rnd[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down + }; + + /* Install everything in the main FPC. */ + env->fpc = fpc; + + /* Install the rounding mode in the shadow fpu_status. */ + set_float_rounding_mode(rnd[fpc & 3], &env->fpu_status); +} diff --git a/target-s390x/helper.h b/target-s390x/helper.h index e64b46d755..3cc4cbdfaf 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -78,6 +78,7 @@ DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) DEF_HELPER_3(cksm, void, env, i32, i32) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) +DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i32, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 771baafa37..b319bebbee 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -351,6 +351,9 @@ C(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0) C(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0) +/* LOAD FPC */ + C(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0) + /* LOAD LENGTHENED */ C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) C(0xb305, LXDBR, RRE, Z, 0, f2_o, x1, 0, lxdb, 0) @@ -455,6 +458,9 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* SET FPC */ + C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) + /* SHIFT LEFT SINGLE */ D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) D(0xebdd, SLAK, RSY_a, DO, r3, sh32, new, r1_32, sla, 0, 31) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e674c93ffe..d4f1bc432c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1337,18 +1337,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x9d: /* LFPC D2(B2) [S] */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0xb1: /* STFL D2(B2) [S] */ /* Store Facility List (CPU features) at 200 */ check_privileged(s); @@ -1394,47 +1382,11 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, } } -static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, - int r1, int r2) -{ - TCGv_i32 tmp32_1; - LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); -#define FP_HELPER(i) \ - tmp32_1 = tcg_const_i32(r1); \ - tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i(cpu_env, tmp32_1, tmp32_2); \ - tcg_temp_free_i32(tmp32_1); \ - tcg_temp_free_i32(tmp32_2); - -#define FP_HELPER_CC(i) \ - tmp32_1 = tcg_const_i32(r1); \ - tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i(cc_op, cpu_env, tmp32_1, tmp32_2); \ - set_cc_static(s); \ - tcg_temp_free_i32(tmp32_1); \ - tcg_temp_free_i32(tmp32_2); - - switch (op) { - case 0x84: /* SFPC R1 [RRE] */ - tmp32_1 = load_reg32(r1); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i32(tmp32_1); - break; - default: - LOG_DISAS("illegal b3 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } - -#undef FP_HELPER_CC -#undef FP_HELPER -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { unsigned char opc; uint64_t insn; - int op, r1, r2, r3; + int op; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -1445,14 +1397,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b2(env, s, op, insn); break; - case 0xb3: - insn = ld_code4(env, s->pc); - op = (insn >> 16) & 0xff; - r3 = (insn >> 12) & 0xf; /* aka m3 */ - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - disas_b3(env, s, op, r3, r1, r2); - break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); gen_illegal_opcode(s); @@ -2981,6 +2925,12 @@ static ExitStatus op_srl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) +{ + gen_helper_sfpc(cpu_env, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { From 6e2704e74d317ba077b680c2fc881724686fb24a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:18:21 -0700 Subject: [PATCH 087/149] target-s390: Convert IPM Note that the previous placement of the PM field was incorrect. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 12 ------------ target-s390x/helper.h | 1 - target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 25 +++++++++++++++++++------ 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index e3bed16bd3..a6d60bf885 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -544,18 +544,6 @@ uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, return do_calc_cc(env, cc_op, src, dst, vr); } -/* insert psw mask and condition code into r1 */ -void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1) -{ - uint64_t r = env->regs[r1]; - - r &= 0xffffffff00ffffffULL; - r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); - env->regs[r1] = r; - HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, - cc, env->psw.mask, r); -} - #ifndef CONFIG_USER_ONLY void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 3cc4cbdfaf..633667827f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -25,7 +25,6 @@ DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) -DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b319bebbee..13b1771bc3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -237,6 +237,8 @@ D(0xa501, IIHL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1020) D(0xa502, IILH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1010) D(0xa503, IILL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1000) +/* INSERT PROGRAM MASK */ + C(0xb222, IPM, RRE, Z, 0, 0, r1, 0, ipm, 0) /* LOAD */ C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d4f1bc432c..702b174a10 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,12 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x22: /* IPM R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_ipm(cpu_env, cc_op, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x41: /* CKSM R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); @@ -2348,6 +2342,25 @@ static ExitStatus op_insi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ipm(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1; + + gen_op_calc_cc(s); + tcg_gen_andi_i64(o->out, o->out, ~0xff000000ull); + + t1 = tcg_temp_new_i64(); + tcg_gen_shli_i64(t1, psw_mask, 20); + tcg_gen_shri_i64(t1, t1, 36); + tcg_gen_or_i64(o->out, o->out, t1); + + tcg_gen_extu_i32_i64(t1, cc_op); + tcg_gen_shli_i64(t1, t1, 28); + tcg_gen_or_i64(o->out, o->out, t1); + tcg_temp_free_i64(t1); + return NO_EXIT; +} + static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) { gen_helper_ldeb(o->out, cpu_env, o->in2); From 374724f91ab236b4f60ec4796f1601720486d06b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 11:38:12 -0700 Subject: [PATCH 088/149] target-s390: Convert CKSM Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 +++ target-s390x/mem_helper.c | 43 ++++++++++++++++++++++---------------- target-s390x/translate.c | 31 +++++++++++++++++++-------- 4 files changed, 51 insertions(+), 28 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 633667827f..c6afcbc6b6 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -75,7 +75,7 @@ DEF_HELPER_3(sqxb, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) -DEF_HELPER_3(cksm, void, env, i32, i32) +DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 13b1771bc3..74f10323db 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -91,6 +91,9 @@ C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* CHECKSUM */ + C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) + /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 9c3ade816c..9c7815ad17 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -747,42 +747,49 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } /* checksum */ -void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, + uint64_t src, uint64_t src_len) { - uint64_t src = get_address_31fix(env, r2); - uint64_t src_len = env->regs[(r2 + 1) & 15]; - uint64_t cksm = (uint32_t)env->regs[r1]; + uint64_t max_len, len; + uint64_t cksm = (uint32_t)r1; - while (src_len >= 4) { - cksm += cpu_ldl_data(env, src); + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + max_len = (src_len > 0x2000 ? 0x2000 : src_len); - /* move to next word */ - src_len -= 4; - src += 4; + /* Process full words as available. */ + for (len = 0; len + 4 <= max_len; len += 4, src += 4) { + cksm += (uint32_t)cpu_ldl_data(env, src); } - switch (src_len) { - case 0: - break; + switch (max_len - len) { case 1: cksm += cpu_ldub_data(env, src) << 24; + len += 1; break; case 2: cksm += cpu_lduw_data(env, src) << 16; + len += 2; break; case 3: cksm += cpu_lduw_data(env, src) << 16; cksm += cpu_ldub_data(env, src + 2) << 8; + len += 3; break; } - /* indicate we've processed everything */ - env->regs[r2] = src + src_len; - env->regs[(r2 + 1) & 15] = 0; + /* Fold the carry from the checksum. Note that we can see carry-out + during folding more than once (but probably not more than twice). */ + while (cksm > 0xffffffffull) { + cksm = (uint32_t)cksm + (cksm >> 32); + } - /* store result */ - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - ((uint32_t)cksm + (cksm >> 32)); + /* Indicate whether or not we've processed everything. */ + env->cc_op = (len == src_len ? 0 : 3); + + /* Return both cksm and processed length. */ + env->retxl = cksm; + return len; } void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 702b174a10..ea2b1dc561 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,15 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x41: /* CKSM R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_cksm(cpu_env, tmp32_1, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - gen_op_movi_cc(s, 0); - break; case 0x4e: /* SAR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r1])); @@ -2047,6 +2038,23 @@ static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cksm(DisasContext *s, DisasOps *o) +{ + int r2 = get_field(s->fields, r2); + TCGv_i64 len = tcg_temp_new_i64(); + + potential_page_fault(s); + gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]); + set_cc_static(s); + return_low128(o->out); + + tcg_gen_add_i64(regs[r2], regs[r2], len); + tcg_gen_sub_i64(regs[r2 + 1], regs[r2 + 1], len); + tcg_temp_free_i64(len); + + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); @@ -3847,6 +3855,11 @@ static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = o->g_in2 = true; } +static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = get_address(s, 0, get_field(f, r2), 0); +} + static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; From d62a4c97f2cab0bd8649e3cd0b7692f989dbb577 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 11:54:04 -0700 Subject: [PATCH 089/149] target-s390: Convert EAR, SAR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 25 ++++++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 74f10323db..c4ce7e2332 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -220,6 +220,8 @@ /* EXECUTE RELATIVE LONG */ C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) +/* EXTRACT ACCESS */ + C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) /* EXTRACT FPC */ C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) @@ -463,6 +465,8 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* SET ACCESS */ + C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index ea2b1dc561..de9e2fe08f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,17 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x4e: /* SAR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r1])); - tcg_temp_free_i32(tmp32_1); - break; - case 0x4f: /* EAR R1,R2 [RRE] */ - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r2])); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x54: /* MVPG R1,R2 [RRE] */ tmp = load_reg(0); tmp2 = load_reg(r1); @@ -2230,6 +2219,13 @@ static ExitStatus op_dxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ear(DisasContext *s, DisasOps *o) +{ + int r2 = get_field(s->fields, r2); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, aregs[r2])); + return NO_EXIT; +} + static ExitStatus op_efpc(DisasContext *s, DisasOps *o) { tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); @@ -2864,6 +2860,13 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sar(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + tcg_gen_st32_i64(o->in2, cpu_env, offsetof(CPUS390XState, aregs[r1])); + return NO_EXIT; +} + static ExitStatus op_seb(DisasContext *s, DisasOps *o) { gen_helper_seb(o->out, cpu_env, o->in1, o->in2); From ee6c38d5b10fda25175fa85febde532a12456346 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:19:44 -0700 Subject: [PATCH 090/149] target-s390: Convert MVPG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 7 ++----- target-s390x/translate.c | 20 ++++++++------------ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c4ce7e2332..4223d35efa 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -394,6 +394,8 @@ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) /* MOVE LONG EXTENDED */ C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) +/* MOVE PAGE */ + C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 9c7815ad17..61c35a2c38 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -398,12 +398,9 @@ uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) { /* XXX missing r0 handling */ + env->cc_op = 0; #ifdef CONFIG_USER_ONLY - int i; - - for (i = 0; i < TARGET_PAGE_SIZE; i++) { - cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i)); - } + memmove(g2h(r1), g2h(r2), TARGET_PAGE_SIZE); #else mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); #endif diff --git a/target-s390x/translate.c b/target-s390x/translate.c index de9e2fe08f..d77b30f762 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,18 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x54: /* MVPG R1,R2 [RRE] */ - tmp = load_reg(0); - tmp2 = load_reg(r1); - tmp3 = load_reg(r2); - potential_page_fault(s); - gen_helper_mvpg(cpu_env, tmp, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - /* XXX check CCO bit and set CC accordingly */ - gen_op_movi_cc(s, 0); - break; case 0x55: /* MVST R1,R2 [RRE] */ tmp32_1 = load_reg32(0); tmp32_2 = tcg_const_i32(r1); @@ -2654,6 +2642,14 @@ static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_mvpg(cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From aa31bf60312157aefb09f887e2f750c7d59a8bbc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:20:53 -0700 Subject: [PATCH 091/149] target-s390: Convert CLST, MVST Signed-off-by: Richard Henderson --- target-s390x/helper.h | 4 +- target-s390x/insn-data.def | 4 ++ target-s390x/mem_helper.c | 119 ++++++++++++++++++------------------- target-s390x/translate.c | 42 ++++++------- 4 files changed, 83 insertions(+), 86 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c6afcbc6b6..999d5d0604 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -14,9 +14,9 @@ DEF_HELPER_3(divu32, i64, env, i64, i64) DEF_HELPER_3(divs64, s64, env, s64, s64) DEF_HELPER_4(divu64, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i32, env, i32, i32, i32) -DEF_HELPER_4(clst, i32, env, i32, i32, i32) +DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) -DEF_HELPER_4(mvst, void, env, i32, i32, i32) +DEF_HELPER_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_4(csg, i64, env, i64, i64, i64) DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) DEF_HELPER_4(cs, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4223d35efa..b485b85e9c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -153,6 +153,8 @@ C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) C(0xeb20, CLMH, RSY_b, Z, r1_sr32, a2, 0, 0, clm, 0) +/* COMPARE LOGICAL STRING */ + C(0xb25d, CLST, RRE, Z, r1_o, r2_o, 0, 0, clst, 0) /* COMPARE AND SWAP */ C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) @@ -396,6 +398,8 @@ C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) /* MOVE PAGE */ C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0) +/* MOVE STRING */ + C(0xb255, MVST, RRE, Z, r1_o, r2_o, 0, 0, mvst, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 61c35a2c38..7d87c746f6 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -304,36 +304,30 @@ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, return cc; } +static inline uint64_t fix_address(CPUS390XState *env, uint64_t a) +{ + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + a &= 0x7fffffff; + } + return a; +} + static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) { uint64_t r = d2; - if (x2) { r += env->regs[x2]; } - if (b2) { r += env->regs[b2]; } - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; + return fix_address(env, r); } static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) { - uint64_t r = env->regs[reg]; - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; + return fix_address(env, env->regs[reg]); } /* search string (c is byte to search, r2 is string, r1 end of string) */ @@ -359,39 +353,40 @@ uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) } /* unsigned string compare (c is string terminator) */ -uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) { - uint64_t s1 = get_address_31fix(env, r1); - uint64_t s2 = get_address_31fix(env, r2); - uint8_t v1, v2; - uint32_t cc; + uint32_t len; c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: comparing '%s' and '%s'\n", - __func__, (char *)g2h(s1), (char *)g2h(s2)); - } -#endif - for (;;) { - v1 = cpu_ldub_data(env, s1); - v2 = cpu_ldub_data(env, s2); - if ((v1 == c || v2 == c) || (v1 != v2)) { - break; + s1 = fix_address(env, s1); + s2 = fix_address(env, s2); + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + uint8_t v1 = cpu_ldub_data(env, s1 + len); + uint8_t v2 = cpu_ldub_data(env, s2 + len); + if (v1 == v2) { + if (v1 == c) { + /* Equal. CC=0, and don't advance the registers. */ + env->cc_op = 0; + env->retxl = s2; + return s1; + } + } else { + /* Unequal. CC={1,2}, and advance the registers. Note that + the terminator need not be zero, but the string that contains + the terminator is by definition "low". */ + env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2); + env->retxl = s2 + len; + return s1 + len; } - s1++; - s2++; } - if (v1 == v2) { - cc = 0; - } else { - cc = (v1 < v2) ? 1 : 2; - /* FIXME: 31-bit mode! */ - env->regs[r1] = s1; - env->regs[r2] = s2; - } - return cc; + /* CPU-determined bytes equal; advance the registers. */ + env->cc_op = 3; + env->retxl = s2 + len; + return s1 + len; } /* move page */ @@ -407,29 +402,31 @@ void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) } /* string copy (c is string terminator) */ -void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) { - uint64_t dest = get_address_31fix(env, r1); - uint64_t src = get_address_31fix(env, r2); - uint8_t v; + uint32_t len; c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), - dest); - } -#endif - for (;;) { - v = cpu_ldub_data(env, src); - cpu_stb_data(env, dest, v); + d = fix_address(env, d); + s = fix_address(env, s); + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + uint8_t v = cpu_ldub_data(env, s + len); + cpu_stb_data(env, d + len, v); if (v == c) { - break; + /* Complete. Set CC=1 and advance R1. */ + env->cc_op = 1; + env->retxl = s; + return d + len; } - src++; - dest++; } - env->regs[r1] = dest; /* FIXME: 31-bit mode! */ + + /* Incomplete. Set CC=3 and signal to advance R1 and R2. */ + env->cc_op = 3; + env->retxl = s + len; + return d + len; } /* compare and swap 64-bit */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d77b30f762..f1eb4bb8da 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -427,7 +427,7 @@ static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) return tmp; } -static void gen_op_movi_cc(DisasContext *s, uint32_t val) +static inline void gen_op_movi_cc(DisasContext *s, uint32_t val) { s->cc_op = CC_OP_CONST0 + val; } @@ -1034,28 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x55: /* MVST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_mvst(cpu_env, tmp32_1, tmp32_2, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - gen_op_movi_cc(s, 1); - break; - case 0x5d: /* CLST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_clst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x5e: /* SRST R1,R2 [RRE] */ tmp32_1 = load_reg32(0); tmp32_2 = tcg_const_i32(r1); @@ -2091,6 +2069,15 @@ static ExitStatus op_clm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + static ExitStatus op_cs(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); @@ -2650,6 +2637,15 @@ static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From 4600c994d93fc9af2b045086dd31e613d2f9d7bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 14:27:42 -0700 Subject: [PATCH 092/149] target-s390: Convert SRST Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 +++ target-s390x/mem_helper.c | 39 +++++++++++++++++++++++++------------- target-s390x/translate.c | 33 +++++++++++++++----------------- 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 999d5d0604..dd7479abcf 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -13,7 +13,7 @@ DEF_HELPER_3(divs32, s64, env, s64, s64) DEF_HELPER_3(divu32, i64, env, i64, i64) DEF_HELPER_3(divs64, s64, env, s64, s64) DEF_HELPER_4(divu64, i64, env, i64, i64, i64) -DEF_HELPER_4(srst, i32, env, i32, i32, i32) +DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) DEF_HELPER_4(mvst, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b485b85e9c..5e1f8fda9b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -471,6 +471,9 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* SEARCH STRING */ + C(0xb25e, SRST, RRE, Z, r1_o, r2_o, 0, 0, srst, 0) + /* SET ACCESS */ C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 7d87c746f6..59877eef96 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -331,25 +331,38 @@ static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) } /* search string (c is byte to search, r2 is string, r1 end of string) */ -uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, + uint64_t str) { - uint64_t i; - uint32_t cc = 2; - uint64_t str = get_address_31fix(env, r2); - uint64_t end = get_address_31fix(env, r1); + uint32_t len; + uint8_t v, c = r0; - HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, - c, env->regs[r1], env->regs[r2]); + str = fix_address(env, str); + end = fix_address(env, end); - for (i = str; i != end; i++) { - if (cpu_ldub_data(env, i) == c) { - env->regs[r1] = i; - cc = 1; - break; + /* Assume for now that R2 is unmodified. */ + env->retxl = str; + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + if (str + len == end) { + /* Character not found. R1 & R2 are unmodified. */ + env->cc_op = 2; + return end; + } + v = cpu_ldub_data(env, str + len); + if (v == c) { + /* Character found. Set R1 to the location; R2 is unmodified. */ + env->cc_op = 1; + return str + len; } } - return cc; + /* CPU-determined bytes processed. Advance R2 to next byte to process. */ + env->retxl = str + len; + env->cc_op = 3; + return end; } /* unsigned string compare (c is string terminator) */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f1eb4bb8da..bbbd5fe09a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1021,12 +1021,11 @@ static void free_compare(DisasCompare *c) static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { - TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; - int r1, r2; #ifndef CONFIG_USER_ONLY + TCGv_i64 tmp, tmp2, tmp3; + TCGv_i32 tmp32_1, tmp32_2; + int r1, r2; int r3, d2, b2; -#endif r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; @@ -1034,19 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x5e: /* SRST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_srst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - -#ifndef CONFIG_USER_ONLY case 0x02: /* STIDP D2(B2) [S] */ /* Store CPU ID */ check_privileged(s); @@ -1314,12 +1300,14 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; -#endif default: +#endif LOG_DISAS("illegal b2 operation 0x%x\n", op); gen_illegal_opcode(s); +#ifndef CONFIG_USER_ONLY break; } +#endif } static void disas_s390_insn(CPUS390XState *env, DisasContext *s) @@ -3136,6 +3124,15 @@ static ExitStatus op_stmh(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_srst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_srst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); From 71bd666963ad9fb004d7aa919b7222165e602173 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:21:47 -0700 Subject: [PATCH 093/149] target-s390: Convert STIDP Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 6 ------ target-s390x/translate.c | 16 +++++++--------- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index dd7479abcf..8e90741d3f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -83,7 +83,6 @@ DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) -DEF_HELPER_FLAGS_2(stidp, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) DEF_HELPER_2(stck, i32, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 5e1f8fda9b..4d9ecf4b13 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -640,6 +640,8 @@ /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) +/* STORE CPU ID */ + C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 6dca0ebabd..009cc92660 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -131,12 +131,6 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, return r; } -/* Store CPU ID */ -void HELPER(stidp)(CPUS390XState *env, uint64_t a1) -{ - cpu_stq_data(env, a1, env->cpu_num); -} - /* Set Prefix */ void HELPER(spx)(CPUS390XState *env, uint64_t a1) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index bbbd5fe09a..d57c737fc8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x02: /* STIDP D2(B2) [S] */ - /* Store CPU ID */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stidp(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; case 0x04: /* SCK D2(B2) [S] */ /* Set Clock */ check_privileged(s); @@ -2967,6 +2958,13 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stidp(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From 352897995147c4a054679654048f5c128ca32743 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:20:49 -0700 Subject: [PATCH 094/149] target-s390: Convert SCK Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 3 +++ target-s390x/misc_helper.c | 8 -------- target-s390x/translate.c | 10 ---------- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 8e90741d3f..3591a92ada 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -84,7 +84,6 @@ DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) DEF_HELPER_2(stck, i32, env, i64) DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4d9ecf4b13..824e9dc526 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -633,6 +633,9 @@ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +/* SET CLOCK */ + /* ??? Not implemented - is it necessary? */ + C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 009cc92660..c16359134a 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -143,14 +143,6 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) tlb_flush_page(env, TARGET_PAGE_SIZE); } -/* Set Clock */ -uint32_t HELPER(sck)(uint64_t a1) -{ - /* XXX not implemented - is it necessary? */ - - return 0; -} - static inline uint64_t clock_value(CPUS390XState *env) { uint64_t time; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d57c737fc8..e835df0ce9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,16 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x04: /* SCK D2(B2) [S] */ - /* Set Clock */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sck(cc_op, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; case 0x05: /* STCK D2(B2) [S] */ /* Store Clock */ decode_rs(s, insn, &r1, &r3, &b2, &d2); From 434c91a5f4ed7219819678315b5529fbc35435e6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:31:07 -0700 Subject: [PATCH 095/149] target-s390: Convert STCK Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 +++ target-s390x/misc_helper.c | 6 ++---- target-s390x/translate.c | 17 ++++++++--------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 3591a92ada..d3a30cb4a0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -84,7 +84,7 @@ DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_2(stck, i32, env, i64) +DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(stckc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 824e9dc526..4404791661 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -640,6 +640,9 @@ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) +/* STORE CLOCK */ + C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) + C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index c16359134a..f1edf6c67b 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -154,11 +154,9 @@ static inline uint64_t clock_value(CPUS390XState *env) } /* Store Clock */ -uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stck)(CPUS390XState *env) { - cpu_stq_data(env, a1, clock_value(env)); - - return 0; + return clock_value(env); } /* Store Clock Extended */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e835df0ce9..624ee8d99a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x05: /* STCK D2(B2) [S] */ - /* Store Clock */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stck(cc_op, cpu_env, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; case 0x06: /* SCKC D2(B2) [S] */ /* Set Clock Comparator */ check_privileged(s); @@ -2924,6 +2915,14 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stck(DisasContext *s, DisasOps *o) +{ + gen_helper_stck(o->out, cpu_env); + /* ??? We don't implement clock states. */ + gen_op_movi_cc(s, 0); + return NO_EXIT; +} + static ExitStatus op_stctg(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From dd3eb7b54f0dbcf76e3ccfdf8535201049670378 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:36:58 -0700 Subject: [PATCH 096/149] target-s390: Convert SCKC, STCKC Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 4 ++++ target-s390x/misc_helper.c | 8 +++----- target-s390x/translate.c | 32 ++++++++++++++------------------ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index d3a30cb4a0..a55aa9f4d7 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -87,7 +87,7 @@ DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_2(stckc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(stpt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_4(stsi, i32, env, i64, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4404791661..06c780ba21 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -636,6 +636,8 @@ /* SET CLOCK */ /* ??? Not implemented - is it necessary? */ C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) +/* SET CLOCK COMPARATOR */ + C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ @@ -643,6 +645,8 @@ /* STORE CLOCK */ C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) +/* STORE CLOCK COMPARATOR */ + C(0xb207, STCKC, S, Z, la2, 0, new, m1_64, stckc, 0) /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index f1edf6c67b..9263ae727f 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -174,10 +174,8 @@ uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) } /* Set Clock Comparator */ -void HELPER(sckc)(CPUS390XState *env, uint64_t a1) +void HELPER(sckc)(CPUS390XState *env, uint64_t time) { - uint64_t time = cpu_ldq_data(env, a1); - if (time == -1ULL) { return; } @@ -191,10 +189,10 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t a1) } /* Store Clock Comparator */ -void HELPER(stckc)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stckc)(CPUS390XState *env) { /* XXX implement */ - cpu_stq_data(env, a1, 0); + return 0; } /* Set CPU Timer */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 624ee8d99a..30c7acec22 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,24 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x06: /* SCKC D2(B2) [S] */ - /* Set Clock Comparator */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sckc(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x07: /* STCKC D2(B2) [S] */ - /* Store Clock Comparator */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stckc(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; case 0x08: /* SPT D2(B2) [S] */ /* Set CPU Timer */ check_privileged(s); @@ -2923,6 +2905,20 @@ static ExitStatus op_stck(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sckc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sckc(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stckc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stckc(o->out, cpu_env); + return NO_EXIT; +} + static ExitStatus op_stctg(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From c4f0a863c3b980694e2ccb8fa3252a0eb8ef6a97 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:47:26 -0700 Subject: [PATCH 097/149] target-s390: Convert SPT, STPT Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 4 ++++ target-s390x/misc_helper.c | 8 +++----- target-s390x/translate.c | 32 ++++++++++++++------------------ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index a55aa9f4d7..d7736e3aa1 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -89,7 +89,7 @@ DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_2(stpt, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_4(stsi, i32, env, i64, i32, i32) DEF_HELPER_4(lctl, void, env, i32, i64, i32) DEF_HELPER_4(lctlg, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 06c780ba21..a45454c4b9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -638,6 +638,8 @@ C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) /* SET CLOCK COMPARATOR */ C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) +/* SET CPU TIMER */ + C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ @@ -652,6 +654,8 @@ C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) /* STORE CPU ID */ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) +/* STORE CPU TIMER */ + C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 9263ae727f..431824249c 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -196,10 +196,8 @@ uint64_t HELPER(stckc)(CPUS390XState *env) } /* Set CPU Timer */ -void HELPER(spt)(CPUS390XState *env, uint64_t a1) +void HELPER(spt)(CPUS390XState *env, uint64_t time) { - uint64_t time = cpu_ldq_data(env, a1); - if (time == -1ULL) { return; } @@ -211,10 +209,10 @@ void HELPER(spt)(CPUS390XState *env, uint64_t a1) } /* Store CPU Timer */ -void HELPER(stpt)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stpt)(CPUS390XState *env) { /* XXX implement */ - cpu_stq_data(env, a1, 0); + return 0; } /* Store System Information */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 30c7acec22..a31849253b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,24 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x08: /* SPT D2(B2) [S] */ - /* Set CPU Timer */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_spt(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x09: /* STPT D2(B2) [S] */ - /* Store CPU Timer */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stpt(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; case 0x0a: /* SPKA D2(B2) [S] */ /* Set PSW Key from Address */ check_privileged(s); @@ -2950,6 +2932,20 @@ static ExitStatus op_stidp(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_spt(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_spt(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stpt(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stpt(o->out, cpu_env); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From 28d555566719dada8e2d028ff611b4fb8a984e0c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:55:34 -0700 Subject: [PATCH 098/149] target-s390: Convert SPKA Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 20 ++++++++------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a45454c4b9..f95ba11b3a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -640,6 +640,8 @@ C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) /* SET CPU TIMER */ C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) +/* SET PSW KEY FROM ADDRESS */ + C(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a31849253b..6296113dca 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x0a: /* SPKA D2(B2) [S] */ - /* Set PSW Key from Address */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_andi_i64(tmp2, psw_mask, ~PSW_MASK_KEY); - tcg_gen_shli_i64(tmp, tmp, PSW_SHIFT_KEY - 4); - tcg_gen_or_i64(psw_mask, tmp2, tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; case 0x0d: /* PTLB [S] */ /* Purge TLB */ check_privileged(s); @@ -2872,6 +2860,14 @@ static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_spka(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_shri_i64(o->in2, o->in2, 4); + tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, PSW_SHIFT_KEY - 4, 4); + return NO_EXIT; +} + static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { check_privileged(s); From 0568d8aab0b48cb033aad8ecaef5bc0c531ce9ff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:59:26 -0700 Subject: [PATCH 099/149] target-s390: Convert PTLB Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f95ba11b3a..e9b9dc1038 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -629,6 +629,8 @@ C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) /* MOVE TO SECONDARY */ C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) +/* PURGE TLB */ + C(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6296113dca..563c2e79af 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,11 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x0d: /* PTLB [S] */ - /* Purge TLB */ - check_privileged(s); - gen_helper_ptlb(cpu_env); - break; case 0x10: /* SPX D2(B2) [S] */ /* Set Prefix Register */ check_privileged(s); @@ -2725,6 +2720,15 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_ptlb(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_ptlb(cpu_env); + return NO_EXIT; +} +#endif + static ExitStatus op_rev16(DisasContext *s, DisasOps *o) { tcg_gen_bswap16_i64(o->out, o->in2); From e805a0d39e26fc85681db7e1bf58c91a5628eaff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 16:11:32 -0700 Subject: [PATCH 100/149] target-s390: Convert SPX, STPX Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/misc_helper.c | 6 ++---- target-s390x/translate.c | 35 +++++++++++++++-------------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e9b9dc1038..87a77a2ad0 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -642,6 +642,8 @@ C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) /* SET CPU TIMER */ C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) +/* SET PREFIX */ + C(0xb210, SPX, S, Z, 0, m2_32u, 0, 0, spx, 0) /* SET PSW KEY FROM ADDRESS */ C(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0) /* SET SYSTEM MASK */ @@ -660,6 +662,8 @@ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE CPU TIMER */ C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) +/* STORE PREFIX */ + C(0xb211, STPX, S, Z, la2, 0, new, m1_32, stpx, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 431824249c..b098e8869d 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -134,10 +134,8 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, /* Set Prefix */ void HELPER(spx)(CPUS390XState *env, uint64_t a1) { - uint32_t prefix; - - prefix = cpu_ldl_data(env, a1); - env->psa = prefix & 0xfffff000; + uint32_t prefix = a1 & 0x7fffe000; + env->psa = prefix; qemu_log("prefix: %#x\n", prefix); tlb_flush_page(env, 0); tlb_flush_page(env, TARGET_PAGE_SIZE); diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 563c2e79af..e355de26ce 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,26 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x10: /* SPX D2(B2) [S] */ - /* Set Prefix Register */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_spx(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x11: /* STPX D2(B2) [S] */ - /* Store Prefix */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp2, cpu_env, offsetof(CPUS390XState, psa)); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x12: /* STAP D2(B2) [S] */ /* Store CPU Address */ check_privileged(s); @@ -2946,6 +2926,21 @@ static ExitStatus op_stpt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_spx(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_spx(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stpx(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, psa)); + tcg_gen_andi_i64(o->out, o->out, 0x7fffe000); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From 411fea3d8400af5479690d6e22c6492c15e10a4a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 16:18:33 -0700 Subject: [PATCH 101/149] target-s390: Convert STAP Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 24 ++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 87a77a2ad0..f68e586e0d 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -658,6 +658,8 @@ /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) +/* STORE CPU ADDRESS */ + C(0xb212, STAP, S, Z, la2, 0, new, m1_16, stap, 0) /* STORE CPU ID */ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE CPU TIMER */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e355de26ce..5ffbdb3b61 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,20 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x12: /* STAP D2(B2) [S] */ - /* Store CPU Address */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, cpu_num)); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x21: /* IPTE R1,R2 [RRE] */ /* Invalidate PTE */ check_privileged(s); @@ -2859,6 +2845,16 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stap(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* ??? Surely cpu address != cpu number. In any case the previous + version of this stored more than the required half-word, so it + is unlikely this has ever been tested. */ + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + return NO_EXIT; +} + static ExitStatus op_stck(DisasContext *s, DisasOps *o) { gen_helper_stck(o->out, cpu_env); From cfef53e356119bddcba0724c0c26fd5940f231e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 16:25:28 -0700 Subject: [PATCH 102/149] target-s390: Convert IPTE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 20 +++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f68e586e0d..c8368cf151 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -616,6 +616,8 @@ #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) +/* INVALIDATE PAGE TABLE ENTRY */ + C(0xb221, IPTE, RRF_a, Z, r1_o, r2_o, 0, 0, ipte, 0) /* LOAD CONTROL */ C(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0) C(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5ffbdb3b61..b25a5e6549 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,17 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x21: /* IPTE R1,R2 [RRE] */ - /* Invalidate PTE */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp = load_reg(r1); - tmp2 = load_reg(r2); - gen_helper_ipte(cpu_env, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x29: /* ISKE R1,R2 [RRE] */ /* Insert Storage Key Extended */ check_privileged(s); @@ -2213,6 +2202,15 @@ static ExitStatus op_ipm(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_ipte(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_ipte(cpu_env, o->in1, o->in2); + return NO_EXIT; +} +#endif + static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) { gen_helper_ldeb(o->out, cpu_env, o->in2); From 8026417c7169e7efd1696f3ed15e51306729176a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:13:38 -0700 Subject: [PATCH 103/149] target-s390: Convert ISKE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 19 +++++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c8368cf151..87daec1a79 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -616,6 +616,8 @@ #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) +/* INSERT STORAGE KEY EXTENDED */ + C(0xb229, ISKE, RRE, Z, 0, r2_o, new, r1_8, iske, 0) /* INVALIDATE PAGE TABLE ENTRY */ C(0xb221, IPTE, RRF_a, Z, r1_o, r2_o, 0, 0, ipte, 0) /* LOAD CONTROL */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b25a5e6549..b9647d8833 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x29: /* ISKE R1,R2 [RRE] */ - /* Insert Storage Key Extended */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp = load_reg(r2); - tmp2 = tcg_temp_new_i64(); - gen_helper_iske(tmp2, cpu_env, tmp); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x2a: /* RRBE R1,R2 [RRE] */ /* Set Storage Key Extended */ check_privileged(s); @@ -2209,6 +2197,13 @@ static ExitStatus op_ipte(DisasContext *s, DisasOps *o) gen_helper_ipte(cpu_env, o->in1, o->in2); return NO_EXIT; } + +static ExitStatus op_iske(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_iske(o->out, cpu_env, o->in2); + return NO_EXIT; +} #endif static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) From 2bbde27f2548cb48f362eada1080e590f5453404 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:18:01 -0700 Subject: [PATCH 104/149] target-s390: Convert SSKE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 2 +- target-s390x/translate.c | 18 +++++++----------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index d7736e3aa1..9ff0c36aa5 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -97,7 +97,7 @@ DEF_HELPER_4(stctl, void, env, i32, i64, i32) DEF_HELPER_4(stctg, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) -DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i32, i64) +DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_NO_RWG, i32, env, i32, i64) DEF_HELPER_3(csp, i32, env, i32, i32) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 87daec1a79..f554c1b567 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -650,6 +650,8 @@ C(0xb210, SPX, S, Z, 0, m2_32u, 0, 0, spx, 0) /* SET PSW KEY FROM ADDRESS */ C(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0) +/* SET STORAGE KEY EXTENDED */ + C(0xb22b, SSKE, RRF_c, Z, r1_o, r2_o, 0, 0, sske, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 59877eef96..099724174a 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -946,7 +946,7 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) } /* set storage key extended */ -void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2) +void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) { uint64_t addr = get_address(env, 0, 0, r2); diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b9647d8833..2b07a8ecf6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1045,17 +1045,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x2b: /* SSKE R1,R2 [RRE] */ - /* Set Storage Key Extended */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - gen_helper_sske(cpu_env, tmp32_1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x34: /* STCH ? */ /* Store Subchannel */ check_privileged(s); @@ -2831,6 +2820,13 @@ static ExitStatus op_spka(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sske(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sske(cpu_env, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { check_privileged(s); From 5cc69c54f606005ea0432d83dafbec0f5b0e831a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:22:13 -0700 Subject: [PATCH 105/149] target-s390: Convert RRBE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 2 +- target-s390x/translate.c | 22 ++++++++++------------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 9ff0c36aa5..9bcf4d6b85 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -98,7 +98,7 @@ DEF_HELPER_4(stctg, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_NO_RWG, i32, env, i32, i64) +DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) DEF_HELPER_3(csp, i32, env, i32, i32) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f554c1b567..2a045727ae 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -635,6 +635,8 @@ C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) /* PURGE TLB */ C(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0) +/* RESET REFERENCE BIT EXTENDED */ + C(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 099724174a..406ec9b69d 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -958,7 +958,7 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) } /* reset reference bit extended */ -uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2) +uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) { uint8_t re; uint8_t key; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2b07a8ecf6..d7d991c58a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x2a: /* RRBE R1,R2 [RRE] */ - /* Set Storage Key Extended */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x34: /* STCH ? */ /* Store Subchannel */ check_privileged(s); @@ -2716,6 +2704,16 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_rrbe(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_rrbe(cc_op, cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_sar(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); From 2c423fc070b3e260fc368e2573c76d7ddd52e165 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:36:20 -0700 Subject: [PATCH 106/149] target-s390: Convert subchannel instructions While we're at it, list all of the chapter 14 subchannel insns. Which is easy since all merely need indicate non-operation. Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 14 ++++++++++++++ target-s390x/translate.c | 18 ++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2a045727ae..24a419c416 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -680,4 +680,18 @@ C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* TEST PROTECTION */ C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) + +/* I/O Instructions. For each we simply indicate non-operation. */ + C(0xb276, XSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb230, CSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb231, HSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb232, MSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb23b, RCHP, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb238, RSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb233, SSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb234, STSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb235, TSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + /* ??? Not listed in PoO ninth edition, but there's a linux driver that + uses it: "A CHSC subchannel is usually present on LPAR only." */ + C(0xb25f, CHSC, S, Z, 0, 0, 0, 0, subchannel, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d7d991c58a..1172031465 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,11 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x34: /* STCH ? */ - /* Store Subchannel */ - check_privileged(s); - gen_op_movi_cc(s, 3); - break; case 0x46: /* STURA R1,R2 [RRE] */ /* Store Using Real Address */ check_privileged(s); @@ -1062,11 +1057,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5f: /* CHSC ? */ - /* Channel Subsystem Call */ - check_privileged(s); - gen_op_movi_cc(s, 3); - break; case 0x78: /* STCKE D2(B2) [S] */ /* Store Clock Extended */ decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2916,6 +2906,14 @@ static ExitStatus op_spx(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_subchannel(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* Not operational. */ + gen_op_movi_cc(s, 3); + return NO_EXIT; +} + static ExitStatus op_stpx(DisasContext *s, DisasOps *o) { check_privileged(s); From 204504e2fa0ec0f11c806ad335edf6bd1f499e34 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:45:38 -0700 Subject: [PATCH 107/149] target-s390: Convert STURA Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 4 ++-- target-s390x/translate.c | 20 ++++++++------------ 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 9bcf4d6b85..4597b58f59 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -107,7 +107,7 @@ DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) -DEF_HELPER_3(stura, void, env, i64, i32) +DEF_HELPER_3(stura, void, env, i64, i64) #endif #include "exec/def-helper.h" diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 24a419c416..8e457cb9f2 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -678,6 +678,8 @@ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* STORE USING REAL ADDRESS */ + C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0) /* TEST PROTECTION */ C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 406ec9b69d..8987bbb9b1 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1093,9 +1093,9 @@ void HELPER(ptlb)(CPUS390XState *env) } /* store using real address */ -void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) +void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) { - stw_phys(get_address(env, 0, 0, addr), v1); + stw_phys(get_address(env, 0, 0, addr), (uint32_t)v1); } /* load real address */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1172031465..8079c6fc3d 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x46: /* STURA R1,R2 [RRE] */ - /* Store Using Real Address */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - potential_page_fault(s); - gen_helper_stura(cpu_env, tmp, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x50: /* CSP R1,R2 [RRE] */ /* Compare And Swap And Purge */ check_privileged(s); @@ -2945,6 +2933,14 @@ static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) } return NO_EXIT; } + +static ExitStatus op_stura(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_stura(cpu_env, o->in2, o->in1); + return NO_EXIT; +} #endif static ExitStatus op_st8(DisasContext *s, DisasOps *o) From 3d596f491250d66fffabbc60d0621ea72859e96c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:57:18 -0700 Subject: [PATCH 108/149] target-s390: Convert CSP Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 6 +++--- target-s390x/translate.c | 24 ++++++++++++------------ 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 4597b58f59..c359377b62 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -99,7 +99,7 @@ DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) -DEF_HELPER_3(csp, i32, env, i32, i32) +DEF_HELPER_3(csp, i32, env, i32, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8e457cb9f2..12468a3ef5 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -614,6 +614,8 @@ C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) #ifndef CONFIG_USER_ONLY +/* COMPARE AND SWAP AND PURGE */ + C(0xb250, CSP, RRE, Z, 0, ra2, 0, 0, csp, 0) /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* INSERT STORAGE KEY EXTENDED */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 8987bbb9b1..0e9bbd4035 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -984,16 +984,16 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) } /* compare and swap and purge */ -uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2) { uint32_t cc; uint32_t o1 = env->regs[r1]; - uint64_t a2 = get_address_31fix(env, r2) & ~3ULL; + uint64_t a2 = r2 & ~3ULL; uint32_t o2 = cpu_ldl_data(env, a2); if (o1 == o2) { cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]); - if (env->regs[r2] & 0x3) { + if (r2 & 0x3) { /* flush TLB / ALB */ tlb_flush(env, 1); } diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8079c6fc3d..19781edb92 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x50: /* CSP R1,R2 [RRE] */ - /* Compare And Swap And Purge */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x78: /* STCKE D2(B2) [S] */ /* Store Clock Extended */ decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -1901,6 +1889,18 @@ static ExitStatus op_csg(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_csp(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + check_privileged(s); + gen_helper_csp(cc_op, cpu_env, r1, o->in2); + tcg_temp_free_i32(r1); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_cds(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); From 39a5003c89191a46ec6af722ade3dfdf457e9f58 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:11:36 -0700 Subject: [PATCH 109/149] target-s390: Convert STCKE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 14 -------------- target-s390x/translate.c | 31 ++++++++++++++++++++++--------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c359377b62..3d7472eba0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -85,7 +85,6 @@ DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) -DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 12468a3ef5..75729fee64 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -663,6 +663,8 @@ /* STORE CLOCK */ C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) +/* STORE CLOCK EXTENDED */ + C(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0) /* STORE CLOCK COMPARATOR */ C(0xb207, STCKC, S, Z, la2, 0, new, m1_64, stckc, 0) /* STORE CONTROL */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index b098e8869d..409df4f7f8 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -157,20 +157,6 @@ uint64_t HELPER(stck)(CPUS390XState *env) return clock_value(env); } -/* Store Clock Extended */ -uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) -{ - cpu_stb_data(env, a1, 0); - /* basically the same value as stck */ - cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num); - /* more fine grained than stck */ - cpu_stq_data(env, a1 + 9, 0); - /* XXX programmable fields */ - cpu_stw_data(env, a1 + 17, 0); - - return 0; -} - /* Set Clock Comparator */ void HELPER(sckc)(CPUS390XState *env, uint64_t time) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 19781edb92..e5c3ee6dd7 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x78: /* STCKE D2(B2) [S] */ - /* Store Clock Extended */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stcke(cc_op, cpu_env, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; case 0x79: /* SACF D2(B2) [S] */ /* Set Address Space Control Fast */ check_privileged(s); @@ -2828,6 +2819,28 @@ static ExitStatus op_stck(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stcke(DisasContext *s, DisasOps *o) +{ + TCGv_i64 c1 = tcg_temp_new_i64(); + TCGv_i64 c2 = tcg_temp_new_i64(); + gen_helper_stck(c1, cpu_env); + /* Shift the 64-bit value into its place as a zero-extended + 104-bit value. Note that "bit positions 64-103 are always + non-zero so that they compare differently to STCK"; we set + the least significant bit to 1. */ + tcg_gen_shli_i64(c2, c1, 56); + tcg_gen_shri_i64(c1, c1, 8); + tcg_gen_ori_i64(c2, c2, 0x10000); + tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 8); + tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s)); + tcg_temp_free_i64(c1); + tcg_temp_free_i64(c2); + /* ??? We don't implement clock states. */ + gen_op_movi_cc(s, 0); + return NO_EXIT; +} + static ExitStatus op_sckc(DisasContext *s, DisasOps *o) { check_privileged(s); From 14244b21a041161185bb53c3eb29e3d8dc7bfe6e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:17:16 -0700 Subject: [PATCH 110/149] target-s390: Convert SACF Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 21 ++++++++------------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 75729fee64..a389f1503e 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -643,6 +643,8 @@ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +/* SET ADDRESS SPACE CONTROL FAST */ + C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) /* SET CLOCK */ /* ??? Not implemented - is it necessary? */ C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e5c3ee6dd7..491f8fd6b6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,19 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x79: /* SACF D2(B2) [S] */ - /* Set Address Space Control Fast */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sacf(cpu_env, tmp); - tcg_temp_free_i64(tmp); - /* addressing mode has changed, so end the block */ - s->pc = s->next_pc; - update_psw_addr(s); - s->is_jmp = DISAS_JUMP; - break; case 0x7d: /* STSI D2,(B2) [S] */ check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2681,6 +2668,14 @@ static ExitStatus op_rrbe(DisasContext *s, DisasOps *o) set_cc_static(s); return NO_EXIT; } + +static ExitStatus op_sacf(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sacf(cpu_env, o->in2); + /* Addressing mode has changed, so end the block. */ + return EXIT_PC_STALE; +} #endif static ExitStatus op_sar(DisasContext *s, DisasOps *o) From d14b3e09b21a297fddc62c0c7839156022079d05 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:43:38 -0700 Subject: [PATCH 111/149] target-s390: Convert STSI Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 4 ++-- target-s390x/translate.c | 24 ++++++++++-------------- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 3d7472eba0..f2eaef45fa 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -89,7 +89,7 @@ DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) -DEF_HELPER_4(stsi, i32, env, i64, i32, i32) +DEF_HELPER_4(stsi, i32, env, i64, i64, i64) DEF_HELPER_4(lctl, void, env, i32, i64, i32) DEF_HELPER_4(lctlg, void, env, i32, i64, i32) DEF_HELPER_4(stctl, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a389f1503e..5de3256be9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -680,6 +680,8 @@ C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) /* STORE PREFIX */ C(0xb211, STPX, S, Z, la2, 0, new, m1_32, stpx, 0) +/* STORE SYSTEM INFORMATION */ + C(0xb27d, STSI, S, Z, 0, a2, 0, 0, stsi, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 409df4f7f8..60e6538fbf 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -200,8 +200,8 @@ uint64_t HELPER(stpt)(CPUS390XState *env) } /* Store System Information */ -uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0, - uint32_t r1) +uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, + uint64_t r0, uint64_t r1) { int cc = 0; int sel1, sel2; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 491f8fd6b6..6f1f799d2d 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1023,7 +1023,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, { #ifndef CONFIG_USER_ONLY TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2; + TCGv_i32 tmp32_1; int r1, r2; int r3, d2, b2; @@ -1033,19 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x7d: /* STSI D2,(B2) [S] */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(0); - tmp32_2 = load_reg32(1); - potential_page_fault(s); - gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xb1: /* STFL D2(B2) [S] */ /* Store Facility List (CPU features) at 200 */ check_privileged(s); @@ -2895,6 +2882,15 @@ static ExitStatus op_stpt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stsi(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_spx(DisasContext *s, DisasOps *o) { check_privileged(s); From fc778b55a5ae45abac2a94d591e7490622917872 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:58:59 -0700 Subject: [PATCH 112/149] target-s390: Convert STFL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 5de3256be9..ba070f1725 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -678,6 +678,8 @@ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE CPU TIMER */ C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) +/* STORE FACILITY LIST */ + C(0xb2b1, STFL, S, Z, 0, 0, 0, 0, stfl, 0) /* STORE PREFIX */ C(0xb211, STPX, S, Z, la2, 0, new, m1_32, stpx, 0) /* STORE SYSTEM INFORMATION */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6f1f799d2d..b5cc573b6e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0xb1: /* STFL D2(B2) [S] */ - /* Store Facility List (CPU features) at 200 */ - check_privileged(s); - tmp2 = tcg_const_i64(0xc0000000); - tmp = tcg_const_i64(200); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; case 0xb2: /* LPSWE D2(B2) [S] */ /* Load PSW Extended */ check_privileged(s); @@ -2875,6 +2866,20 @@ static ExitStatus op_spt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stfl(DisasContext *s, DisasOps *o) +{ + TCGv_i64 f, a; + /* We really ought to have more complete indication of facilities + that we implement. Address this when STFLE is implemented. */ + check_privileged(s); + f = tcg_const_i64(0xc0000000); + a = tcg_const_i64(200); + tcg_gen_qemu_st32(f, a, get_mem_index(s)); + tcg_temp_free_i64(f); + tcg_temp_free_i64(a); + return NO_EXIT; +} + static ExitStatus op_stpt(DisasContext *s, DisasOps *o) { check_privileged(s); From 7ab938d706b515cfe4680a823525693124e2047d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 11:04:48 -0700 Subject: [PATCH 113/149] target-s390: Convert LPSWE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 37 ++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ba070f1725..b0cf90880a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -627,6 +627,8 @@ C(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) +/* LOAD PSW EXTENDED */ + C(0xb2b2, LPSWE, S, Z, 0, a2, 0, 0, lpswe, 0) /* LOAD REAL ADDRESS */ C(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0) C(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b5cc573b6e..5472dfc1c4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1022,10 +1022,9 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { #ifndef CONFIG_USER_ONLY - TCGv_i64 tmp, tmp2, tmp3; + TCGv_i64 tmp; TCGv_i32 tmp32_1; int r1, r2; - int r3, d2, b2; r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; @@ -1033,23 +1032,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0xb2: /* LPSWE D2(B2) [S] */ - /* Load PSW Extended */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); - tcg_gen_addi_i64(tmp, tmp, 8); - tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(cpu_env, tmp2, tmp3); - /* we need to keep cc_op intact */ - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x20: /* SERVC R1,R2 [RRE] */ /* SCLP Service call (PV hypercall) */ check_privileged(s); @@ -2254,6 +2236,23 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) tcg_temp_free_i64(t2); return EXIT_NORETURN; } + +static ExitStatus op_lpswe(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1, t2; + + check_privileged(s); + + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 8); + tcg_gen_qemu_ld64(t2, o->in2, get_mem_index(s)); + gen_helper_load_psw(cpu_env, t1, t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return EXIT_NORETURN; +} #endif static ExitStatus op_lam(DisasContext *s, DisasOps *o) From dc458df91d00986885fe12ed25876aa6d0604cee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 11:12:40 -0700 Subject: [PATCH 114/149] target-s390: Convert SERVC Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 6 ++---- target-s390x/translate.c | 29 +++++++++-------------------- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index f2eaef45fa..5d8a82175c 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -80,7 +80,7 @@ DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) #ifndef CONFIG_USER_ONLY -DEF_HELPER_3(servc, i32, env, i32, i64) +DEF_HELPER_3(servc, i32, env, i64, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b0cf90880a..cd773d0168 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -641,6 +641,8 @@ C(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0) /* RESET REFERENCE BIT EXTENDED */ C(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0) +/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */ + C(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 60e6538fbf..3015bfe3f2 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -88,11 +88,9 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) } /* SCLP service call */ -uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2) +uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) { - int r; - - r = sclp_service_call(r1, r2); + int r = sclp_service_call(r1, r2); if (r < 0) { program_interrupt(env, -r, 4); return 0; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5472dfc1c4..b4b197bb44 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1022,27 +1022,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { #ifndef CONFIG_USER_ONLY - TCGv_i64 tmp; - TCGv_i32 tmp32_1; - int r1, r2; - - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - - LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); - switch (op) { - case 0x20: /* SERVC R1,R2 [RRE] */ - /* SCLP Service call (PV hypercall) */ - check_privileged(s); - potential_page_fault(s); - tmp32_1 = load_reg32(r2); - tmp = load_reg(r1); - gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; default: #endif LOG_DISAS("illegal b2 operation 0x%x\n", op); @@ -2701,6 +2681,15 @@ static ExitStatus op_sqxb(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_servc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_servc(cc_op, cpu_env, o->in2, o->in1); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_sigp(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From 4f3adfb2a63416c434fdafdfa406604f2a18392b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 11:33:58 -0700 Subject: [PATCH 115/149] target-s390: Delete dead code from old translator The use of inline restricts detection of static functions that are no longer used. Limit the use of inline to those functions that are conditionally used based on CONFIG_USER_ONLY. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 318 ++++----------------------------------- 1 file changed, 27 insertions(+), 291 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b4b197bb44..3d92a56a50 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -79,12 +79,7 @@ static uint64_t inline_branch_hit[CC_OP_MAX]; static uint64_t inline_branch_miss[CC_OP_MAX]; #endif -static inline void debug_insn(uint64_t insn) -{ - LOG_DISAS("insn: 0x%" PRIx64 "\n", insn); -} - -static inline uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) +static uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) { if (!(s->tb->flags & FLAG_MASK_64)) { if (s->tb->flags & FLAG_MASK_32) { @@ -200,112 +195,58 @@ void s390x_translate_init(void) #include "helper.h" } -static inline TCGv_i64 load_reg(int reg) +static TCGv_i64 load_reg(int reg) { TCGv_i64 r = tcg_temp_new_i64(); tcg_gen_mov_i64(r, regs[reg]); return r; } -static inline TCGv_i64 load_freg(int reg) -{ - TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_mov_i64(r, fregs[reg]); - return r; -} - -static inline TCGv_i32 load_freg32(int reg) -{ - TCGv_i32 r = tcg_temp_new_i32(); -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(r, TCGV_HIGH(fregs[reg])); -#else - tcg_gen_shri_i64(MAKE_TCGV_I64(GET_TCGV_I32(r)), fregs[reg], 32); -#endif - return r; -} - -static inline TCGv_i64 load_freg32_i64(int reg) +static TCGv_i64 load_freg32_i64(int reg) { TCGv_i64 r = tcg_temp_new_i64(); tcg_gen_shri_i64(r, fregs[reg], 32); return r; } -static inline TCGv_i32 load_reg32(int reg) -{ - TCGv_i32 r = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(r, regs[reg]); - return r; -} - -static inline TCGv_i64 load_reg32_i64(int reg) -{ - TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ext32s_i64(r, regs[reg]); - return r; -} - -static inline void store_reg(int reg, TCGv_i64 v) +static void store_reg(int reg, TCGv_i64 v) { tcg_gen_mov_i64(regs[reg], v); } -static inline void store_freg(int reg, TCGv_i64 v) +static void store_freg(int reg, TCGv_i64 v) { tcg_gen_mov_i64(fregs[reg], v); } -static inline void store_reg32(int reg, TCGv_i32 v) -{ - /* 32 bit register writes keep the upper half */ -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v); -#else - tcg_gen_deposit_i64(regs[reg], regs[reg], - MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 32); -#endif -} - -static inline void store_reg32_i64(int reg, TCGv_i64 v) +static void store_reg32_i64(int reg, TCGv_i64 v) { /* 32 bit register writes keep the upper half */ tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); } -static inline void store_reg32h_i64(int reg, TCGv_i64 v) +static void store_reg32h_i64(int reg, TCGv_i64 v) { tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); } -static inline void store_freg32(int reg, TCGv_i32 v) -{ - /* 32 bit register writes keep the lower half */ -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_HIGH(fregs[reg]), v); -#else - tcg_gen_deposit_i64(fregs[reg], fregs[reg], - MAKE_TCGV_I64(GET_TCGV_I32(v)), 32, 32); -#endif -} - -static inline void store_freg32_i64(int reg, TCGv_i64 v) +static void store_freg32_i64(int reg, TCGv_i64 v) { tcg_gen_deposit_i64(fregs[reg], fregs[reg], v, 32, 32); } -static inline void return_low128(TCGv_i64 dest) +static void return_low128(TCGv_i64 dest) { tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); } -static inline void update_psw_addr(DisasContext *s) +static void update_psw_addr(DisasContext *s) { /* psw.addr */ tcg_gen_movi_i64(psw_addr, s->pc); } -static inline void potential_page_fault(DisasContext *s) +static void potential_page_fault(DisasContext *s) { #ifndef CONFIG_USER_ONLY update_psw_addr(s); @@ -328,7 +269,7 @@ static inline uint64_t ld_code6(CPUS390XState *env, uint64_t pc) return (ld_code2(env, pc) << 32) | ld_code4(env, pc + 2); } -static inline int get_mem_index(DisasContext *s) +static int get_mem_index(DisasContext *s) { switch (s->tb->flags & FLAG_MASK_ASC) { case PSW_ASC_PRIMARY >> 32: @@ -440,14 +381,6 @@ static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst) s->cc_op = op; } -static void gen_op_update1_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 dst) -{ - tcg_gen_discard_i64(cc_src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); - s->cc_op = op; -} - static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, TCGv_i64 dst) { @@ -457,15 +390,6 @@ static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, s->cc_op = op; } -static void gen_op_update2_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src, - TCGv_i32 dst) -{ - tcg_gen_extu_i32_i64(cc_src, src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); - s->cc_op = op; -} - static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, TCGv_i64 dst, TCGv_i64 vr) { @@ -475,104 +399,28 @@ static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, s->cc_op = op; } -static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val) -{ - gen_op_update1_cc_i32(s, CC_OP_NZ, val); -} - -static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) +static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) { gen_op_update1_cc_i64(s, CC_OP_NZ, val); } -static inline void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) +static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) { gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val); } -static inline void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) +static void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) { gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val); } -static inline void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) +static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) { gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl); } -static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - enum cc_op cond) -{ - gen_op_update2_cc_i32(s, cond, v1, v2); -} - -static inline void cmp_64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - enum cc_op cond) -{ - gen_op_update2_cc_i64(s, cond, v1, v2); -} - -static inline void cmp_s32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - cmp_32(s, v1, v2, CC_OP_LTGT_32); -} - -static inline void cmp_u32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - cmp_32(s, v1, v2, CC_OP_LTUGTU_32); -} - -static inline void cmp_s32c(DisasContext *s, TCGv_i32 v1, int32_t v2) -{ - /* XXX optimize for the constant? put it in s? */ - TCGv_i32 tmp = tcg_const_i32(v2); - cmp_32(s, v1, tmp, CC_OP_LTGT_32); - tcg_temp_free_i32(tmp); -} - -static inline void cmp_u32c(DisasContext *s, TCGv_i32 v1, uint32_t v2) -{ - TCGv_i32 tmp = tcg_const_i32(v2); - cmp_32(s, v1, tmp, CC_OP_LTUGTU_32); - tcg_temp_free_i32(tmp); -} - -static inline void cmp_s64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) -{ - cmp_64(s, v1, v2, CC_OP_LTGT_64); -} - -static inline void cmp_u64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) -{ - cmp_64(s, v1, v2, CC_OP_LTUGTU_64); -} - -static inline void cmp_s64c(DisasContext *s, TCGv_i64 v1, int64_t v2) -{ - TCGv_i64 tmp = tcg_const_i64(v2); - cmp_s64(s, v1, tmp); - tcg_temp_free_i64(tmp); -} - -static inline void cmp_u64c(DisasContext *s, TCGv_i64 v1, uint64_t v2) -{ - TCGv_i64 tmp = tcg_const_i64(v2); - cmp_u64(s, v1, tmp); - tcg_temp_free_i64(tmp); -} - -static inline void set_cc_s32(DisasContext *s, TCGv_i32 val) -{ - gen_op_update1_cc_i32(s, CC_OP_LTGT0_32, val); -} - -static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) -{ - gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); -} - /* CC value is in env->cc_op */ -static inline void set_cc_static(DisasContext *s) +static void set_cc_static(DisasContext *s) { tcg_gen_discard_i64(cc_src); tcg_gen_discard_i64(cc_dst); @@ -580,14 +428,14 @@ static inline void set_cc_static(DisasContext *s) s->cc_op = CC_OP_STATIC; } -static inline void gen_op_set_cc_op(DisasContext *s) +static void gen_op_set_cc_op(DisasContext *s) { if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { tcg_gen_movi_i32(cc_op, s->cc_op); } } -static inline void gen_update_cc_op(DisasContext *s) +static void gen_update_cc_op(DisasContext *s) { gen_op_set_cc_op(s); } @@ -667,51 +515,6 @@ static void gen_op_calc_cc(DisasContext *s) set_cc_static(s); } -static inline void decode_rr(DisasContext *s, uint64_t insn, int *r1, int *r2) -{ - debug_insn(insn); - - *r1 = (insn >> 4) & 0xf; - *r2 = insn & 0xf; -} - -static inline TCGv_i64 decode_rx(DisasContext *s, uint64_t insn, int *r1, - int *x2, int *b2, int *d2) -{ - debug_insn(insn); - - *r1 = (insn >> 20) & 0xf; - *x2 = (insn >> 16) & 0xf; - *b2 = (insn >> 12) & 0xf; - *d2 = insn & 0xfff; - - return get_address(s, *x2, *b2, *d2); -} - -static inline void decode_rs(DisasContext *s, uint64_t insn, int *r1, int *r3, - int *b2, int *d2) -{ - debug_insn(insn); - - *r1 = (insn >> 20) & 0xf; - /* aka m3 */ - *r3 = (insn >> 16) & 0xf; - *b2 = (insn >> 12) & 0xf; - *d2 = insn & 0xfff; -} - -static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2, - int *b1, int *d1) -{ - debug_insn(insn); - - *i2 = (insn >> 16) & 0xff; - *b1 = (insn >> 12) & 0xf; - *d1 = insn & 0xfff; - - return get_address(s, 0, *b1, *d1); -} - static int use_goto_tb(DisasContext *s, uint64_t dest) { /* NOTE: we handle the case where the TB spans two pages here */ @@ -721,29 +524,14 @@ static int use_goto_tb(DisasContext *s, uint64_t dest) && !(s->tb->cflags & CF_LAST_IO)); } -static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc) -{ - gen_update_cc_op(s); - - if (use_goto_tb(s, pc)) { - tcg_gen_goto_tb(tb_num); - tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb((tcg_target_long)s->tb + tb_num); - } else { - /* jump to another page: currently not optimized */ - tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb(0); - } -} - -static inline void account_noninline_branch(DisasContext *s, int cc_op) +static void account_noninline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES inline_branch_miss[cc_op]++; #endif } -static inline void account_inline_branch(DisasContext *s, int cc_op) +static void account_inline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES inline_branch_hit[cc_op]++; @@ -1018,43 +806,6 @@ static void free_compare(DisasCompare *c) } } -static void disas_b2(CPUS390XState *env, DisasContext *s, int op, - uint32_t insn) -{ -#ifndef CONFIG_USER_ONLY - switch (op) { - default: -#endif - LOG_DISAS("illegal b2 operation 0x%x\n", op); - gen_illegal_opcode(s); -#ifndef CONFIG_USER_ONLY - break; - } -#endif -} - -static void disas_s390_insn(CPUS390XState *env, DisasContext *s) -{ - unsigned char opc; - uint64_t insn; - int op; - - opc = cpu_ldub_code(env, s->pc); - LOG_DISAS("opc 0x%x\n", opc); - - switch (opc) { - case 0xb2: - insn = ld_code4(env, s->pc); - op = (insn >> 16) & 0xff; - disas_b2(env, s, op, insn); - break; - default: - qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); - gen_illegal_opcode(s); - break; - } -} - /* ====================================================================== */ /* Define the insn format enumeration. */ #define F0(N) FMT_##N, @@ -4108,30 +3859,15 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) DisasFields f; DisasOps o; + /* Search for the insn in the table. */ insn = extract_insn(env, s, &f); - /* If not found, try the old interpreter. This includes ILLOPC. */ + /* Not found means unimplemented/illegal opcode. */ if (insn == NULL) { - disas_s390_insn(env, s); - switch (s->is_jmp) { - case DISAS_NEXT: - ret = NO_EXIT; - break; - case DISAS_TB_JUMP: - ret = EXIT_GOTO_TB; - break; - case DISAS_JUMP: - ret = EXIT_PC_UPDATED; - break; - case DISAS_EXCP: - ret = EXIT_NORETURN; - break; - default: - abort(); - } - - s->pc = s->next_pc; - return ret; + qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n", + f.op, f.op2); + gen_illegal_opcode(s); + return EXIT_NORETURN; } /* Set up the strutures we use to communicate with the helpers. */ From 2cf5e350c4f7ec08aab5d70193310c721b8179e9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 29 Aug 2012 12:57:55 -0700 Subject: [PATCH 116/149] target-s390: Implement BRANCH ON INDEX Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 10 ++++++++ target-s390x/translate.c | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index cd773d0168..8b89ce6217 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -90,6 +90,16 @@ /* BRANCH RELATIVE ON COUNT */ C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* BRANCH ON INDEX */ + D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0) + D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1) + D(0xeb44, BXHG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 0) + D(0xeb45, BXLEG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 1) +/* BRANCH RELATIVE ON INDEX */ + D(0x8400, BRXH, RSI, Z, 0, 0, 0, 0, bx32, 0, 0) + D(0x8500, BRXLE, RSI, Z, 0, 0, 0, 0, bx32, 0, 1) + D(0xec44, BRXHG, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 0) + D(0xec45, BRXHLE, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 1) /* CHECKSUM */ C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 3d92a56a50..6553e486c3 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1355,6 +1355,58 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_bx32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + TCGv_i64 t; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_add_i64(t, regs[r1], regs[r3]); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_gen_trunc_i64_i32(c.u.s32.b, regs[r3 | 1]); + store_reg32_i64(r1, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bx64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = true; + + if (r1 == (r3 | 1)) { + c.u.s64.b = load_reg(r3 | 1); + c.g2 = false; + } else { + c.u.s64.b = regs[r3 | 1]; + c.g2 = true; + } + + tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]); + c.u.s64.a = regs[r1]; + c.g1 = true; + + return help_branch(s, &c, is_imm, imm, o->in2); +} + static ExitStatus op_ceb(DisasContext *s, DisasOps *o) { gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); From 7a6c7067f034c5b887cda5e45ef660fe50ebbd1b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 17:28:17 -0700 Subject: [PATCH 117/149] target-s390: Tidy s->op_cc handling There's no need to force computation of the true cc_op when taking an exception or single stepping. In either case we'll enter the next TB with s->cc_op = DYNAMIC and recompute anyway. Just make sure that s->cc_op is stored back to env->cc_op as needed. Delete some dead functions, avoid allocating unused TCG temps, drop the old s->is_jmp setting. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 95 +++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6553e486c3..c87d97ffe2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -55,7 +55,6 @@ struct DisasContext { uint64_t pc, next_pc; enum cc_op cc_op; bool singlestep_enabled; - int is_jmp; }; /* Information carried about a condition to be evaluated. */ @@ -72,8 +71,6 @@ typedef struct { #define DISAS_EXCP 4 -static void gen_op_calc_cc(DisasContext *s); - #ifdef DEBUG_INLINE_BRANCHES static uint64_t inline_branch_hit[CC_OP_MAX]; static uint64_t inline_branch_miss[CC_OP_MAX]; @@ -246,12 +243,17 @@ static void update_psw_addr(DisasContext *s) tcg_gen_movi_i64(psw_addr, s->pc); } +static void update_cc_op(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { + tcg_gen_movi_i32(cc_op, s->cc_op); + } +} + static void potential_page_fault(DisasContext *s) { -#ifndef CONFIG_USER_ONLY update_psw_addr(s); - gen_op_calc_cc(s); -#endif + update_cc_op(s); } static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) @@ -309,13 +311,10 @@ static void gen_program_exception(DisasContext *s, int code) update_psw_addr(s); /* Save off cc. */ - gen_op_calc_cc(s); + update_cc_op(s); /* Trigger exception. */ gen_exception(EXCP_PGM); - - /* End TB here. */ - s->is_jmp = DISAS_EXCP; } static inline void gen_illegal_opcode(DisasContext *s) @@ -428,23 +427,40 @@ static void set_cc_static(DisasContext *s) s->cc_op = CC_OP_STATIC; } -static void gen_op_set_cc_op(DisasContext *s) -{ - if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { - tcg_gen_movi_i32(cc_op, s->cc_op); - } -} - -static void gen_update_cc_op(DisasContext *s) -{ - gen_op_set_cc_op(s); -} - /* calculates cc into cc_op */ static void gen_op_calc_cc(DisasContext *s) { - TCGv_i32 local_cc_op = tcg_const_i32(s->cc_op); - TCGv_i64 dummy = tcg_const_i64(0); + TCGv_i32 local_cc_op; + TCGv_i64 dummy; + + TCGV_UNUSED_I32(local_cc_op); + TCGV_UNUSED_I64(dummy); + switch (s->cc_op) { + default: + dummy = tcg_const_i64(0); + /* FALLTHRU */ + case CC_OP_ADD_64: + case CC_OP_ADDU_64: + case CC_OP_ADDC_64: + case CC_OP_SUB_64: + case CC_OP_SUBU_64: + case CC_OP_SUBB_64: + case CC_OP_ADD_32: + case CC_OP_ADDU_32: + case CC_OP_ADDC_32: + case CC_OP_SUB_32: + case CC_OP_SUBU_32: + case CC_OP_SUBB_32: + local_cc_op = tcg_const_i32(s->cc_op); + break; + case CC_OP_CONST0: + case CC_OP_CONST1: + case CC_OP_CONST2: + case CC_OP_CONST3: + case CC_OP_STATIC: + case CC_OP_DYNAMIC: + break; + } switch (s->cc_op) { case CC_OP_CONST0: @@ -508,8 +524,12 @@ static void gen_op_calc_cc(DisasContext *s) tcg_abort(); } - tcg_temp_free_i32(local_cc_op); - tcg_temp_free_i64(dummy); + if (!TCGV_IS_UNUSED_I32(local_cc_op)) { + tcg_temp_free_i32(local_cc_op); + } + if (!TCGV_IS_UNUSED_I64(dummy)) { + tcg_temp_free_i64(dummy); + } /* We now have cc in cc_op as constant */ set_cc_static(s); @@ -1054,7 +1074,7 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) return NO_EXIT; } if (use_goto_tb(s, dest)) { - gen_update_cc_op(s); + update_cc_op(s); tcg_gen_goto_tb(0); tcg_gen_movi_i64(psw_addr, dest); tcg_gen_exit_tb((tcg_target_long)s->tb); @@ -1103,7 +1123,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, if (use_goto_tb(s, s->next_pc)) { if (is_imm && use_goto_tb(s, dest)) { /* Both exits can use goto_tb. */ - gen_update_cc_op(s); + update_cc_op(s); lab = gen_new_label(); if (c->is_64) { @@ -1141,7 +1161,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, } /* Branch not taken. */ - gen_update_cc_op(s); + update_cc_op(s); tcg_gen_goto_tb(0); tcg_gen_movi_i64(psw_addr, s->next_pc); tcg_gen_exit_tb((tcg_target_long)s->tb + 0); @@ -1749,7 +1769,7 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) TCGv_i64 tmp; update_psw_addr(s); - gen_op_calc_cc(s); + update_cc_op(s); tmp = tcg_const_i64(s->next_pc); gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); @@ -2913,7 +2933,7 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) TCGv_i32 t; update_psw_addr(s); - gen_op_calc_cc(s); + update_cc_op(s); t = tcg_const_i32(get_field(s->fields, i1) & 0xff); tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); @@ -3999,7 +4019,6 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; do_debug = dc.singlestep_enabled = env->singlestep_enabled; - dc.is_jmp = DISAS_NEXT; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -4073,17 +4092,13 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, update_psw_addr(&dc); /* FALLTHRU */ case EXIT_PC_UPDATED: - if (singlestep && dc.cc_op != CC_OP_DYNAMIC) { - gen_op_calc_cc(&dc); - } else { - /* Next TB starts off with CC_OP_DYNAMIC, - so make sure the cc op type is in env */ - gen_op_set_cc_op(&dc); - } + /* Next TB starts off with CC_OP_DYNAMIC, so make sure the + cc op type is in env */ + update_cc_op(&dc); + /* Exit the TB, either by raising a debug exception or by return. */ if (do_debug) { gen_exception(EXCP_DEBUG); } else { - /* Generate the return instruction */ tcg_gen_exit_tb(0); } break; From 5550359f07b54d6fb6f38ee5dcbc198cff42bf51 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 10:53:49 -0700 Subject: [PATCH 118/149] target-s390: Implement COMPARE AND BRANCH Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 19 +++++++++++++++++++ target-s390x/translate.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8b89ce6217..4478d1c8cf 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -166,6 +166,25 @@ /* COMPARE LOGICAL STRING */ C(0xb25d, CLST, RRE, Z, r1_o, r2_o, 0, 0, clst, 0) +/* COMPARE AND BRANCH */ + D(0xecf6, CRB, RRS, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xece4, CGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xec76, CRJ, RIE_b, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xec64, CGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xecfe, CIB, RIS, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xecfc, CGIB, RIS, GIE, r1_o, i2, 0, 0, cj, 0, 0) + D(0xec7e, CIJ, RIE_c, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xec7c, CGIJ, RIE_c, GIE, r1_o, i2, 0, 0, cj, 0, 0) +/* COMPARE LOGICAL AND BRANCH */ + D(0xecf7, CLRB, RRS, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xece5, CLGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xec77, CLRJ, RIE_b, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xec65, CLGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xecff, CLIB, RIS, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xecfd, CLGIB, RIS, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + D(0xec7f, CLIJ, RIE_c, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + /* COMPARE AND SWAP */ C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) C(0xeb14, CSY, RSY_a, LD, r1_o, a2, new, r1_32, cs, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c87d97ffe2..d6f7121a2e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1427,6 +1427,34 @@ static ExitStatus op_bx64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_cj(DisasContext *s, DisasOps *o) +{ + int imm, m3 = get_field(s->fields, m3); + bool is_imm; + DisasCompare c; + + /* Bit 3 of the m3 field is reserved and should be zero. + Choose to ignore it wrt the ltgt_cond table above. */ + c.cond = ltgt_cond[m3 & 14]; + if (s->insn->data) { + c.cond = tcg_unsigned_cond(c.cond); + } + c.is_64 = c.g1 = c.g2 = true; + c.u.s64.a = o->in1; + c.u.s64.b = o->in2; + + is_imm = have_field(s->fields, i4); + if (is_imm) { + imm = get_field(s->fields, i4); + } else { + imm = 0; + o->out = get_address(s, 0, get_field(s->fields, b4), + get_field(s->fields, d4)); + } + + return help_branch(s, &c, is_imm, imm, o->out); +} + static ExitStatus op_ceb(DisasContext *s, DisasOps *o) { gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); From 2d6a869833d99d89fc4bbe42bdb35b2c1d808067 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 12:50:06 -0700 Subject: [PATCH 119/149] target-s390: Implement RISBG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 83 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4478d1c8cf..c80a386c32 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -500,6 +500,11 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* ROTATE THEN INSERT SELECTED BITS */ + C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) + C(0xec5d, RISBHG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) + C(0xec51, RISBLG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) + /* SEARCH STRING */ C(0xb25e, SRST, RRE, Z, r1_o, r2_o, 0, 0, srst, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d6f7121a2e..1f8659f4db 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2429,6 +2429,89 @@ static ExitStatus op_ptlb(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_risbg(DisasContext *s, DisasOps *o) +{ + int i3 = get_field(s->fields, i3); + int i4 = get_field(s->fields, i4); + int i5 = get_field(s->fields, i5); + int do_zero = i4 & 0x80; + uint64_t mask, imask, pmask; + int pos, len, rot; + + /* Adjust the arguments for the specific insn. */ + switch (s->fields->op2) { + case 0x55: /* risbg */ + i3 &= 63; + i4 &= 63; + pmask = ~0; + break; + case 0x5d: /* risbhg */ + i3 &= 31; + i4 &= 31; + pmask = 0xffffffff00000000ull; + break; + case 0x51: /* risblg */ + i3 &= 31; + i4 &= 31; + pmask = 0x00000000ffffffffull; + break; + default: + abort(); + } + + /* MASK is the set of bits to be inserted from R2. + Take care for I3/I4 wraparound. */ + mask = pmask >> i3; + if (i3 <= i4) { + mask ^= pmask >> i4 >> 1; + } else { + mask |= ~(pmask >> i4 >> 1); + } + mask &= pmask; + + /* IMASK is the set of bits to be kept from R1. In the case of the high/low + insns, we need to keep the other half of the register. */ + imask = ~mask | ~pmask; + if (do_zero) { + if (s->fields->op2 == 0x55) { + imask = 0; + } else { + imask = ~pmask; + } + } + + /* In some cases we can implement this with deposit, which can be more + efficient on some hosts. */ + if (~mask == imask && i3 <= i4) { + if (s->fields->op2 == 0x5d) { + i3 += 32, i4 += 32; + } + /* Note that we rotate the bits to be inserted to the lsb, not to + the position as described in the PoO. */ + len = i4 - i3 + 1; + pos = 63 - i4; + rot = (i5 - pos) & 63; + } else { + pos = len = -1; + rot = i5 & 63; + } + + /* Rotate the input as necessary. */ + tcg_gen_rotli_i64(o->in2, o->in2, rot); + + /* Insert the selected bits into the output. */ + if (pos >= 0) { + tcg_gen_deposit_i64(o->out, o->out, o->in2, pos, len); + } else if (imask == 0) { + tcg_gen_andi_i64(o->out, o->in2, mask); + } else { + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_andi_i64(o->out, o->out, imask); + tcg_gen_or_i64(o->out, o->out, o->in2); + } + return NO_EXIT; +} + static ExitStatus op_rev16(DisasContext *s, DisasOps *o) { tcg_gen_bswap16_i64(o->out, o->in2); From 143cbbc5ebc4a5b5beb82dc31ecc5ac5f6d511d2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:52:08 -0700 Subject: [PATCH 120/149] target-s390: Implement LDGR, LGDR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c80a386c32..8bcfb2b98a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -364,6 +364,10 @@ /* LOAD LOGICAL THIRTY ONE BITS */ C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) +/* LOAD FPR FROM GR */ + C(0xb3c1, LDGR, RRE, FPRGR, 0, r2_o, 0, f1, mov2, 0) +/* LOAD GR FROM FPR */ + C(0xb3cd, LGDR, RRE, FPRGR, 0, f2_o, 0, r1, mov2, 0) /* LOAD NEGATIVE */ C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) From d6c6372e186e7f17fe9eeec0c50a43b484669d71 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 13:54:13 -0700 Subject: [PATCH 121/149] target-s390: Implement R[NOX]SBG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 +++ target-s390x/translate.c | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8bcfb2b98a..9582f0c847 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -508,6 +508,10 @@ C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) C(0xec5d, RISBHG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) C(0xec51, RISBLG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) +/* ROTATE_THEN SELECTED BITS */ + C(0xec54, RNSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec56, ROSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec57, RXSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) /* SEARCH STRING */ C(0xb25e, SRST, RRE, Z, r1_o, r2_o, 0, 0, srst, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1f8659f4db..dbc43a6754 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2512,6 +2512,59 @@ static ExitStatus op_risbg(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_rosbg(DisasContext *s, DisasOps *o) +{ + int i3 = get_field(s->fields, i3); + int i4 = get_field(s->fields, i4); + int i5 = get_field(s->fields, i5); + uint64_t mask; + + /* If this is a test-only form, arrange to discard the result. */ + if (i3 & 0x80) { + o->out = tcg_temp_new_i64(); + o->g_out = false; + } + + i3 &= 63; + i4 &= 63; + i5 &= 63; + + /* MASK is the set of bits to be operated on from R2. + Take care for I3/I4 wraparound. */ + mask = ~0ull >> i3; + if (i3 <= i4) { + mask ^= ~0ull >> i4 >> 1; + } else { + mask |= ~(~0ull >> i4 >> 1); + } + + /* Rotate the input as necessary. */ + tcg_gen_rotli_i64(o->in2, o->in2, i5); + + /* Operate. */ + switch (s->fields->op2) { + case 0x55: /* AND */ + tcg_gen_ori_i64(o->in2, o->in2, ~mask); + tcg_gen_and_i64(o->out, o->out, o->in2); + break; + case 0x56: /* OR */ + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_or_i64(o->out, o->out, o->in2); + break; + case 0x57: /* XOR */ + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_xor_i64(o->out, o->out, o->in2); + break; + default: + abort(); + } + + /* Set the CC. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + static ExitStatus op_rev16(DisasContext *s, DisasOps *o) { tcg_gen_bswap16_i64(o->out, o->in2); From e0def9094ef1997613e488768405bcfb589f0596 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 14:10:05 -0700 Subject: [PATCH 122/149] target-s390: Implement PREFETCH Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 9582f0c847..eb88c550d6 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -500,6 +500,11 @@ C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) +/* PREFETCH */ + /* Implemented as nops of course. */ + C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) + C(0xc602, PFDRL, RIL_c, GIE, 0, 0, 0, 0, 0, 0) + /* ROTATE LEFT SINGLE LOGICAL */ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) From 403e217f4073b885b7e02a1b64054ceca7202bf6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:54:00 -0700 Subject: [PATCH 123/149] target-s390: Implement COMPARE RELATIVE LONG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index eb88c550d6..5c19aefefc 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -120,6 +120,10 @@ /* COMPARE IMMEDIATE */ C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) +/* COMPARE RELATIVE LONG */ + C(0xc60d, CRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps32) + C(0xc608, CGRL, RIL_b, GIE, r1, mri2_64, 0, 0, 0, cmps64) + C(0xc60c, CGFRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps64) /* COMPARE HALFWORD */ C(0x4900, CH, RX_a, Z, r1_o, m2_16s, 0, 0, 0, cmps32) C(0xe379, CHY, RXY_a, LD, r1_o, m2_16s, 0, 0, 0, cmps32) From 1c2687518235aa38dd3dd270fc216e559d0509eb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 17:32:54 -0700 Subject: [PATCH 124/149] target-s390: Implement COMPARE AND TRAP Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 11 +++++++++++ target-s390x/translate.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 5c19aefefc..b739d70d38 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -198,6 +198,17 @@ C(0xeb31, CDSY, RSY_a, LD, r1_D32, a2, new, r1_D32, cds, 0) C(0xeb3e, CDSG, RSY_a, Z, 0, a2, 0, 0, cdsg, 0) +/* COMPARE AND TRAP */ + D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0) + D(0xb960, CGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 0) + D(0xec72, CIT, RIE_a, GIE, r1_32s, i2, 0, 0, ct, 0, 0) + D(0xec70, CGIT, RIE_a, GIE, r1_o, i2, 0, 0, ct, 0, 0) +/* COMPARE LOGICAL AND TRAP */ + D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1) + D(0xb961, CLGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1) + D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1) + D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 0) + /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dbc43a6754..e94c663180 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1705,6 +1705,35 @@ static ExitStatus op_cvd(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ct(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int lab = gen_new_label(); + TCGv_i32 t; + TCGCond c; + + /* Bit 3 of the m3 field is reserved and should be zero. + Choose to ignore it wrt the ltgt_cond table above. */ + c = tcg_invert_cond(ltgt_cond[m3 & 14]); + if (s->insn->data) { + c = tcg_unsigned_cond(c); + } + tcg_gen_brcond_i64(c, o->in1, o->in2, lab); + + /* Set DXC to 0xff. */ + t = tcg_temp_new_i32(); + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_ori_i32(t, t, 0xff00); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_temp_free_i32(t); + + /* Trap. */ + gen_program_exception(s, PGM_DATA); + + gen_set_label(lab); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_diag(DisasContext *s, DisasOps *o) { From 632086da28e1682c0129276656ee0d32274fcd17 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:55:00 -0700 Subject: [PATCH 125/149] target-s390: Implement LOAD ON CONDITION Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b739d70d38..91ee0551bb 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -390,6 +390,11 @@ C(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32) C(0xb311, LNDBR, RRE, Z, 0, f2_o, f1, 0, nabsf64, f64) C(0xb341, LNXBR, RRE, Z, 0, x2_o, x1, 0, nabsf128, f128) +/* LOAD ON CONDITION */ + C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0) + C(0xb9e2, LOCGR, RRF_c, LOC, r1, r2, r1, 0, loc, 0) + C(0xebf2, LOC, RSY_b, LOC, r1, m2_32u, new, r1_32, loc, 0) + C(0xebe2, LOCG, RSY_b, LOC, r1, m2_64, r1, 0, loc, 0) /* LOAD POSITIVE */ C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e94c663180..1edb066463 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2045,6 +2045,36 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_loc(DisasContext *s, DisasOps *o) +{ + DisasCompare c; + + disas_jcc(s, &c, get_field(s->fields, m3)); + + if (c.is_64) { + tcg_gen_movcond_i64(c.cond, o->out, c.u.s64.a, c.u.s64.b, + o->in2, o->in1); + free_compare(&c); + } else { + TCGv_i32 t32 = tcg_temp_new_i32(); + TCGv_i64 t, z; + + tcg_gen_setcond_i32(c.cond, t32, c.u.s32.a, c.u.s32.b); + free_compare(&c); + + t = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t, t32); + tcg_temp_free_i32(t32); + + z = tcg_const_i64(0); + tcg_gen_movcond_i64(TCG_COND_NE, o->out, t, z, o->in2, o->in1); + tcg_temp_free_i64(t); + tcg_temp_free_i64(z); + } + + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_lctl(DisasContext *s, DisasOps *o) { From b92fa33486b240404923308b483a3318eb804c4a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 09:45:20 -0700 Subject: [PATCH 126/149] target-s390: Implement STORE ON CONDITION Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 91ee0551bb..00b95b681d 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -601,6 +601,9 @@ C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE ON CONDITION */ + D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0) + D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1) /* STORE REVERSED */ C(0xe33f, STRVH, RXY_a, Z, la2, r1_16u, new, m1_16, rev16, 0) C(0xe33e, STRV, RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1edb066463..321fc46a13 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2747,6 +2747,35 @@ static ExitStatus op_sigp(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_soc(DisasContext *s, DisasOps *o) +{ + DisasCompare c; + TCGv_i64 a; + int lab, r1; + + disas_jcc(s, &c, get_field(s->fields, m3)); + + lab = gen_new_label(); + if (c.is_64) { + tcg_gen_brcond_i64(c.cond, c.u.s64.a, c.u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c.cond, c.u.s32.a, c.u.s32.b, lab); + } + free_compare(&c); + + r1 = get_field(s->fields, r1); + a = get_address(s, 0, get_field(s->fields, b2), get_field(s->fields, d2)); + if (s->insn->data) { + tcg_gen_qemu_st64(regs[r1], a, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(regs[r1], a, get_mem_index(s)); + } + tcg_temp_free_i64(a); + + gen_set_label(lab); + return NO_EXIT; +} + static ExitStatus op_sla(DisasContext *s, DisasOps *o) { uint64_t sign = 1ull << s->insn->data; From 6ac1b45f9b3cb788255c0fde7637ba663eba632c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 10:42:54 -0700 Subject: [PATCH 127/149] target-s390: Implement CONVERT TO LOGICAL Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 66 ++++++++++++++++++++++++++++++++++++++ target-s390x/helper.h | 6 ++++ target-s390x/insn-data.def | 7 ++++ target-s390x/translate.c | 54 +++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 74b94f290f..6a76541833 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -457,6 +457,72 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) return ret; } +/* convert 32-bit float to 64-bit uint */ +uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint64_t ret; + v2 = float32_to_float64(v2, &env->fpu_status); + ret = float64_to_uint64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit float to 64-bit uint */ +uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint64_t ret = float64_to_uint64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 128-bit float to 64-bit uint */ +uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + /* ??? Not 100% correct. */ + uint64_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 32-bit float to 32-bit uint */ +uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint32_t ret = float32_to_uint32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit float to 32-bit uint */ +uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint32_t ret = float64_to_uint32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 128-bit float to 32-bit uint */ +uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + /* Not 100% correct. */ + uint32_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + /* 32-bit FP multiply and add */ uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 5d8a82175c..0204e8505f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -61,6 +61,12 @@ DEF_HELPER_4(cgxb, i64, env, i64, i64, i32) DEF_HELPER_3(cfeb, i64, env, i64, i32) DEF_HELPER_3(cfdb, i64, env, i64, i32) DEF_HELPER_4(cfxb, i64, env, i64, i64, i32) +DEF_HELPER_3(clgeb, i64, env, i64, i32) +DEF_HELPER_3(clgdb, i64, env, i64, i32) +DEF_HELPER_4(clgxb, i64, env, i64, i64, i32) +DEF_HELPER_3(clfeb, i64, env, i64, i32) +DEF_HELPER_3(clfdb, i64, env, i64, i32) +DEF_HELPER_4(clfxb, i64, env, i64, i64, i32) DEF_HELPER_4(maeb, i64, env, i64, i64, i64) DEF_HELPER_4(madb, i64, env, i64, i64, i64) DEF_HELPER_4(mseb, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 00b95b681d..a67fdcc6ad 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -226,6 +226,13 @@ C(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0) C(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, f1, 0, cdgb, 0) C(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, x1, 0, cxgb, 0) +/* CONVERT TO LOGICAL */ + C(0xb39c, CLFEBR, RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0) + C(0xb39d, CLFDBR, RRF_e, FPE, 0, f2_o, new, r1_32, clfdb, 0) + C(0xb39e, CLFXBR, RRF_e, FPE, 0, x2_o, new, r1_32, clfxb, 0) + C(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0) + C(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2_o, r1, 0, clgdb, 0) + C(0xb3ae, CLGXBR, RRF_e, FPE, 0, x2_o, r1, 0, clgxb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 321fc46a13..1b7a8dc946 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1530,6 +1530,60 @@ static ExitStatus op_cgxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clfeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clfdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clfxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_cegb(DisasContext *s, DisasOps *o) { TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); From 2112bf1bfb696def31b211425e5e74e89f9574c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 11:08:17 -0700 Subject: [PATCH 128/149] target-s390: Implement CONVERT FROM LOGICAL Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 31 +++++++++++++++++++++++++++++++ target-s390x/helper.h | 3 +++ target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 25 +++++++++++++++++++++++++ 4 files changed, 66 insertions(+) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 6a76541833..58c2e6135c 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -395,6 +395,37 @@ uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3) return RET128(ret); } +/* convert 64-bit uint to 32-bit float */ +uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float32 ret = uint64_to_float32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit uint to 64-bit float */ +uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float64 ret = uint64_to_float64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit uint to 128-bit float */ +uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + /* ??? Not 50% correct. */ + float128 ret = int64_to_float128(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + /* convert 32-bit float to 64-bit int */ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 0204e8505f..aef6f0faf8 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -32,6 +32,9 @@ DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32) DEF_HELPER_3(cdgb, i64, env, s64, i32) DEF_HELPER_3(cxgb, i64, env, s64, i32) +DEF_HELPER_3(celgb, i64, env, i64, i32) +DEF_HELPER_3(cdlgb, i64, env, i64, i32) +DEF_HELPER_3(cxlgb, i64, env, i64, i32) DEF_HELPER_3(aeb, i64, env, i64, i64) DEF_HELPER_3(adb, i64, env, i64, i64) DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a67fdcc6ad..0777b5567b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -233,6 +233,13 @@ C(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0) C(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2_o, r1, 0, clgdb, 0) C(0xb3ae, CLGXBR, RRF_e, FPE, 0, x2_o, r1, 0, clgxb, 0) +/* CONVERT FROM LOGICAL */ + C(0xb390, CELFBR, RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0) + C(0xb391, CDLFBR, RRF_e, FPE, 0, r2_32u, f1, 0, cdlgb, 0) + C(0xb392, CXLFBR, RRF_e, FPE, 0, r2_32u, x1, 0, cxlgb, 0) + C(0xb3a0, CELGBR, RRF_e, FPE, 0, r2_o, new, e1, celgb, 0) + C(0xb3a1, CDLGBR, RRF_e, FPE, 0, r2_o, f1, 0, cdlgb, 0) + C(0xb3a2, CXLGBR, RRF_e, FPE, 0, r2_o, x1, 0, cxlgb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1b7a8dc946..dc5aac7941 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1609,6 +1609,31 @@ static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_celgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_celgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cdlgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cdlgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cxlgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cxlgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_cksm(DisasContext *s, DisasOps *o) { int r2 = get_field(s->fields, r2); From 99b4f24b3e636ab241b53bc16bf8f0a0ac4a2271 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 11:14:04 -0700 Subject: [PATCH 129/149] target-s390: Implement POPCNT Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 + target-s390x/insn-data.def | 3 +++ target-s390x/int_helper.c | 12 ++++++++++++ target-s390x/translate.c | 6 ++++++ 4 files changed, 22 insertions(+) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index aef6f0faf8..23d23d5b3a 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -87,6 +87,7 @@ DEF_HELPER_4(tr, void, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0777b5567b..49e4a441fd 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -539,6 +539,9 @@ C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) C(0xc602, PFDRL, RIL_c, GIE, 0, 0, 0, 0, 0, 0) +/* POPULATION COUNT */ + C(0xb9e1, POPCNT, RRE, PC, 0, r2_o, r1, 0, popcnt, nz64) + /* ROTATE LEFT SINGLE LOGICAL */ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index dc16de206c..685830124f 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -191,3 +191,15 @@ uint64_t HELPER(cvd)(int32_t bin) return dec; } + +uint64_t HELPER(popcnt)(uint64_t r2) +{ + uint64_t ret = 0; + int i; + + for (i = 0; i < 64; i += 8) { + uint64_t t = ctpop32((r2 >> i) & 0xff); + ret |= t << i; + } + return ret; +} diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dc5aac7941..fe880956f0 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2558,6 +2558,12 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_popcnt(DisasContext *s, DisasOps *o) +{ + gen_helper_popcnt(o->out, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_ptlb(DisasContext *s, DisasOps *o) { From 2db014b5a73f295f6edbdc2c8400a94ccfc90624 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 14:13:52 -0700 Subject: [PATCH 130/149] target-s390: Implement CPSDR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 49e4a441fd..b023911cec 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -104,6 +104,9 @@ /* CHECKSUM */ C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) +/* COPY SIGN */ + C(0xb372, CPSDR, RRF_b, FPSSH, f3_o, f2_o, f1, 0, cps, 0) + /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index fe880956f0..2873f7d2e4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1719,6 +1719,16 @@ static ExitStatus op_clst(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cps(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t = tcg_temp_new_i64(); + tcg_gen_andi_i64(t, o->in1, 0x8000000000000000ull); + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull); + tcg_gen_or_i64(o->out, o->out, t); + tcg_temp_free_i64(t); + return NO_EXIT; +} + static ExitStatus op_cs(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); @@ -3801,6 +3811,12 @@ static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_out = o->g_out2 = true; } +static void in1_f3_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = fregs[get_field(f, r3)]; + o->g_in1 = true; +} + static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); From 49f7ee802fa6695af61dc1e88638f426d47a22a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 7 Sep 2012 16:16:57 -0700 Subject: [PATCH 131/149] target-s390: Check insn operand specifications Removes all the fixmes for even register numbers, etc. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 195 +++++++++++++++++++++++++++++++-------- 1 file changed, 159 insertions(+), 36 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2873f7d2e4..b4dd68e3f5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -993,6 +993,17 @@ typedef struct { TCGv_i64 addr1; } DisasOps; +/* Instructions can place constraints on their operands, raising specification + exceptions if they are violated. To make this easy to automate, each "in1", + "in2", "prep", "wout" helper will have a SPEC_ define that equals one + of the following, or 0. To make this easy to document, we'll put the + SPEC_ defines next to . */ + +#define SPEC_r1_even 1 +#define SPEC_r2_even 2 +#define SPEC_r1_f128 4 +#define SPEC_r2_f128 8 + /* Return values from translate_one, indicating the state of the TB. */ typedef enum { /* Continue the TB. */ @@ -1038,6 +1049,7 @@ struct DisasInsn { unsigned opc:16; DisasFormat fmt:6; DisasFacility fac:6; + unsigned spec:4; const char *name; @@ -3561,42 +3573,46 @@ static void prep_new(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = tcg_temp_new_i64(); } +#define SPEC_prep_new 0 static void prep_new_P(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = tcg_temp_new_i64(); o->out2 = tcg_temp_new_i64(); } +#define SPEC_prep_new_P 0 static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = regs[get_field(f, r1)]; o->g_out = true; } +#define SPEC_prep_r1 0 static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); o->out = regs[r1]; - o->out2 = regs[(r1 + 1) & 15]; + o->out2 = regs[r1 + 1]; o->g_out = o->g_out2 = true; } +#define SPEC_prep_r1_P SPEC_r1_even static void prep_f1(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = fregs[get_field(f, r1)]; o->g_out = true; } +#define SPEC_prep_f1 0 static void prep_x1(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int r1 = get_field(f, r1); o->out = fregs[r1]; - o->out2 = fregs[(r1 + 2) & 15]; + o->out2 = fregs[r1 + 2]; o->g_out = o->g_out2 = true; } +#define SPEC_prep_x1 SPEC_r1_f128 /* ====================================================================== */ /* The "Write OUTput" generators. These generally perform some non-trivial @@ -3608,58 +3624,64 @@ static void wout_r1(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg(get_field(f, r1), o->out); } +#define SPEC_wout_r1 0 static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o) { int r1 = get_field(f, r1); tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8); } +#define SPEC_wout_r1_8 0 static void wout_r1_16(DisasContext *s, DisasFields *f, DisasOps *o) { int r1 = get_field(f, r1); tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16); } +#define SPEC_wout_r1_16 0 static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); } +#define SPEC_wout_r1_32 0 static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); store_reg32_i64(r1, o->out); - store_reg32_i64((r1 + 1) & 15, o->out2); + store_reg32_i64(r1 + 1, o->out2); } +#define SPEC_wout_r1_P32 SPEC_r1_even static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); - store_reg32_i64((r1 + 1) & 15, o->out); + store_reg32_i64(r1 + 1, o->out); tcg_gen_shri_i64(o->out, o->out, 32); store_reg32_i64(r1, o->out); } +#define SPEC_wout_r1_D32 SPEC_r1_even static void wout_e1(DisasContext *s, DisasFields *f, DisasOps *o) { store_freg32_i64(get_field(f, r1), o->out); } +#define SPEC_wout_e1 0 static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o) { store_freg(get_field(f, r1), o->out); } +#define SPEC_wout_f1 0 static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int f1 = get_field(s->fields, r1); store_freg(f1, o->out); - store_freg((f1 + 2) & 15, o->out2); + store_freg(f1 + 2, o->out2); } +#define SPEC_wout_x1 SPEC_r1_f128 static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3667,6 +3689,7 @@ static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(get_field(f, r1), o->out); } } +#define SPEC_wout_cond_r1r2_32 0 static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3674,31 +3697,37 @@ static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) store_freg32_i64(get_field(f, r1), o->out); } } +#define SPEC_wout_cond_e1e2 0 static void wout_m1_8(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_8 0 static void wout_m1_16(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_16 0 static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_32 0 static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_64 0 static void wout_m2_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s)); } +#define SPEC_wout_m2_32 0 /* ====================================================================== */ /* The "INput 1" generators. These load the first operand to an insn. */ @@ -3707,126 +3736,138 @@ static void in1_r1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r1)); } +#define SPEC_in1_r1 0 static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = regs[get_field(f, r1)]; o->g_in1 = true; } +#define SPEC_in1_r1_o 0 static void in1_r1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1)]); } +#define SPEC_in1_r1_32s 0 static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); } +#define SPEC_in1_r1_32u 0 static void in1_r1_sr32(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_shri_i64(o->in1, regs[get_field(f, r1)], 32); } +#define SPEC_in1_r1_sr32 0 static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ - int r1 = get_field(f, r1); - o->in1 = load_reg((r1 + 1) & 15); + o->in1 = load_reg(get_field(f, r1) + 1); } +#define SPEC_in1_r1p1 SPEC_r1_even static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ - int r1 = get_field(f, r1); o->in1 = tcg_temp_new_i64(); - tcg_gen_ext32s_i64(o->in1, regs[(r1 + 1) & 15]); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1) + 1]); } +#define SPEC_in1_r1p1_32s SPEC_r1_even static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ - int r1 = get_field(f, r1); o->in1 = tcg_temp_new_i64(); - tcg_gen_ext32u_i64(o->in1, regs[(r1 + 1) & 15]); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1) + 1]); } +#define SPEC_in1_r1p1_32u SPEC_r1_even static void in1_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); o->in1 = tcg_temp_new_i64(); tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]); } +#define SPEC_in1_r1_D32 SPEC_r1_even static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); } +#define SPEC_in1_r2 0 static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r3)); } +#define SPEC_in1_r3 0 static void in1_r3_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = regs[get_field(f, r3)]; o->g_in1 = true; } +#define SPEC_in1_r3_o 0 static void in1_r3_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r3)]); } +#define SPEC_in1_r3_32s 0 static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r3)]); } +#define SPEC_in1_r3_32u 0 static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_freg32_i64(get_field(f, r1)); } +#define SPEC_in1_e1 0 static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = fregs[get_field(f, r1)]; o->g_in1 = true; } +#define SPEC_in1_f1_o 0 static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int r1 = get_field(f, r1); o->out = fregs[r1]; - o->out2 = fregs[(r1 + 2) & 15]; + o->out2 = fregs[r1 + 2]; o->g_out = o->g_out2 = true; } +#define SPEC_in1_x1_o SPEC_r1_f128 static void in1_f3_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = fregs[get_field(f, r3)]; o->g_in1 = true; } +#define SPEC_in1_f3_o 0 static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); } +#define SPEC_in1_la1 0 static void in1_la2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; o->addr1 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); } +#define SPEC_in1_la2 0 static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3834,6 +3875,7 @@ static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_8u 0 static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3841,6 +3883,7 @@ static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_16s 0 static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3848,6 +3891,7 @@ static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_16u 0 static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3855,6 +3899,7 @@ static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_32s 0 static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3862,6 +3907,7 @@ static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_32u 0 static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3869,6 +3915,7 @@ static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_64 0 /* ====================================================================== */ /* The "INput 2" generators. These load the second operand to an insn. */ @@ -3878,29 +3925,34 @@ static void in2_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = regs[get_field(f, r1)]; o->g_in2 = true; } +#define SPEC_in2_r1_o 0 static void in2_r1_16u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r1)]); } +#define SPEC_in2_r1_16u 0 static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r1)]); } +#define SPEC_in2_r1_32u 0 static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r2)); } +#define SPEC_in2_r2 0 static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = regs[get_field(f, r2)]; o->g_in2 = true; } +#define SPEC_in2_r2_o 0 static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3909,185 +3961,216 @@ static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = load_reg(r2); } } +#define SPEC_in2_r2_nz 0 static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext8s_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_8s 0 static void in2_r2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext8u_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_8u 0 static void in2_r2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext16s_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_16s 0 static void in2_r2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_16u 0 static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r3)); } +#define SPEC_in2_r3 0 static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext32s_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_32s 0 static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_32u 0 static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_freg32_i64(get_field(f, r2)); } +#define SPEC_in2_e2 0 static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = fregs[get_field(f, r2)]; o->g_in2 = true; } +#define SPEC_in2_f2_o 0 static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int r2 = get_field(f, r2); o->in1 = fregs[r2]; - o->in2 = fregs[(r2 + 2) & 15]; + o->in2 = fregs[r2 + 2]; o->g_in1 = o->g_in2 = true; } +#define SPEC_in2_x2_o SPEC_r2_f128 static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = get_address(s, 0, get_field(f, r2), 0); } +#define SPEC_in2_ra2 0 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)); } +#define SPEC_in2_a2 0 static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); } +#define SPEC_in2_ri2 0 static void in2_sh32(DisasContext *s, DisasFields *f, DisasOps *o) { help_l2_shift(s, f, o, 31); } +#define SPEC_in2_sh32 0 static void in2_sh64(DisasContext *s, DisasFields *f, DisasOps *o) { help_l2_shift(s, f, o, 63); } +#define SPEC_in2_sh64 0 static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_8u 0 static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_16s 0 static void in2_m2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_16u 0 static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_32s 0 static void in2_m2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_32u 0 static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_64 0 static void in2_mri2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_16u 0 static void in2_mri2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_32s 0 static void in2_mri2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_32u 0 static void in2_mri2_64(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_64 0 static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64(get_field(f, i2)); } +#define SPEC_in2_i2 0 static void in2_i2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint8_t)get_field(f, i2)); } +#define SPEC_in2_i2_8u 0 static void in2_i2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint16_t)get_field(f, i2)); } +#define SPEC_in2_i2_16u 0 static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); } +#define SPEC_in2_i2_32u 0 static void in2_i2_16u_shl(DisasContext *s, DisasFields *f, DisasOps *o) { uint64_t i2 = (uint16_t)get_field(f, i2); o->in2 = tcg_const_i64(i2 << s->insn->data); } +#define SPEC_in2_i2_16u_shl 0 static void in2_i2_32u_shl(DisasContext *s, DisasFields *f, DisasOps *o) { uint64_t i2 = (uint32_t)get_field(f, i2); o->in2 = tcg_const_i64(i2 << s->insn->data); } +#define SPEC_in2_i2_32u_shl 0 /* ====================================================================== */ @@ -4106,18 +4189,19 @@ enum DisasInsnEnum { }; #undef D -#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \ - .opc = OPC, \ - .fmt = FMT_##FT, \ - .fac = FAC_##FC, \ - .name = #NM, \ - .help_in1 = in1_##I1, \ - .help_in2 = in2_##I2, \ - .help_prep = prep_##P, \ - .help_wout = wout_##W, \ - .help_cout = cout_##CC, \ - .help_op = op_##OP, \ - .data = D \ +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \ + .opc = OPC, \ + .fmt = FMT_##FT, \ + .fac = FAC_##FC, \ + .spec = SPEC_in1_##I1 | SPEC_in2_##I2 | SPEC_prep_##P | SPEC_wout_##W, \ + .name = #NM, \ + .help_in1 = in1_##I1, \ + .help_in2 = in2_##I2, \ + .help_prep = prep_##P, \ + .help_wout = wout_##W, \ + .help_cout = cout_##CC, \ + .help_op = op_##OP, \ + .data = D \ }, /* Allow 0 to be used for NULL in the table below. */ @@ -4128,6 +4212,11 @@ enum DisasInsnEnum { #define cout_0 NULL #define op_0 NULL +#define SPEC_in1_0 0 +#define SPEC_in2_0 0 +#define SPEC_prep_0 0 +#define SPEC_wout_0 0 + static const DisasInsn insn_info[] = { #include "insn-data.def" }; @@ -4295,6 +4384,40 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) return EXIT_NORETURN; } + /* Check for insn specification exceptions. */ + if (insn->spec) { + int spec = insn->spec, excp = 0, r; + + if (spec & SPEC_r1_even) { + r = get_field(&f, r1); + if (r & 1) { + excp = PGM_SPECIFICATION; + } + } + if (spec & SPEC_r2_even) { + r = get_field(&f, r2); + if (r & 1) { + excp = PGM_SPECIFICATION; + } + } + if (spec & SPEC_r1_f128) { + r = get_field(&f, r1); + if (r > 13) { + excp = PGM_SPECIFICATION; + } + } + if (spec & SPEC_r2_f128) { + r = get_field(&f, r2); + if (r > 13) { + excp = PGM_SPECIFICATION; + } + } + if (excp) { + gen_program_exception(s, excp); + return EXIT_NORETURN; + } + } + /* Set up the strutures we use to communicate with the helpers. */ s->insn = insn; s->fields = &f; From 1d1f63013539bccc877899116cccf106d318b04a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 9 Sep 2012 14:31:43 -0700 Subject: [PATCH 132/149] target-s390: Implement LCDFR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 1 + 1 file changed, 1 insertion(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b023911cec..6e92790c5e 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -356,6 +356,7 @@ C(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32) C(0xb313, LCDBR, RRE, Z, 0, f2_o, f1, 0, negf64, f64) C(0xb343, LCXBR, RRE, Z, 0, x2_o, x1, 0, negf128, f128) + C(0xb373, LCDFR, RRE, FPSSH, 0, f2_o, f1, 0, negf64, 0) /* LOAD HALFWORD */ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) From d2d9feac6fa9f6fd40e8f251bcfdd9a9a0f421f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 9 Sep 2012 16:04:17 -0700 Subject: [PATCH 133/149] target-s390: Use uint64_to_float128 Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 58c2e6135c..b6e5040ff5 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -419,8 +419,7 @@ uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { int hold = swap_round_mode(env, m3); - /* ??? Not 50% correct. */ - float128 ret = int64_to_float128(v2, &env->fpu_status); + float128 ret = uint64_to_float128(v2, &env->fpu_status); set_float_rounding_mode(hold, &env->fpu_status); handle_exceptions(env, GETPC()); return RET128(ret); From a12000b9ece917f62d6405e7ee83c8abb6ad7afa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Sep 2012 16:26:35 -0700 Subject: [PATCH 134/149] target-s390: Implement SET ROUNDING MODE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6e92790c5e..79341a4b41 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -566,6 +566,11 @@ C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) +/* SET BFP ROUNDING MODE */ + C(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0) + C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0) +/* SET DFP ROUNDING MODE */ + C(0xb2b9, SRNMT, S, DFP, 0, 0, 0, 0, srnm, 0) /* SHIFT LEFT SINGLE */ D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b4dd68e3f5..c4d9fffa21 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2921,6 +2921,45 @@ static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_srnm(DisasContext *s, DisasOps *o) +{ + int b2 = get_field(s->fields, b2); + int d2 = get_field(s->fields, d2); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + int mask, pos, len; + + switch (s->fields->op2) { + case 0x99: /* SRNM */ + pos = 0, len = 2; + break; + case 0xb8: /* SRNMB */ + pos = 0, len = 3; + break; + case 0xb9: /* SRNMT */ + pos = 4, len = 3; + default: + tcg_abort(); + } + mask = (1 << len) - 1; + + /* Insert the value into the appropriate field of the FPC. */ + if (b2 == 0) { + tcg_gen_movi_i64(t1, d2 & mask); + } else { + tcg_gen_addi_i64(t1, regs[b2], d2); + tcg_gen_andi_i64(t1, t1, mask); + } + tcg_gen_ld32u_i64(t2, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_deposit_i64(t2, t2, t1, pos, len); + tcg_temp_free_i64(t1); + + /* Then install the new FPC to set the rounding mode in fpu_status. */ + gen_helper_sfpc(cpu_env, t2); + tcg_temp_free_i64(t2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_spka(DisasContext *s, DisasOps *o) { From 411edc22cbab9a44f6d6c6cdef8637ba1f313e37 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Sep 2012 17:23:13 -0700 Subject: [PATCH 135/149] target-s390: Implement LOAD/SET FP AND SIGNAL Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 37 +++++++++++++++++++++++++++++-------- target-s390x/helper.h | 1 + target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 6 ++++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b6e5040ff5..94375b6a63 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -674,19 +674,40 @@ uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) return RET128(ret); } +static const int fpc_to_rnd[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + /* set fpc */ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) { - static const int rnd[4] = { - float_round_nearest_even, - float_round_to_zero, - float_round_up, - float_round_down - }; - /* Install everything in the main FPC. */ env->fpc = fpc; /* Install the rounding mode in the shadow fpu_status. */ - set_float_rounding_mode(rnd[fpc & 3], &env->fpu_status); + set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status); +} + +/* set fpc and signal */ +void HELPER(sfas)(CPUS390XState *env, uint64_t val) +{ + uint32_t signalling = env->fpc; + uint32_t source = val; + uint32_t s390_exc; + + /* The contents of the source operand are placed in the FPC register; + then the flags in the FPC register are set to the logical OR of the + signalling flags and the source flags. */ + env->fpc = source | (signalling & 0x00ff0000); + set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status); + + /* If any signalling flag is 1 and the corresponding source mask + is also 1, a simulated-iee-exception trap occurs. */ + s390_exc = (signalling >> 16) & (source >> 24); + if (s390_exc) { + ieee_exception(env, s390_exc | 3, GETPC()); + } } diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 23d23d5b3a..b7376339cd 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -87,6 +87,7 @@ DEF_HELPER_4(tr, void, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) #ifndef CONFIG_USER_ONLY diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 79341a4b41..e915984828 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -433,6 +433,8 @@ /* LOAD FPC */ C(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0) +/* LOAD FPC AND SIGNAL */ + C(0xb2bd, LFAS, S, IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0) /* LOAD LENGTHENED */ C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) @@ -566,6 +568,8 @@ C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) +/* SET FPC AND SIGNAL */ + C(0xb385, SFASR, RRE, IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0) /* SET BFP ROUNDING MODE */ C(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0) C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c4d9fffa21..34b9cdf127 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2921,6 +2921,12 @@ static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sfas(DisasContext *s, DisasOps *o) +{ + gen_helper_sfas(cpu_env, o->in2); + return NO_EXIT; +} + static ExitStatus op_srnm(DisasContext *s, DisasOps *o) { int b2 = get_field(s->fields, b2); From 90b4f8ad7226960d3a21bd8fca894ce1e6b5e4cf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Sep 2012 16:52:31 -0700 Subject: [PATCH 136/149] target-s390: Fix cpu_clone_regs R2 is the syscall return register, not R0. Signed-off-by: Richard Henderson --- target-s390x/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index dc7bbc67f6..bc3fab226b 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -116,7 +116,7 @@ static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) if (newsp) { env->regs[15] = newsp; } - env->regs[0] = 0; + env->regs[2] = 0; } #endif From d074ac6d266129f8f4e2aac5b0e6c39c22964d9a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Sep 2012 13:48:46 -0700 Subject: [PATCH 137/149] target-s390: Optimize XC Notice XC with same address and convert that to store of zero. Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 +- target-s390x/translate.c | 50 +++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e915984828..480f1fdf51 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -271,7 +271,7 @@ C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) - C(0xd700, XC, SS_a, Z, la1, a2, 0, 0, xc, 0) + C(0xd700, XC, SS_a, Z, 0, 0, 0, 0, xc, 0) /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 34b9cdf127..7f8a5503d9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3403,10 +3403,54 @@ static ExitStatus op_unpk(DisasContext *s, DisasOps *o) static ExitStatus op_xc(DisasContext *s, DisasOps *o) { - TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + int d1 = get_field(s->fields, d1); + int d2 = get_field(s->fields, d2); + int b1 = get_field(s->fields, b1); + int b2 = get_field(s->fields, b2); + int l = get_field(s->fields, l1); + TCGv_i32 t32; + + o->addr1 = get_address(s, 0, b1, d1); + + /* If the addresses are identical, this is a store/memset of zero. */ + if (b1 == b2 && d1 == d2 && (l + 1) <= 32) { + o->in2 = tcg_const_i64(0); + + l++; + while (l >= 8) { + tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s)); + l -= 8; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 8); + } + } + if (l >= 4) { + tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s)); + l -= 4; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 4); + } + } + if (l >= 2) { + tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s)); + l -= 2; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 2); + } + } + if (l) { + tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s)); + } + gen_op_movi_cc(s, 0); + return NO_EXIT; + } + + /* But in general we'll defer to a helper. */ + o->in2 = get_address(s, 0, b2, d2); + t32 = tcg_const_i32(l); potential_page_fault(s); - gen_helper_xc(cc_op, cpu_env, l, o->addr1, o->in2); - tcg_temp_free_i32(l); + gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2); + tcg_temp_free_i32(t32); set_cc_static(s); return NO_EXIT; } From f24c49c24a4979fe50eff7afe18f371f5809177d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Sep 2012 13:50:07 -0700 Subject: [PATCH 138/149] target-s390: Optmize emitting discards While they aren't expensive, they aren't free to process. When we know that the three cc helper variables are dead, don't kill them. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 7f8a5503d9..cfe3766e81 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -367,25 +367,41 @@ static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) return tmp; } +static inline bool live_cc_data(DisasContext *s) +{ + return (s->cc_op != CC_OP_DYNAMIC + && s->cc_op != CC_OP_STATIC + && s->cc_op > 3); +} + static inline void gen_op_movi_cc(DisasContext *s, uint32_t val) { + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_dst); + tcg_gen_discard_i64(cc_vr); + } s->cc_op = CC_OP_CONST0 + val; } static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst) { - tcg_gen_discard_i64(cc_src); + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_vr); + } tcg_gen_mov_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); s->cc_op = op; } static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, TCGv_i64 dst) { + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_vr); + } tcg_gen_mov_i64(cc_src, src); tcg_gen_mov_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); s->cc_op = op; } @@ -421,9 +437,11 @@ static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) /* CC value is in env->cc_op */ static void set_cc_static(DisasContext *s) { - tcg_gen_discard_i64(cc_src); - tcg_gen_discard_i64(cc_dst); - tcg_gen_discard_i64(cc_vr); + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_dst); + tcg_gen_discard_i64(cc_vr); + } s->cc_op = CC_OP_STATIC; } From de379661d5c7cc1d219000d0741f5d96ced56553 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 07:55:51 -0700 Subject: [PATCH 139/149] target-s390: Tidy comparisons After full conversion, we can audit the uses of LTGT cc ops and see that none of the instructions can ever set CC=3. Thus we can extend the table to treat that bit as ignored. This fixes a regression wrt the pre-conversion translation in which NE was used for both m=6 and m=7. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index cfe3766e81..2949bb1fc4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -577,30 +577,29 @@ static void account_inline_branch(DisasContext *s, int cc_op) } /* Table of mask values to comparison codes, given a comparison as input. - For a true comparison CC=3 will never be set, but we treat this - conservatively for possible use when CC=3 indicates overflow. */ + For such, CC=3 should not be possible. */ static const TCGCond ltgt_cond[16] = { TCG_COND_NEVER, TCG_COND_NEVER, /* | | | x */ - TCG_COND_GT, TCG_COND_NEVER, /* | | GT | x */ - TCG_COND_LT, TCG_COND_NEVER, /* | LT | | x */ - TCG_COND_NE, TCG_COND_NEVER, /* | LT | GT | x */ - TCG_COND_EQ, TCG_COND_NEVER, /* EQ | | | x */ - TCG_COND_GE, TCG_COND_NEVER, /* EQ | | GT | x */ - TCG_COND_LE, TCG_COND_NEVER, /* EQ | LT | | x */ + TCG_COND_GT, TCG_COND_GT, /* | | GT | x */ + TCG_COND_LT, TCG_COND_LT, /* | LT | | x */ + TCG_COND_NE, TCG_COND_NE, /* | LT | GT | x */ + TCG_COND_EQ, TCG_COND_EQ, /* EQ | | | x */ + TCG_COND_GE, TCG_COND_GE, /* EQ | | GT | x */ + TCG_COND_LE, TCG_COND_LE, /* EQ | LT | | x */ TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | LT | GT | x */ }; /* Table of mask values to comparison codes, given a logic op as input. For such, only CC=0 and CC=1 should be possible. */ static const TCGCond nz_cond[16] = { - /* | | x | x */ - TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, - /* | NE | x | x */ - TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, - /* EQ | | x | x */ - TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, - /* EQ | NE | x | x */ - TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, + TCG_COND_NEVER, TCG_COND_NEVER, /* | | x | x */ + TCG_COND_NEVER, TCG_COND_NEVER, + TCG_COND_NE, TCG_COND_NE, /* | NE | x | x */ + TCG_COND_NE, TCG_COND_NE, + TCG_COND_EQ, TCG_COND_EQ, /* EQ | | x | x */ + TCG_COND_EQ, TCG_COND_EQ, + TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | NE | x | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, }; /* Interpret MASK in terms of S->CC_OP, and fill in C with all the @@ -1463,9 +1462,7 @@ static ExitStatus op_cj(DisasContext *s, DisasOps *o) bool is_imm; DisasCompare c; - /* Bit 3 of the m3 field is reserved and should be zero. - Choose to ignore it wrt the ltgt_cond table above. */ - c.cond = ltgt_cond[m3 & 14]; + c.cond = ltgt_cond[m3]; if (s->insn->data) { c.cond = tcg_unsigned_cond(c.cond); } @@ -1831,9 +1828,7 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o) TCGv_i32 t; TCGCond c; - /* Bit 3 of the m3 field is reserved and should be zero. - Choose to ignore it wrt the ltgt_cond table above. */ - c = tcg_invert_cond(ltgt_cond[m3 & 14]); + c = tcg_invert_cond(ltgt_cond[m3]); if (s->insn->data) { c = tcg_unsigned_cond(c); } From a359b770c60bf3085c244bc9d5a5fd8fcf286bce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 09:41:33 -0700 Subject: [PATCH 140/149] target-s390: Optimize ADDU/SUBU CC testing We can easily generate some masks for logical add/subtract inline. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2949bb1fc4..04001e34d4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -692,6 +692,49 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) account_inline_branch(s, old_cc_op); break; + case CC_OP_ADDU_32: + case CC_OP_ADDU_64: + switch (mask) { + case 8 | 2: /* vr == 0 */ + cond = TCG_COND_EQ; + break; + case 4 | 1: /* vr != 0 */ + cond = TCG_COND_NE; + break; + case 8 | 4: /* no carry -> vr >= src */ + cond = TCG_COND_GEU; + break; + case 2 | 1: /* carry -> vr < src */ + cond = TCG_COND_LTU; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_SUBU_32: + case CC_OP_SUBU_64: + /* Note that CC=0 is impossible; treat it as dont-care. */ + switch (mask & 7) { + case 2: /* zero -> op1 == op2 */ + cond = TCG_COND_EQ; + break; + case 4 | 1: /* !zero -> op1 != op2 */ + cond = TCG_COND_NE; + break; + case 4: /* borrow (!carry) -> op1 < op2 */ + cond = TCG_COND_LTU; + break; + case 2 | 1: /* !borrow (carry) -> op1 >= op2 */ + cond = TCG_COND_GEU; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + default: do_dynamic: /* Calculate cc value. */ @@ -719,6 +762,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) break; case CC_OP_LTGT_32: case CC_OP_LTUGTU_32: + case CC_OP_SUBU_32: c->is_64 = false; c->u.s32.a = tcg_temp_new_i32(); tcg_gen_trunc_i64_i32(c->u.s32.a, cc_src); @@ -735,6 +779,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) break; case CC_OP_LTGT_64: case CC_OP_LTUGTU_64: + case CC_OP_SUBU_64: c->u.s64.a = cc_src; c->u.s64.b = cc_dst; c->g1 = c->g2 = true; @@ -748,6 +793,29 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); break; + case CC_OP_ADDU_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_vr); + if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { + tcg_gen_movi_i32(c->u.s32.b, 0); + } else { + tcg_gen_trunc_i64_i32(c->u.s32.b, cc_src); + } + break; + + case CC_OP_ADDU_64: + c->u.s64.a = cc_vr; + c->g1 = true; + if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { + c->u.s64.b = tcg_const_i64(0); + } else { + c->u.s64.b = cc_src; + c->g2 = true; + } + break; + case CC_OP_STATIC: c->is_64 = false; c->u.s32.a = cc_op; From c95ec459c6c39b7a7e1850f82abd95eca4ccfcce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 09:51:40 -0700 Subject: [PATCH 141/149] target-s390: Optimize ADDC/SUBB Giving the proper mask to disas_jcc allows us to generate an inline comparison generating the carry/borrow with setcond. In the very worst case, when we must use the external helper to compute a value for CC, we generate (cc > 1) instead of (cc >> 1), which is only very slightly slower on common cpus. In the very best case, when the CC comes from a COMPARE insn and the compiler is using ALCG with zero, everything folds out to become just the setcond that the compiler wanted. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 56 ++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 04001e34d4..8d293d3be5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1344,18 +1344,28 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) static ExitStatus op_addc(DisasContext *s, DisasOps *o) { - TCGv_i64 cc; + DisasCompare cmp; + TCGv_i64 carry; tcg_gen_add_i64(o->out, o->in1, o->in2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - cc = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(cc, cc_op); - tcg_gen_shri_i64(cc, cc, 1); + /* The carry flag is the msb of CC, therefore the branch mask that would + create that comparison is 3. Feeding the generated comparison to + setcond produces the carry flag that we desire. */ + disas_jcc(s, &cmp, 3); + carry = tcg_temp_new_i64(); + if (cmp.is_64) { + tcg_gen_setcond_i64(cmp.cond, carry, cmp.u.s64.a, cmp.u.s64.b); + } else { + TCGv_i32 t = tcg_temp_new_i32(); + tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); + tcg_gen_extu_i32_i64(carry, t); + tcg_temp_free_i32(t); + } + free_compare(&cmp); - tcg_gen_add_i64(o->out, o->out, cc); - tcg_temp_free_i64(cc); + tcg_gen_add_i64(o->out, o->out, carry); + tcg_temp_free_i64(carry); return NO_EXIT; } @@ -3397,19 +3407,27 @@ static ExitStatus op_sub(DisasContext *s, DisasOps *o) static ExitStatus op_subb(DisasContext *s, DisasOps *o) { - TCGv_i64 cc; + DisasCompare cmp; + TCGv_i64 borrow; - assert(!o->g_in2); - tcg_gen_not_i64(o->in2, o->in2); - tcg_gen_add_i64(o->out, o->in1, o->in2); + tcg_gen_sub_i64(o->out, o->in1, o->in2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - cc = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(cc, cc_op); - tcg_gen_shri_i64(cc, cc, 1); - tcg_gen_add_i64(o->out, o->out, cc); - tcg_temp_free_i64(cc); + /* The !borrow flag is the msb of CC. Since we want the inverse of + that, we ask for a comparison of CC=0 | CC=1 -> mask of 8 | 4. */ + disas_jcc(s, &cmp, 8 | 4); + borrow = tcg_temp_new_i64(); + if (cmp.is_64) { + tcg_gen_setcond_i64(cmp.cond, borrow, cmp.u.s64.a, cmp.u.s64.b); + } else { + TCGv_i32 t = tcg_temp_new_i32(); + tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); + tcg_gen_extu_i32_i64(borrow, t); + tcg_temp_free_i32(t); + } + free_compare(&cmp); + + tcg_gen_sub_i64(o->out, o->out, borrow); + tcg_temp_free_i64(borrow); return NO_EXIT; } From bacf43c62e54ee21494c4bf0c39d96d2bcc0e260 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Sep 2012 06:57:09 -0700 Subject: [PATCH 142/149] target-s390: Optimize get_address Don't load the displacement into a register first, add it second so that tcg_gen_addi_i64 can eliminate zeros. Don't mask the displacement first so that we don't turn small negative numbers into large positive numbers. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 44 ++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8d293d3be5..0ad78d2eb4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -331,37 +331,29 @@ static inline void check_privileged(DisasContext *s) static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { - TCGv_i64 tmp; + TCGv_i64 tmp = tcg_temp_new_i64(); + bool need_31 = !(s->tb->flags & FLAG_MASK_64); - /* 31-bitify the immediate part; register contents are dealt with below */ - if (!(s->tb->flags & FLAG_MASK_64)) { - d2 &= 0x7fffffffUL; - } + /* Note that d2 is limited to 20 bits, signed. If we crop negative + displacements early we create larger immedate addends. */ - if (x2) { - if (d2) { - tmp = tcg_const_i64(d2); - tcg_gen_add_i64(tmp, tmp, regs[x2]); - } else { - tmp = load_reg(x2); - } - if (b2) { - tcg_gen_add_i64(tmp, tmp, regs[b2]); - } + /* Note that addi optimizes the imm==0 case. */ + if (b2 && x2) { + tcg_gen_add_i64(tmp, regs[b2], regs[x2]); + tcg_gen_addi_i64(tmp, tmp, d2); } else if (b2) { - if (d2) { - tmp = tcg_const_i64(d2); - tcg_gen_add_i64(tmp, tmp, regs[b2]); - } else { - tmp = load_reg(b2); - } + tcg_gen_addi_i64(tmp, regs[b2], d2); + } else if (x2) { + tcg_gen_addi_i64(tmp, regs[x2], d2); } else { - tmp = tcg_const_i64(d2); + if (need_31) { + d2 &= 0x7fffffff; + need_31 = false; + } + tcg_gen_movi_i64(tmp, d2); } - - /* 31-bit mode mask if there are values loaded from registers */ - if (!(s->tb->flags & FLAG_MASK_64) && (x2 || b2)) { - tcg_gen_andi_i64(tmp, tmp, 0x7fffffffUL); + if (need_31) { + tcg_gen_andi_i64(tmp, tmp, 0x7fffffff); } return tmp; From b7886de3f36111b71ee0664a0b992f6c5b55de7d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 17:09:35 -0700 Subject: [PATCH 143/149] target-s390: Perform COMPARE AND SWAP inline Still no proper solution for CONFIG_USER_ONLY, but the system version is significantly better. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 3 - target-s390x/insn-data.def | 12 +-- target-s390x/mem_helper.c | 53 ------------- target-s390x/translate.c | 152 ++++++++++++++++++++++++++++--------- 4 files changed, 124 insertions(+), 96 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index b7376339cd..a5844b3ee0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -17,9 +17,6 @@ DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) DEF_HELPER_4(mvst, i64, env, i64, i64, i64) -DEF_HELPER_4(csg, i64, env, i64, i64, i64) -DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) -DEF_HELPER_4(cs, i64, env, i64, i64, i64) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 480f1fdf51..b42ebb6a1a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -193,13 +193,13 @@ D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) /* COMPARE AND SWAP */ - C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) - C(0xeb14, CSY, RSY_a, LD, r1_o, a2, new, r1_32, cs, 0) - C(0xeb30, CSG, RSY_a, Z, r1_o, a2, r1, 0, csg, 0) + D(0xba00, CS, RS_a, Z, r3_32u, r1_32u, new, r1_32, cs, 0, 0) + D(0xeb14, CSY, RSY_a, LD, r3_32u, r1_32u, new, r1_32, cs, 0, 0) + D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, 1) /* COMPARE DOUBLE AND SWAP */ - C(0xbb00, CDS, RS_a, Z, r1_D32, a2, new, r1_D32, cds, 0) - C(0xeb31, CDSY, RSY_a, LD, r1_D32, a2, new, r1_D32, cds, 0) - C(0xeb3e, CDSG, RSY_a, Z, 0, a2, 0, 0, cdsg, 0) + D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, 1) + D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, 1) + C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0) /* COMPARE AND TRAP */ D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 0e9bbd4035..372334b3c8 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -442,59 +442,6 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) return d + len; } -/* compare and swap 64-bit */ -uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) -{ - /* FIXME: locking? */ - uint64_t v2 = cpu_ldq_data(env, a2); - if (r1 == v2) { - cpu_stq_data(env, a2, r3); - env->cc_op = 0; - return r1; - } else { - env->cc_op = 1; - return v2; - } -} - -/* compare double and swap 64-bit */ -uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2_hi = cpu_ldq_data(env, a2); - uint64_t v2_lo = cpu_ldq_data(env, a2 + 8); - uint64_t v1_hi = env->regs[r1]; - uint64_t v1_lo = env->regs[r1 + 1]; - - if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { - cc = 0; - cpu_stq_data(env, a2, env->regs[r3]); - cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]); - } else { - cc = 1; - env->regs[r1] = v2_hi; - env->regs[r1 + 1] = v2_lo; - } - - return cc; -} - -/* compare and swap 32-bit */ -uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) -{ - /* FIXME: locking? */ - uint32_t v2 = cpu_ldl_data(env, a2); - if ((uint32_t)r1 == v2) { - cpu_stl_data(env, a2, (uint32_t)r3); - env->cc_op = 0; - return r1; - } else { - env->cc_op = 1; - return v2; - } -} - static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, uint32_t mask) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0ad78d2eb4..a57296c64f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1078,8 +1078,9 @@ typedef struct { #define SPEC_r1_even 1 #define SPEC_r2_even 2 -#define SPEC_r1_f128 4 -#define SPEC_r2_f128 8 +#define SPEC_r3_even 4 +#define SPEC_r1_f128 8 +#define SPEC_r2_f128 16 /* Return values from translate_one, indicating the state of the TB. */ typedef enum { @@ -1124,9 +1125,9 @@ typedef enum DisasFacility { struct DisasInsn { unsigned opc:16; - DisasFormat fmt:6; - DisasFacility fac:6; - unsigned spec:4; + DisasFormat fmt:8; + DisasFacility fac:8; + unsigned spec:8; const char *name; @@ -1828,18 +1829,102 @@ static ExitStatus op_cps(DisasContext *s, DisasOps *o) static ExitStatus op_cs(DisasContext *s, DisasOps *o) { - int r3 = get_field(s->fields, r3); - potential_page_fault(s); - gen_helper_cs(o->out, cpu_env, o->in1, o->in2, regs[r3]); + /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */ + int d2 = get_field(s->fields, d2); + int b2 = get_field(s->fields, b2); + int is_64 = s->insn->data; + TCGv_i64 addr, mem, cc, z; + + /* Note that in1 = R3 (new value) and + in2 = (zero-extended) R1 (expected value). */ + + /* Load the memory into the (temporary) output. While the PoO only talks + about moving the memory to R1 on inequality, if we include equality it + means that R1 is equal to the memory in all conditions. */ + addr = get_address(s, 0, b2, d2); + if (is_64) { + tcg_gen_qemu_ld64(o->out, addr, get_mem_index(s)); + } else { + tcg_gen_qemu_ld32u(o->out, addr, get_mem_index(s)); + } + + /* Are the memory and expected values (un)equal? Note that this setcond + produces the output CC value, thus the NE sense of the test. */ + cc = tcg_temp_new_i64(); + tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in2, o->out); + + /* If the memory and expected values are equal (CC==0), copy R3 to MEM. + Recall that we are allowed to unconditionally issue the store (and + thus any possible write trap), so (re-)store the original contents + of MEM in case of inequality. */ + z = tcg_const_i64(0); + mem = tcg_temp_new_i64(); + tcg_gen_movcond_i64(TCG_COND_EQ, mem, cc, z, o->in1, o->out); + if (is_64) { + tcg_gen_qemu_st64(mem, addr, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(mem, addr, get_mem_index(s)); + } + tcg_temp_free_i64(z); + tcg_temp_free_i64(mem); + tcg_temp_free_i64(addr); + + /* Store CC back to cc_op. Wait until after the store so that any + exception gets the old cc_op value. */ + tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_temp_free_i64(cc); set_cc_static(s); return NO_EXIT; } -static ExitStatus op_csg(DisasContext *s, DisasOps *o) +static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) { + /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */ + int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - potential_page_fault(s); - gen_helper_csg(o->out, cpu_env, o->in1, o->in2, regs[r3]); + int d2 = get_field(s->fields, d2); + int b2 = get_field(s->fields, b2); + TCGv_i64 addrh, addrl, memh, meml, outh, outl, cc, z; + + /* Note that R1:R1+1 = expected value and R3:R3+1 = new value. */ + + addrh = get_address(s, 0, b2, d2); + addrl = get_address(s, 0, b2, d2 + 8); + outh = tcg_temp_new_i64(); + outl = tcg_temp_new_i64(); + + tcg_gen_qemu_ld64(outh, addrh, get_mem_index(s)); + tcg_gen_qemu_ld64(outl, addrl, get_mem_index(s)); + + /* Fold the double-word compare with arithmetic. */ + cc = tcg_temp_new_i64(); + z = tcg_temp_new_i64(); + tcg_gen_xor_i64(cc, outh, regs[r1]); + tcg_gen_xor_i64(z, outl, regs[r1 + 1]); + tcg_gen_or_i64(cc, cc, z); + tcg_gen_movi_i64(z, 0); + tcg_gen_setcond_i64(TCG_COND_NE, cc, cc, z); + + memh = tcg_temp_new_i64(); + meml = tcg_temp_new_i64(); + tcg_gen_movcond_i64(TCG_COND_EQ, memh, cc, z, regs[r3], outh); + tcg_gen_movcond_i64(TCG_COND_EQ, meml, cc, z, regs[r3 + 1], outl); + tcg_temp_free_i64(z); + + tcg_gen_qemu_st64(memh, addrh, get_mem_index(s)); + tcg_gen_qemu_st64(meml, addrl, get_mem_index(s)); + tcg_temp_free_i64(memh); + tcg_temp_free_i64(meml); + tcg_temp_free_i64(addrh); + tcg_temp_free_i64(addrl); + + /* Save back state now that we've passed all exceptions. */ + tcg_gen_mov_i64(regs[r1], outh); + tcg_gen_mov_i64(regs[r1 + 1], outl); + tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_temp_free_i64(outh); + tcg_temp_free_i64(outl); + tcg_temp_free_i64(cc); set_cc_static(s); return NO_EXIT; } @@ -1856,29 +1941,6 @@ static ExitStatus op_csp(DisasContext *s, DisasOps *o) } #endif -static ExitStatus op_cds(DisasContext *s, DisasOps *o) -{ - int r3 = get_field(s->fields, r3); - TCGv_i64 in3 = tcg_temp_new_i64(); - tcg_gen_deposit_i64(in3, regs[r3 + 1], regs[r3], 32, 32); - potential_page_fault(s); - gen_helper_csg(o->out, cpu_env, o->in1, o->in2, in3); - tcg_temp_free_i64(in3); - set_cc_static(s); - return NO_EXIT; -} - -static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) -{ - TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); - TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_cdsg(cc_op, cpu_env, r1, o->in2, r3); - set_cc_static(s); - return NO_EXIT; -} - static ExitStatus op_cvd(DisasContext *s, DisasOps *o) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -4007,6 +4069,14 @@ static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in1_r3_32u 0 +static void in1_r3_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r3 = get_field(f, r3); + o->in1 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in1, regs[r3 + 1], regs[r3]); +} +#define SPEC_in1_r3_D32 SPEC_r3_even + static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_freg32_i64(get_field(f, r1)); @@ -4121,6 +4191,14 @@ static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in2_r1_32u 0 +static void in2_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + o->in2 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in2, regs[r1 + 1], regs[r1]); +} +#define SPEC_in2_r1_D32 SPEC_r1_even + static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r2)); @@ -4580,6 +4658,12 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) excp = PGM_SPECIFICATION; } } + if (spec & SPEC_r3_even) { + r = get_field(&f, r3); + if (r & 1) { + excp = PGM_SPECIFICATION; + } + } if (spec & SPEC_r1_f128) { r = get_field(&f, r1); if (r > 13) { From d918a65c690c321f56e7ce4b5a9e1f2fbe32bb1b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:20:43 -0800 Subject: [PATCH 144/149] target-s390: Use TCG_CALL_NO_WG for memory helpers Those that do not read or write tcg registers, but can raise exceptions via memory faults. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index a5844b3ee0..e9664fa304 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,13 +1,13 @@ #include "exec/def-helper.h" DEF_HELPER_2(exception, void, env, i32) -DEF_HELPER_4(nc, i32, env, i32, i64, i64) -DEF_HELPER_4(oc, i32, env, i32, i64, i64) -DEF_HELPER_4(xc, i32, env, i32, i64, i64) -DEF_HELPER_4(mvc, void, env, i32, i64, i64) -DEF_HELPER_4(clc, i32, env, i32, i64, i64) +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(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) -DEF_HELPER_4(clm, i32, env, i32, i32, i64) +DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_3(divs32, s64, env, s64, s64) DEF_HELPER_3(divu32, i64, env, i64, i64) @@ -22,8 +22,8 @@ DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) -DEF_HELPER_4(stam, void, env, i32, i64, i32) -DEF_HELPER_4(lam, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32) @@ -79,8 +79,8 @@ DEF_HELPER_2(sqeb, i64, env, i64) DEF_HELPER_2(sqdb, i64, env, i64) DEF_HELPER_3(sqxb, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) -DEF_HELPER_4(unpk, void, env, i32, i64, i64) -DEF_HELPER_4(tr, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) @@ -98,10 +98,10 @@ DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_4(stsi, i32, env, i64, i64, i64) -DEF_HELPER_4(lctl, void, env, i32, i64, i32) -DEF_HELPER_4(lctlg, void, env, i32, i64, i32) -DEF_HELPER_4(stctl, void, env, i32, i64, i32) -DEF_HELPER_4(stctg, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) @@ -114,7 +114,7 @@ DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) -DEF_HELPER_3(stura, void, env, i64, i64) +DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64) #endif #include "exec/def-helper.h" From c482ea94eaf26761e5cc0e53259cf1a98db29622 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:21:54 -0800 Subject: [PATCH 145/149] target-s390: Use TCG_CALL_NO_WG for floating-point helpers None of them read or write tcg registers, but most can raise fp exceptions. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index e9664fa304..77f8f7d76b 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -32,52 +32,52 @@ DEF_HELPER_3(cxgb, i64, env, s64, i32) DEF_HELPER_3(celgb, i64, env, i64, i32) DEF_HELPER_3(cdlgb, i64, env, i64, i32) DEF_HELPER_3(cxlgb, i64, env, i64, i32) -DEF_HELPER_3(aeb, i64, env, i64, i64) -DEF_HELPER_3(adb, i64, env, i64, i64) -DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(seb, i64, env, i64, i64) -DEF_HELPER_3(sdb, i64, env, i64, i64) -DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(deb, i64, env, i64, i64) -DEF_HELPER_3(ddb, i64, env, i64, i64) -DEF_HELPER_5(dxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(meeb, i64, env, i64, i64) -DEF_HELPER_3(mdeb, i64, env, i64, i64) -DEF_HELPER_3(mdb, i64, env, i64, i64) -DEF_HELPER_5(mxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_4(mxdb, i64, env, i64, i64, i64) -DEF_HELPER_2(ldeb, i64, env, i64) -DEF_HELPER_3(ldxb, i64, env, i64, i64) -DEF_HELPER_2(lxdb, i64, env, i64) -DEF_HELPER_2(lxeb, i64, env, i64) -DEF_HELPER_2(ledb, i64, env, i64) -DEF_HELPER_3(lexb, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(aeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(adb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(axb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(seb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(sdb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(sxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(deb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(ddb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(dxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(meeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mdeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_2(ldeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(ledb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(lexb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) -DEF_HELPER_3(cgeb, i64, env, i64, i32) -DEF_HELPER_3(cgdb, i64, env, i64, i32) -DEF_HELPER_4(cgxb, i64, env, i64, i64, i32) -DEF_HELPER_3(cfeb, i64, env, i64, i32) -DEF_HELPER_3(cfdb, i64, env, i64, i32) -DEF_HELPER_4(cfxb, i64, env, i64, i64, i32) -DEF_HELPER_3(clgeb, i64, env, i64, i32) -DEF_HELPER_3(clgdb, i64, env, i64, i32) -DEF_HELPER_4(clgxb, i64, env, i64, i64, i32) -DEF_HELPER_3(clfeb, i64, env, i64, i32) -DEF_HELPER_3(clfdb, i64, env, i64, i32) -DEF_HELPER_4(clfxb, i64, env, i64, i64, i32) -DEF_HELPER_4(maeb, i64, env, i64, i64, i64) -DEF_HELPER_4(madb, i64, env, i64, i64, i64) -DEF_HELPER_4(mseb, i64, env, i64, i64, i64) -DEF_HELPER_4(msdb, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(cfeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(cfdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(cfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(clgeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(clgdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(msdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_2(sqeb, i64, env, i64) -DEF_HELPER_2(sqdb, i64, env, i64) -DEF_HELPER_3(sqxb, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) From c20fec4055f06de6d96789d1a290f284fac48fc4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:25:57 -0800 Subject: [PATCH 146/149] target-s390: Use TCG_CALL_NO_WG for integer helpers The division routines do not read or write tcg registers, but can raise fixed-point divide exceptions. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 77f8f7d76b..f5dabb701e 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -9,10 +9,10 @@ DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_3(divs32, s64, env, s64, s64) -DEF_HELPER_3(divu32, i64, env, i64, i64) -DEF_HELPER_3(divs64, s64, env, s64, s64) -DEF_HELPER_4(divu64, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64) +DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) +DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) From 893e1660d5b9be0900bb1f09e574b1856eb30783 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:31:29 -0800 Subject: [PATCH 147/149] target-s390: Use TCG_CALL_NO_WG for misc helpers Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index f5dabb701e..dea7071d84 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -110,7 +110,7 @@ DEF_HELPER_3(csp, i32, env, i32, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) -DEF_HELPER_2(sacf, void, env, i64) +DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) From 26cc0a3fd11d537bdd2649b5f3c385ad858b1857 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:32:25 -0800 Subject: [PATCH 148/149] target-s390: Use noreturn for exception and load_psw Both always exit the cpu loop. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index dea7071d84..dd90d93bee 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,6 +1,6 @@ #include "exec/def-helper.h" -DEF_HELPER_2(exception, void, env, i32) +DEF_HELPER_2(exception, noreturn, env, i32) 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) @@ -90,7 +90,7 @@ DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) -DEF_HELPER_3(load_psw, void, env, i64, i64) +DEF_HELPER_3(load_psw, noreturn, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) From 2b35e93fbfc52c2be6cf85e5a54a3707cdabd914 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Dec 2012 09:23:25 -0600 Subject: [PATCH 149/149] target-s390: Claim maintainership Signed-off-by: Richard Henderson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index cf39e5a00a..4b7553efea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -98,6 +98,7 @@ S: Maintained F: target-ppc/ S390 +M: Richard Henderson M: Alexander Graf S: Maintained F: target-s390x/