mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge branch 's390-reorg' of git://repo.or.cz/qemu/rth
* 's390-reorg' of git://repo.or.cz/qemu/rth: (149 commits) target-s390: Claim maintainership target-s390: Use noreturn for exception and load_psw target-s390: Use TCG_CALL_NO_WG for misc helpers target-s390: Use TCG_CALL_NO_WG for integer helpers target-s390: Use TCG_CALL_NO_WG for floating-point helpers target-s390: Use TCG_CALL_NO_WG for memory helpers target-s390: Perform COMPARE AND SWAP inline target-s390: Optimize get_address target-s390: Optimize ADDC/SUBB target-s390: Optimize ADDU/SUBU CC testing target-s390: Tidy comparisons target-s390: Optmize emitting discards target-s390: Optimize XC target-s390: Fix cpu_clone_regs target-s390: Implement LOAD/SET FP AND SIGNAL target-s390: Implement SET ROUNDING MODE target-s390: Use uint64_to_float128 target-s390: Implement LCDFR target-s390: Check insn operand specifications target-s390: Implement CPSDR ...
This commit is contained in:
@@ -98,6 +98,7 @@ S: Maintained
|
||||
F: target-ppc/
|
||||
|
||||
S390
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: target-s390x/
|
||||
|
||||
+154
-19
@@ -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 */
|
||||
};
|
||||
|
||||
@@ -663,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 */
|
||||
@@ -801,11 +813,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 +962,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 +1045,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 +1067,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 +1201,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 +1223,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 +1379,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 +1563,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 +1925,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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
+93
-49
@@ -2938,71 +2938,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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
+186
-159
File diff suppressed because it is too large
Load Diff
+52
-117
@@ -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;
|
||||
@@ -79,15 +82,15 @@ 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 */
|
||||
|
||||
int pending_int;
|
||||
ExtQueue ext_queue[MAX_EXT_QUEUE];
|
||||
int pending_int;
|
||||
|
||||
int ext_index;
|
||||
|
||||
@@ -113,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
|
||||
|
||||
@@ -253,25 +256,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 +361,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)
|
||||
@@ -430,79 +428,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 {
|
||||
@@ -524,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) */
|
||||
|
||||
@@ -542,14 +471,14 @@ 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_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_FLOGR, /* find leftmost one */
|
||||
CC_OP_MAX
|
||||
};
|
||||
|
||||
@@ -569,26 +498,31 @@ 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",
|
||||
[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_SLAG] = "CC_OP_SLAG",
|
||||
[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)
|
||||
@@ -605,9 +539,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 */
|
||||
@@ -991,12 +925,13 @@ 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 ilc);
|
||||
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
|
||||
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
|
||||
uintptr_t retaddr);
|
||||
|
||||
#endif
|
||||
|
||||
+421
-551
File diff suppressed because it is too large
Load Diff
+33
-34
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -479,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);
|
||||
|
||||
@@ -495,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);
|
||||
@@ -526,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);
|
||||
|
||||
+94
-126
@@ -1,152 +1,120 @@
|
||||
#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_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)
|
||||
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_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_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_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)
|
||||
DEF_HELPER_4(mvst, void, env, i32, i32, i32)
|
||||
DEF_HELPER_4(csg, i32, env, i32, i64, i32)
|
||||
DEF_HELPER_4(cdsg, i32, env, i32, i64, i32)
|
||||
DEF_HELPER_4(cs, i32, env, i32, i64, i32)
|
||||
DEF_HELPER_4(mvst, 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)
|
||||
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_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_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_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)
|
||||
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(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_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_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)
|
||||
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)
|
||||
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_3(flogr, i32, env, i32, i64)
|
||||
DEF_HELPER_3(sqdbr, void, env, i32, 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_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_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_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_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)
|
||||
DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64)
|
||||
DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
|
||||
DEF_HELPER_3(servc, i32, env, i32, 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_1(program_interrupt, void, i32)
|
||||
DEF_HELPER_FLAGS_2(stidp, TCG_CALL_NO_RWG, void, env, 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(sck, TCG_CALL_NO_RWG, i32, i64)
|
||||
DEF_HELPER_2(stck, i32, env, i64)
|
||||
DEF_HELPER_2(stcke, i32, 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)
|
||||
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)
|
||||
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_1(stpt, TCG_CALL_NO_RWG, i64, env)
|
||||
DEF_HELPER_4(stsi, i32, env, i64, i64, i64)
|
||||
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, i32, i64)
|
||||
DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_NO_RWG, i32, env, i32, i64)
|
||||
DEF_HELPER_3(csp, i32, env, i32, i32)
|
||||
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, 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_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)
|
||||
DEF_HELPER_2(lra, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
|
||||
#endif
|
||||
|
||||
#include "exec/def-helper.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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))
|
||||
+90
-86
@@ -30,46 +30,97 @@
|
||||
#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];
|
||||
uint64_t reth;
|
||||
mulu64(&env->retxl, &reth, v1, v2);
|
||||
return reth;
|
||||
}
|
||||
|
||||
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
|
||||
/* 64/32 -> 32 signed division */
|
||||
int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
|
||||
{
|
||||
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 b64)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 128 -> 64/64 unsigned division */
|
||||
void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2)
|
||||
uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
|
||||
uint64_t b)
|
||||
{
|
||||
uint64_t divisor = v2;
|
||||
|
||||
if (!env->regs[r1]) {
|
||||
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->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;
|
||||
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. */
|
||||
cpu_abort(env, "128 -> 64/64 division not implemented\n");
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* absolute value 32-bit */
|
||||
@@ -114,69 +165,10 @@ 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)
|
||||
/* count leading zeros, for find leftmost one */
|
||||
uint64_t HELPER(clz)(uint64_t v)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@@ -199,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;
|
||||
}
|
||||
|
||||
+117
-238
@@ -304,214 +304,142 @@ 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)
|
||||
static inline uint64_t fix_address(CPUS390XState *env, uint64_t a)
|
||||
{
|
||||
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;
|
||||
/* 31-Bit mode */
|
||||
if (!(env->psw.mask & PSW_MASK_64)) {
|
||||
a &= 0x7fffffff;
|
||||
}
|
||||
HELPER_LOG("\n");
|
||||
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) */
|
||||
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) */
|
||||
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 */
|
||||
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
|
||||
}
|
||||
|
||||
/* 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! */
|
||||
}
|
||||
|
||||
/* compare and swap 64-bit */
|
||||
uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_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]);
|
||||
} else {
|
||||
cc = 1;
|
||||
env->regs[r1] = v2;
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_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]);
|
||||
} else {
|
||||
cc = 1;
|
||||
env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
|
||||
}
|
||||
return cc;
|
||||
/* Incomplete. Set CC=3 and signal to advance R1 and R2. */
|
||||
env->cc_op = 3;
|
||||
env->retxl = s + len;
|
||||
return d + len;
|
||||
}
|
||||
|
||||
static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
|
||||
@@ -594,7 +522,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;
|
||||
@@ -613,55 +541,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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@@ -822,42 +701,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,
|
||||
@@ -1007,7 +893,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);
|
||||
|
||||
@@ -1019,7 +905,7 @@ void HELPER(sske)(CPUS390XState *env, uint32_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;
|
||||
@@ -1045,16 +931,16 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, 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);
|
||||
}
|
||||
@@ -1154,13 +1040,13 @@ 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 */
|
||||
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;
|
||||
@@ -1184,14 +1070,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
|
||||
|
||||
+38
-56
@@ -41,7 +41,27 @@
|
||||
#define HELPER_LOG(x...)
|
||||
#endif
|
||||
|
||||
/* raise an exception */
|
||||
/* 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)
|
||||
{
|
||||
HELPER_LOG("%s: exception %d\n", __func__, excp);
|
||||
@@ -50,7 +70,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,18 +81,16 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@@ -105,38 +123,22 @@ 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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@@ -148,32 +150,14 @@ 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
return clock_value(env);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@@ -187,17 +171,15 @@ 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 */
|
||||
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;
|
||||
}
|
||||
@@ -209,15 +191,15 @@ 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 */
|
||||
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;
|
||||
|
||||
+4255
-4614
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user