s390x update:
- tcg: implement the vector enhancements facility and bump the 'qemu' cpu model to a stripped-down z14 GA2 - fix psw.mask handling in signals - fix vfio-ccw sense data handling -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAmDQYXwSHGNvaHVja0By ZWRoYXQuY29tAAoJEN7Pa5PG8C+vrDAQALLimgzAm6br4SHP49T7ZsDkuhZwyYpP Fg09vxjMmKWgLOIQNp7Xd1vQJ5voGc5D0KleVMuX2feycfmon0yVeIBMan6DTcfr lygtiBYrgPWVAs36OXQ/rJUHt2ZUZaQsS57lTgn+Jtn7p+AMjiMrDlam+iqoAnU+ o5RtTFG+bhqa72WI7mCG54hRfXS1b/K8Ts1qs0oJJVDrDWlmLWfpjuJU3ehvhepA hJYnhIRQgbFHPsaJI47s25aa6KC+cGTGGRMl4YmFPACMh1KNXqmGP1XbxyEhz5tl LUdU9JRikbBsErcItHfZabGktLtBi7B9Vyh9KhxG9vK7ol8GUD4pomHrLNH2UUtH MyhTcuVCcEakuhgRr8GwA+7KO2Y3quqHDC3/kCkIarrE4X+YJl9Glv76we6XvbYL 4SAPE87Ub465C3J3tUjLDtfq8LpCIUh7zCYLBfk2Yf4pIbjnWMzUBu3UD2XYrKGF +g+J8ZVjE/WFsZzWUJL54lLuT8+FjPLgNOsth1WTENGUEK+JgWGpHbpR1XdqQFj8 f+bk1nrL94iq3KRdmCaO1w6vc+5xDG0tSY4tVJ1Nip1w3ZxmJFOUWGWLs04hz4mn WLx3vHbq3g1HZn9dtqwh6BvAP9fdLw2xkBcRtepR7vPM0ydqp2dvBbu99MrZN3H1 3Sa6lIpr4bII =bMQp -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck-gitlab/tags/s390x-20210621' into staging s390x update: - tcg: implement the vector enhancements facility and bump the 'qemu' cpu model to a stripped-down z14 GA2 - fix psw.mask handling in signals - fix vfio-ccw sense data handling # gpg: Signature made Mon 21 Jun 2021 10:53:00 BST # gpg: using RSA key C3D0D66DC3624FF6A8C018CEDECF6B93C6F02FAF # gpg: issuer "cohuck@redhat.com" # gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" [unknown] # gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" [full] # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" [full] # gpg: aka "Cornelia Huck <cohuck@kernel.org>" [unknown] # gpg: aka "Cornelia Huck <cohuck@redhat.com>" [unknown] # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * remotes/cohuck-gitlab/tags/s390x-20210621: (37 commits) s390x/css: Add passthrough IRB s390x/css: Refactor IRB construction s390x/css: Split out the IRB sense data s390x/css: Introduce an ESW struct linux-user/s390x: Save and restore psw.mask properly target/s390x: Use s390_cpu_{set_psw, get_psw_mask} in gdbstub target/s390x: Improve s390_cpu_dump_state vs cc_op target/s390x: Do not modify cpu state in s390_cpu_get_psw_mask target/s390x: Expose load_psw and get_psw_mask to cpu.h configure: Check whether we can compile the s390-ccw bios with -msoft-float s390x/cpumodel: Bump up QEMU model to a stripped-down IBM z14 GA2 s390x/tcg: We support Vector enhancements facility linux-user: elf: s390x: Prepare for Vector enhancements facility s390x/tcg: Implement VECTOR FP (MAXIMUM|MINIMUM) s390x/tcg: Implement VECTOR FP NEGATIVE MULTIPLY AND (ADD|SUBTRACT) s390x/tcg: Implement 32/128 bit for VECTOR FP MULTIPLY AND (ADD|SUBTRACT) s390x/tcg: Implement 32/128 bit for VECTOR FP TEST DATA CLASS IMMEDIATE s390x/tcg: Implement 32/128 bit for VECTOR FP PERFORM SIGN OPERATION s390x/tcg: Implement 128 bit for VECTOR FP LOAD ROUNDED s390x/tcg: Implement 64 bit for VECTOR FP LOAD LENGTHENED ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
bf7942e406
2
configure
vendored
2
configure
vendored
@ -5424,7 +5424,7 @@ if test "$cpu" = "s390x" ; then
|
||||
write_c_skeleton
|
||||
compile_prog "-march=z900" ""
|
||||
has_z900=$?
|
||||
if [ $has_z900 = 0 ] || compile_prog "-march=z10" ""; then
|
||||
if [ $has_z900 = 0 ] || compile_object "-march=z10 -msoft-float -Werror"; then
|
||||
if [ $has_z900 != 0 ]; then
|
||||
echo "WARNING: Your compiler does not support the z900!"
|
||||
echo " The s390-ccw bios will only work with guest CPUs >= z10."
|
||||
|
@ -129,6 +129,7 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
|
||||
EMULATED_CCW_3270_CHPID_TYPE);
|
||||
sch->do_subchannel_work = do_subchannel_work_virtual;
|
||||
sch->ccw_cb = emulated_ccw_3270_cb;
|
||||
sch->irb_cb = build_irb_virtual;
|
||||
|
||||
ck->init(dev, &err);
|
||||
if (err) {
|
||||
|
@ -1335,6 +1335,14 @@ static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
|
||||
}
|
||||
}
|
||||
|
||||
void copy_esw_to_guest(ESW *dest, const ESW *src)
|
||||
{
|
||||
dest->word0 = cpu_to_be32(src->word0);
|
||||
dest->erw = cpu_to_be32(src->erw);
|
||||
dest->word2 = cpu_to_be64(src->word2);
|
||||
dest->word4 = cpu_to_be32(src->word4);
|
||||
}
|
||||
|
||||
IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib)
|
||||
{
|
||||
int ret;
|
||||
@ -1604,9 +1612,8 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw,
|
||||
|
||||
copy_scsw_to_guest(&dest->scsw, &src->scsw);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dest->esw); i++) {
|
||||
dest->esw[i] = cpu_to_be32(src->esw[i]);
|
||||
}
|
||||
copy_esw_to_guest(&dest->esw, &src->esw);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) {
|
||||
dest->ecw[i] = cpu_to_be32(src->ecw[i]);
|
||||
}
|
||||
@ -1632,6 +1639,55 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw,
|
||||
*irb_len = sizeof(*dest);
|
||||
}
|
||||
|
||||
static void build_irb_sense_data(SubchDev *sch, IRB *irb)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Attention: sense_data is already BE! */
|
||||
memcpy(irb->ecw, sch->sense_data, sizeof(sch->sense_data));
|
||||
for (i = 0; i < ARRAY_SIZE(irb->ecw); i++) {
|
||||
irb->ecw[i] = be32_to_cpu(irb->ecw[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void build_irb_passthrough(SubchDev *sch, IRB *irb)
|
||||
{
|
||||
/* Copy ESW from hardware */
|
||||
irb->esw = sch->esw;
|
||||
|
||||
/*
|
||||
* If (irb->esw.erw & ESW_ERW_SENSE) is true, then the contents
|
||||
* of the ECW is sense data. If false, then it is model-dependent
|
||||
* information. Either way, copy it into the IRB for the guest to
|
||||
* read/decide what to do with.
|
||||
*/
|
||||
build_irb_sense_data(sch, irb);
|
||||
}
|
||||
|
||||
void build_irb_virtual(SubchDev *sch, IRB *irb)
|
||||
{
|
||||
SCHIB *schib = &sch->curr_status;
|
||||
uint16_t stctl = schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL;
|
||||
|
||||
if (stctl & SCSW_STCTL_STATUS_PEND) {
|
||||
if (schib->scsw.cstat & (SCSW_CSTAT_DATA_CHECK |
|
||||
SCSW_CSTAT_CHN_CTRL_CHK |
|
||||
SCSW_CSTAT_INTF_CTRL_CHK)) {
|
||||
irb->scsw.flags |= SCSW_FLAGS_MASK_ESWF;
|
||||
irb->esw.word0 = 0x04804000;
|
||||
} else {
|
||||
irb->esw.word0 = 0x00800000;
|
||||
}
|
||||
/* If a unit check is pending, copy sense data. */
|
||||
if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) &&
|
||||
(schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) {
|
||||
irb->scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
|
||||
build_irb_sense_data(sch, irb);
|
||||
irb->esw.erw = ESW_ERW_SENSE | (sizeof(sch->sense_data) << 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
|
||||
{
|
||||
SCHIB *schib = &sch->curr_status;
|
||||
@ -1650,29 +1706,12 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
|
||||
|
||||
/* Copy scsw from current status. */
|
||||
irb.scsw = schib->scsw;
|
||||
if (stctl & SCSW_STCTL_STATUS_PEND) {
|
||||
if (schib->scsw.cstat & (SCSW_CSTAT_DATA_CHECK |
|
||||
SCSW_CSTAT_CHN_CTRL_CHK |
|
||||
SCSW_CSTAT_INTF_CTRL_CHK)) {
|
||||
irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF;
|
||||
irb.esw[0] = 0x04804000;
|
||||
} else {
|
||||
irb.esw[0] = 0x00800000;
|
||||
}
|
||||
/* If a unit check is pending, copy sense data. */
|
||||
if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) &&
|
||||
(schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) {
|
||||
int i;
|
||||
|
||||
irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
|
||||
/* Attention: sense_data is already BE! */
|
||||
memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data));
|
||||
for (i = 0; i < ARRAY_SIZE(irb.ecw); i++) {
|
||||
irb.ecw[i] = be32_to_cpu(irb.ecw[i]);
|
||||
}
|
||||
irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8);
|
||||
}
|
||||
/* Build other IRB data, if necessary */
|
||||
if (sch->irb_cb) {
|
||||
sch->irb_cb(sch, &irb);
|
||||
}
|
||||
|
||||
/* Store the irb to the guest. */
|
||||
p = schib->pmcw;
|
||||
copy_irb_to_guest(target_irb, &irb, &p, irb_len);
|
||||
|
@ -124,6 +124,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
|
||||
}
|
||||
sch->driver_data = cdev;
|
||||
sch->do_subchannel_work = do_subchannel_work_passthrough;
|
||||
sch->irb_cb = build_irb_passthrough;
|
||||
|
||||
ccw_dev->sch = sch;
|
||||
ret = css_sch_build_schib(sch, &cdev->hostid);
|
||||
|
@ -802,7 +802,10 @@ DEFINE_CCW_MACHINE(6_1, "6.1", true);
|
||||
|
||||
static void ccw_machine_6_0_instance_options(MachineState *machine)
|
||||
{
|
||||
static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V6_0 };
|
||||
|
||||
ccw_machine_6_1_instance_options(machine);
|
||||
s390_set_qemu_cpu_model(0x2964, 13, 2, qemu_cpu_feat);
|
||||
}
|
||||
|
||||
static void ccw_machine_6_0_class_options(MachineClass *mc)
|
||||
|
@ -753,6 +753,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
|
||||
sch->id.reserved = 0xff;
|
||||
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
|
||||
sch->do_subchannel_work = do_subchannel_work_virtual;
|
||||
sch->irb_cb = build_irb_virtual;
|
||||
ccw_dev->sch = sch;
|
||||
dev->indicators = NULL;
|
||||
dev->revision = -1;
|
||||
|
@ -321,6 +321,7 @@ static void vfio_ccw_io_notifier_handler(void *opaque)
|
||||
SCHIB *schib = &sch->curr_status;
|
||||
SCSW s;
|
||||
IRB irb;
|
||||
ESW esw;
|
||||
int size;
|
||||
|
||||
if (!event_notifier_test_and_clear(&vcdev->io_notifier)) {
|
||||
@ -371,6 +372,9 @@ static void vfio_ccw_io_notifier_handler(void *opaque)
|
||||
copy_scsw_to_guest(&s, &irb.scsw);
|
||||
schib->scsw = s;
|
||||
|
||||
copy_esw_to_guest(&esw, &irb.esw);
|
||||
sch->esw = esw;
|
||||
|
||||
/* If a uint check is pending, copy sense data. */
|
||||
if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) &&
|
||||
(schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) {
|
||||
|
@ -605,6 +605,13 @@ typedef struct {
|
||||
#define HWCAP_S390_HIGH_GPRS 512
|
||||
#define HWCAP_S390_TE 1024
|
||||
#define HWCAP_S390_VXRS 2048
|
||||
#define HWCAP_S390_VXRS_BCD 4096
|
||||
#define HWCAP_S390_VXRS_EXT 8192
|
||||
#define HWCAP_S390_GS 16384
|
||||
#define HWCAP_S390_VXRS_EXT2 32768
|
||||
#define HWCAP_S390_VXRS_PDE 65536
|
||||
#define HWCAP_S390_SORT 131072
|
||||
#define HWCAP_S390_DFLT 262144
|
||||
|
||||
/* M68K specific definitions. */
|
||||
/* We use the top 24 bits to encode information about the
|
||||
|
@ -138,8 +138,10 @@ struct SubchDev {
|
||||
int (*ccw_cb) (SubchDev *, CCW1);
|
||||
void (*disable_cb)(SubchDev *);
|
||||
IOInstEnding (*do_subchannel_work) (SubchDev *);
|
||||
void (*irb_cb)(SubchDev *, IRB *);
|
||||
SenseId id;
|
||||
void *driver_data;
|
||||
ESW esw;
|
||||
};
|
||||
|
||||
static inline void sch_gen_unit_exception(SubchDev *sch)
|
||||
@ -201,6 +203,7 @@ int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id);
|
||||
unsigned int css_find_free_chpid(uint8_t cssid);
|
||||
uint16_t css_build_subchannel_id(SubchDev *sch);
|
||||
void copy_scsw_to_guest(SCSW *dest, const SCSW *src);
|
||||
void copy_esw_to_guest(ESW *dest, const ESW *src);
|
||||
void css_inject_io_interrupt(SubchDev *sch);
|
||||
void css_reset(void);
|
||||
void css_reset_sch(SubchDev *sch);
|
||||
@ -215,6 +218,8 @@ void css_clear_sei_pending(void);
|
||||
IOInstEnding s390_ccw_cmd_request(SubchDev *sch);
|
||||
IOInstEnding do_subchannel_work_virtual(SubchDev *sub);
|
||||
IOInstEnding do_subchannel_work_passthrough(SubchDev *sub);
|
||||
void build_irb_passthrough(SubchDev *sch, IRB *irb);
|
||||
void build_irb_virtual(SubchDev *sch, IRB *irb);
|
||||
|
||||
int s390_ccw_halt(SubchDev *sch);
|
||||
int s390_ccw_clear(SubchDev *sch);
|
||||
|
@ -123,10 +123,20 @@ typedef struct SCHIB {
|
||||
uint8_t mda[4];
|
||||
} QEMU_PACKED SCHIB;
|
||||
|
||||
/* format-0 extended-status word */
|
||||
typedef struct ESW {
|
||||
uint32_t word0; /* subchannel logout for format 0 */
|
||||
uint32_t erw;
|
||||
uint64_t word2; /* failing-storage address for format 0 */
|
||||
uint32_t word4; /* secondary-CCW address for format 0 */
|
||||
} QEMU_PACKED ESW;
|
||||
|
||||
#define ESW_ERW_SENSE 0x01000000
|
||||
|
||||
/* interruption response block */
|
||||
typedef struct IRB {
|
||||
SCSW scsw;
|
||||
uint32_t esw[5];
|
||||
ESW esw;
|
||||
uint32_t ecw[8];
|
||||
uint32_t emw[8];
|
||||
} IRB;
|
||||
|
@ -1376,6 +1376,7 @@ static uint32_t get_elf_hwcap(void)
|
||||
hwcap |= HWCAP_S390_ETF3EH;
|
||||
}
|
||||
GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
|
||||
GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
|
||||
|
||||
return hwcap;
|
||||
}
|
||||
|
@ -112,15 +112,23 @@ get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
|
||||
return (sp - frame_size) & -8ul;
|
||||
}
|
||||
|
||||
#define PSW_USER_BITS (PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
|
||||
PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_ASC_PRIMARY)
|
||||
#define PSW_MASK_USER (PSW_MASK_ASC | PSW_MASK_CC | PSW_MASK_PM | \
|
||||
PSW_MASK_64 | PSW_MASK_32)
|
||||
|
||||
static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
|
||||
{
|
||||
uint64_t psw_mask = s390_cpu_get_psw_mask(env);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Copy a 'clean' PSW mask to the user to avoid leaking
|
||||
* information about whether PER is currently on.
|
||||
* TODO: qemu does not support PSW_MASK_RI; it will never be set.
|
||||
*/
|
||||
__put_user(env->psw.mask, &sregs->regs.psw.mask);
|
||||
psw_mask = PSW_USER_BITS | (psw_mask & PSW_MASK_USER);
|
||||
__put_user(psw_mask, &sregs->regs.psw.mask);
|
||||
__put_user(env->psw.addr, &sregs->regs.psw.addr);
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
@ -289,7 +297,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
|
||||
static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
|
||||
{
|
||||
target_ulong prev_addr;
|
||||
uint64_t prev_addr, prev_mask, mask, addr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
@ -297,9 +305,28 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
|
||||
}
|
||||
|
||||
prev_addr = env->psw.addr;
|
||||
__get_user(env->psw.mask, &sc->regs.psw.mask);
|
||||
__get_user(env->psw.addr, &sc->regs.psw.addr);
|
||||
trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr);
|
||||
__get_user(mask, &sc->regs.psw.mask);
|
||||
__get_user(addr, &sc->regs.psw.addr);
|
||||
trace_user_s390x_restore_sigregs(env, addr, prev_addr);
|
||||
|
||||
/*
|
||||
* Use current psw.mask to preserve PER bit.
|
||||
* TODO:
|
||||
* if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI))
|
||||
* return -EINVAL;
|
||||
* Simply do not allow it to be set in mask.
|
||||
*/
|
||||
prev_mask = s390_cpu_get_psw_mask(env);
|
||||
mask = (prev_mask & ~PSW_MASK_USER) | (mask & PSW_MASK_USER);
|
||||
/* Check for invalid user address space control. */
|
||||
if ((mask & PSW_MASK_ASC) == PSW_ASC_HOME) {
|
||||
mask = (mask & ~PSW_MASK_ASC) | PSW_ASC_PRIMARY;
|
||||
}
|
||||
/* Check for invalid amode. */
|
||||
if (mask & PSW_MASK_64) {
|
||||
mask |= PSW_MASK_32;
|
||||
}
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
__get_user(env->aregs[i], &sc->regs.acrs[i]);
|
||||
|
@ -509,7 +509,7 @@ uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
|
||||
{
|
||||
load_psw(env, mask, addr);
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
cpu_loop_exit(env_cpu(env));
|
||||
}
|
||||
|
||||
|
@ -845,6 +845,9 @@ int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
|
||||
int s390_cpu_restart(S390CPU *cpu);
|
||||
void s390_init_sigp(void);
|
||||
|
||||
/* helper.c */
|
||||
void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
|
||||
uint64_t s390_cpu_get_psw_mask(CPUS390XState *env);
|
||||
|
||||
/* outside of target/s390x/ */
|
||||
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
|
||||
|
@ -90,8 +90,8 @@ static S390CPUDef s390_cpu_defs[] = {
|
||||
CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM z15 T02 GA1"),
|
||||
};
|
||||
|
||||
#define QEMU_MAX_CPU_TYPE 0x2964
|
||||
#define QEMU_MAX_CPU_GEN 13
|
||||
#define QEMU_MAX_CPU_TYPE 0x3906
|
||||
#define QEMU_MAX_CPU_GEN 14
|
||||
#define QEMU_MAX_CPU_EC_GA 2
|
||||
static const S390FeatInit qemu_max_cpu_feat_init = { S390_FEAT_LIST_QEMU_MAX };
|
||||
static S390FeatBitmap qemu_max_cpu_feat;
|
||||
|
@ -252,7 +252,7 @@ static void do_program_interrupt(CPUS390XState *env)
|
||||
|
||||
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.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
|
||||
lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
|
||||
mask = be64_to_cpu(lowcore->program_new_psw.mask);
|
||||
addr = be64_to_cpu(lowcore->program_new_psw.addr);
|
||||
@ -260,7 +260,7 @@ static void do_program_interrupt(CPUS390XState *env)
|
||||
|
||||
cpu_unmap_lowcore(lowcore);
|
||||
|
||||
load_psw(env, mask, addr);
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
}
|
||||
|
||||
static void do_svc_interrupt(CPUS390XState *env)
|
||||
@ -272,14 +272,14 @@ static void do_svc_interrupt(CPUS390XState *env)
|
||||
|
||||
lowcore->svc_code = cpu_to_be16(env->int_svc_code);
|
||||
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.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
|
||||
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);
|
||||
|
||||
cpu_unmap_lowcore(lowcore);
|
||||
|
||||
load_psw(env, mask, addr);
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
|
||||
/* When a PER event is pending, the PER exception has to happen
|
||||
immediately after the SERVICE CALL one. */
|
||||
@ -348,12 +348,12 @@ static void do_ext_interrupt(CPUS390XState *env)
|
||||
|
||||
mask = be64_to_cpu(lowcore->external_new_psw.mask);
|
||||
addr = be64_to_cpu(lowcore->external_new_psw.addr);
|
||||
lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
|
||||
lowcore->external_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
|
||||
lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
|
||||
|
||||
cpu_unmap_lowcore(lowcore);
|
||||
|
||||
load_psw(env, mask, addr);
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
}
|
||||
|
||||
static void do_io_interrupt(CPUS390XState *env)
|
||||
@ -373,7 +373,7 @@ static void do_io_interrupt(CPUS390XState *env)
|
||||
lowcore->subchannel_nr = cpu_to_be16(io->nr);
|
||||
lowcore->io_int_parm = cpu_to_be32(io->parm);
|
||||
lowcore->io_int_word = cpu_to_be32(io->word);
|
||||
lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env));
|
||||
lowcore->io_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
|
||||
lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
|
||||
mask = be64_to_cpu(lowcore->io_new_psw.mask);
|
||||
addr = be64_to_cpu(lowcore->io_new_psw.addr);
|
||||
@ -381,7 +381,7 @@ static void do_io_interrupt(CPUS390XState *env)
|
||||
cpu_unmap_lowcore(lowcore);
|
||||
g_free(io);
|
||||
|
||||
load_psw(env, mask, addr);
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
}
|
||||
|
||||
typedef struct MchkExtSaveArea {
|
||||
@ -457,14 +457,14 @@ static void do_mchk_interrupt(CPUS390XState *env)
|
||||
lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
|
||||
|
||||
lowcore->mcic = cpu_to_be64(mcic);
|
||||
lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env));
|
||||
lowcore->mcck_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
|
||||
lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
|
||||
mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
|
||||
addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
|
||||
|
||||
cpu_unmap_lowcore(lowcore);
|
||||
|
||||
load_psw(env, mask, addr);
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
}
|
||||
|
||||
void s390_cpu_do_interrupt(CPUState *cs)
|
||||
@ -592,9 +592,11 @@ void s390x_cpu_debug_excp_handler(CPUState *cs)
|
||||
and MVCS instrutions are not used. */
|
||||
env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
|
||||
|
||||
/* Remove all watchpoints to re-execute the code. A PER exception
|
||||
will be triggered, it will call load_psw which will recompute
|
||||
the watchpoints. */
|
||||
/*
|
||||
* Remove all watchpoints to re-execute the code. A PER exception
|
||||
* will be triggered, it will call s390_cpu_set_psw which will
|
||||
* recompute the watchpoints.
|
||||
*/
|
||||
cpu_watchpoint_remove_all(cs, BP_CPU);
|
||||
cpu_loop_exit_noexc(cs);
|
||||
}
|
||||
|
@ -509,6 +509,9 @@ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float32_is_any_nan(v2)) {
|
||||
return INT64_MIN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -520,6 +523,9 @@ uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float64_is_any_nan(v2)) {
|
||||
return INT64_MIN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -532,6 +538,9 @@ uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float128_is_any_nan(v2)) {
|
||||
return INT64_MIN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -543,6 +552,9 @@ uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float32_is_any_nan(v2)) {
|
||||
return INT32_MIN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -554,6 +566,9 @@ uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float64_is_any_nan(v2)) {
|
||||
return INT32_MIN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -566,6 +581,9 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float128_is_any_nan(v2)) {
|
||||
return INT32_MIN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -573,12 +591,12 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
|
||||
uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
{
|
||||
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
|
||||
uint64_t ret;
|
||||
|
||||
v2 = float32_to_float64(v2, &env->fpu_status);
|
||||
ret = float64_to_uint64(v2, &env->fpu_status);
|
||||
uint64_t ret = float32_to_uint64(v2, &env->fpu_status);
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float32_is_any_nan(v2)) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -590,6 +608,9 @@ uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float64_is_any_nan(v2)) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -601,6 +622,9 @@ uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float128_is_any_nan(make_float128(h, l))) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -612,6 +636,9 @@ uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float32_is_any_nan(v2)) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -623,6 +650,9 @@ uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float64_is_any_nan(v2)) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -634,6 +664,9 @@ uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
|
||||
|
||||
s390_restore_bfp_rounding_mode(env, old_mode);
|
||||
handle_exceptions(env, xxc_from_m34(m34), GETPC());
|
||||
if (float128_is_any_nan(make_float128(h, l))) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -31,18 +31,10 @@ int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
CPUS390XState *env = &cpu->env;
|
||||
uint64_t val;
|
||||
int cc_op;
|
||||
|
||||
switch (n) {
|
||||
case S390_PSWM_REGNUM:
|
||||
if (tcg_enabled()) {
|
||||
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);
|
||||
return gdb_get_regl(mem_buf, val);
|
||||
}
|
||||
return gdb_get_regl(mem_buf, env->psw.mask);
|
||||
return gdb_get_regl(mem_buf, s390_cpu_get_psw_mask(env));
|
||||
case S390_PSWA_REGNUM:
|
||||
return gdb_get_regl(mem_buf, env->psw.addr);
|
||||
case S390_R0_REGNUM ... S390_R15_REGNUM:
|
||||
@ -59,10 +51,7 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
|
||||
switch (n) {
|
||||
case S390_PSWM_REGNUM:
|
||||
env->psw.mask = tmpl;
|
||||
if (tcg_enabled()) {
|
||||
env->cc_op = extract64(tmpl, 44, 2);
|
||||
}
|
||||
s390_cpu_set_psw(env, tmpl, env->psw.addr);
|
||||
break;
|
||||
case S390_PSWA_REGNUM:
|
||||
env->psw.addr = tmpl;
|
||||
|
@ -706,20 +706,23 @@ static uint16_t qemu_V4_1[] = {
|
||||
S390_FEAT_VECTOR,
|
||||
};
|
||||
|
||||
static uint16_t qemu_LATEST[] = {
|
||||
static uint16_t qemu_V6_0[] = {
|
||||
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
|
||||
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
|
||||
S390_FEAT_ESOP,
|
||||
};
|
||||
|
||||
static uint16_t qemu_LATEST[] = {
|
||||
S390_FEAT_INSTRUCTION_EXEC_PROT,
|
||||
S390_FEAT_MISC_INSTRUCTION_EXT2,
|
||||
S390_FEAT_MSA_EXT_8,
|
||||
S390_FEAT_VECTOR_ENH,
|
||||
};
|
||||
|
||||
/* add all new definitions before this point */
|
||||
static uint16_t qemu_MAX[] = {
|
||||
/* generates a dependency warning, leave it out for now */
|
||||
S390_FEAT_MSA_EXT_5,
|
||||
/* features introduced after the z13 */
|
||||
S390_FEAT_INSTRUCTION_EXEC_PROT,
|
||||
S390_FEAT_MISC_INSTRUCTION_EXT2,
|
||||
S390_FEAT_MSA_EXT_8,
|
||||
};
|
||||
|
||||
/****** END FEATURE DEFS ******/
|
||||
@ -838,6 +841,7 @@ static FeatGroupDefSpec QemuFeatDef[] = {
|
||||
QEMU_FEAT_INITIALIZER(V3_1),
|
||||
QEMU_FEAT_INITIALIZER(V4_0),
|
||||
QEMU_FEAT_INITIALIZER(V4_1),
|
||||
QEMU_FEAT_INITIALIZER(V6_0),
|
||||
QEMU_FEAT_INITIALIZER(LATEST),
|
||||
QEMU_FEAT_INITIALIZER(MAX),
|
||||
};
|
||||
|
@ -104,44 +104,6 @@ void s390_handle_wait(S390CPU *cpu)
|
||||
}
|
||||
}
|
||||
|
||||
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
|
||||
{
|
||||
uint64_t old_mask = env->psw.mask;
|
||||
|
||||
env->psw.addr = addr;
|
||||
env->psw.mask = mask;
|
||||
|
||||
/* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
|
||||
if (!tcg_enabled()) {
|
||||
return;
|
||||
}
|
||||
env->cc_op = (mask >> 44) & 3;
|
||||
|
||||
if ((old_mask ^ mask) & PSW_MASK_PER) {
|
||||
s390_cpu_recompute_watchpoints(env_cpu(env));
|
||||
}
|
||||
|
||||
if (mask & PSW_MASK_WAIT) {
|
||||
s390_handle_wait(env_archcpu(env));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t get_psw_mask(CPUS390XState *env)
|
||||
{
|
||||
uint64_t r = env->psw.mask;
|
||||
|
||||
if (tcg_enabled()) {
|
||||
env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
|
||||
env->cc_vr);
|
||||
|
||||
r &= ~PSW_MASK_CC;
|
||||
assert(!(env->cc_op & ~3));
|
||||
r |= (uint64_t)env->cc_op << 44;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
LowCore *cpu_map_lowcore(CPUS390XState *env)
|
||||
{
|
||||
LowCore *lowcore;
|
||||
@ -168,7 +130,7 @@ void do_restart_interrupt(CPUS390XState *env)
|
||||
|
||||
lowcore = cpu_map_lowcore(env);
|
||||
|
||||
lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env));
|
||||
lowcore->restart_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
|
||||
lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
|
||||
mask = be64_to_cpu(lowcore->restart_new_psw.mask);
|
||||
addr = be64_to_cpu(lowcore->restart_new_psw.addr);
|
||||
@ -176,7 +138,7 @@ void do_restart_interrupt(CPUS390XState *env)
|
||||
cpu_unmap_lowcore(lowcore);
|
||||
env->pending_int &= ~INTERRUPT_RESTART;
|
||||
|
||||
load_psw(env, mask, addr);
|
||||
s390_cpu_set_psw(env, mask, addr);
|
||||
}
|
||||
|
||||
void s390_cpu_recompute_watchpoints(CPUState *cs)
|
||||
@ -266,7 +228,7 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
|
||||
sa->grs[i] = cpu_to_be64(cpu->env.regs[i]);
|
||||
}
|
||||
sa->psw.addr = cpu_to_be64(cpu->env.psw.addr);
|
||||
sa->psw.mask = cpu_to_be64(get_psw_mask(&cpu->env));
|
||||
sa->psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(&cpu->env));
|
||||
sa->prefix = cpu_to_be32(cpu->env.psa);
|
||||
sa->fpc = cpu_to_be32(cpu->env.fpc);
|
||||
sa->todpr = cpu_to_be32(cpu->env.todpr);
|
||||
@ -323,20 +285,67 @@ int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
|
||||
cpu_physical_memory_unmap(sa, len, 1, len);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* For user-only, tcg is always enabled. */
|
||||
#define tcg_enabled() true
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
||||
void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
uint64_t old_mask = env->psw.mask;
|
||||
#endif
|
||||
|
||||
env->psw.addr = addr;
|
||||
env->psw.mask = mask;
|
||||
|
||||
/* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
|
||||
if (!tcg_enabled()) {
|
||||
return;
|
||||
}
|
||||
env->cc_op = (mask >> 44) & 3;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if ((old_mask ^ mask) & PSW_MASK_PER) {
|
||||
s390_cpu_recompute_watchpoints(env_cpu(env));
|
||||
}
|
||||
|
||||
if (mask & PSW_MASK_WAIT) {
|
||||
s390_handle_wait(env_archcpu(env));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
|
||||
{
|
||||
uint64_t r = env->psw.mask;
|
||||
|
||||
if (tcg_enabled()) {
|
||||
uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
|
||||
env->cc_dst, env->cc_vr);
|
||||
|
||||
assert(cc <= 3);
|
||||
r &= ~PSW_MASK_CC;
|
||||
r |= cc << 44;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
CPUS390XState *env = &cpu->env;
|
||||
int i;
|
||||
|
||||
if (env->cc_op > 3) {
|
||||
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n",
|
||||
env->psw.mask, env->psw.addr, cc_name(env->cc_op));
|
||||
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64,
|
||||
s390_cpu_get_psw_mask(env), env->psw.addr);
|
||||
if (!tcg_enabled()) {
|
||||
qemu_fprintf(f, "\n");
|
||||
} else if (env->cc_op > 3) {
|
||||
qemu_fprintf(f, " cc %15s\n", cc_name(env->cc_op));
|
||||
} else {
|
||||
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n",
|
||||
env->psw.mask, env->psw.addr, env->cc_op);
|
||||
qemu_fprintf(f, " cc %02x\n", env->cc_op);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
|
@ -126,6 +126,7 @@ DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env)
|
||||
DEF_HELPER_FLAGS_3(probe_write_access, TCG_CALL_NO_WG, void, env, i64, i64)
|
||||
|
||||
/* === Vector Support Instructions === */
|
||||
DEF_HELPER_FLAGS_4(gvec_vbperm, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
|
||||
DEF_HELPER_FLAGS_4(vll, TCG_CALL_NO_WG, void, env, ptr, i64, i64)
|
||||
DEF_HELPER_FLAGS_4(gvec_vpk16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vpk32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
|
||||
@ -246,50 +247,77 @@ DEF_HELPER_6(gvec_vstrc_cc_rt16, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_6(gvec_vstrc_cc_rt32, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
|
||||
/* === Vector Floating-Point Instructions */
|
||||
DEF_HELPER_FLAGS_5(gvec_vfa32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfa64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfa128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_wfc32, void, cptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_wfk32, void, cptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_wfc128, void, cptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_wfk128, void, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfce32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfce32_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfce64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfce64_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfce64s_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfce128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfce128_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfch32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfch32_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfch64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfch64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfch64_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfch64s_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfch128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfch128_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfche32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfche32_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfche64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfche64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfche64_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfche64s_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfche128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_5(gvec_vfche128_cc, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vcdg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vcdlg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vcgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vclgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfd32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfd64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfd128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfi32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfi64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfi128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfll32s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfll64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vflr64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vflr128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfm64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfm128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfmax32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfmax64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfmax128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfmin32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfmin64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfmin128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfma32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfma64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfms32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfms64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfms128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfnma32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfnma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfnma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfnms32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfnms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_6(gvec_vfnms128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfsq32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfsq64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_vfsq128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfs32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfs64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_FLAGS_5(gvec_vfs128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_vftci32, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_vftci64s, void, ptr, cptr, env, i32)
|
||||
DEF_HELPER_4(gvec_vftci128, void, ptr, cptr, env, i32)
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
DEF_HELPER_3(servc, i32, env, i64, i64)
|
||||
|
@ -989,6 +989,8 @@
|
||||
|
||||
/* === Vector Support Instructions === */
|
||||
|
||||
/* VECTOR BIT PERMUTE */
|
||||
E(0xe785, VBPERM, VRR_c, VE, 0, 0, 0, 0, vbperm, 0, 0, IF_VEC)
|
||||
/* VECTOR GATHER ELEMENT */
|
||||
E(0xe713, VGEF, VRV, V, la2, 0, 0, 0, vge, 0, ES_32, IF_VEC)
|
||||
E(0xe712, VGEG, VRV, V, la2, 0, 0, 0, vge, 0, ES_64, IF_VEC)
|
||||
@ -1149,6 +1151,8 @@
|
||||
F(0xe7a7, VMO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC)
|
||||
/* VECTOR MULTIPLY LOGICAL ODD */
|
||||
F(0xe7a5, VMLO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC)
|
||||
/* VECTOR MULTIPLY SUM LOGICAL */
|
||||
F(0xe7b8, VMSL, VRR_d, VE, 0, 0, 0, 0, vmsl, 0, IF_VEC)
|
||||
/* VECTOR NAND */
|
||||
F(0xe76e, VNN, VRR_c, VE, 0, 0, 0, 0, vnn, 0, IF_VEC)
|
||||
/* VECTOR NOR */
|
||||
@ -1245,16 +1249,24 @@
|
||||
F(0xe7e5, VFD, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC)
|
||||
/* VECTOR LOAD FP INTEGER */
|
||||
F(0xe7c7, VFI, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC)
|
||||
/* VECTOR LOAD LENGTHENED */
|
||||
/* VECTOR FP LOAD LENGTHENED */
|
||||
F(0xe7c4, VFLL, VRR_a, V, 0, 0, 0, 0, vfll, 0, IF_VEC)
|
||||
/* VECTOR LOAD ROUNDED */
|
||||
/* VECTOR FP LOAD ROUNDED */
|
||||
F(0xe7c5, VFLR, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC)
|
||||
/* VECTOR FP MAXIMUM */
|
||||
F(0xe7ef, VFMAX, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC)
|
||||
/* VECTOR FP MINIMUM */
|
||||
F(0xe7ee, VFMIN, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC)
|
||||
/* VECTOR FP MULTIPLY */
|
||||
F(0xe7e7, VFM, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC)
|
||||
/* VECTOR FP MULTIPLY AND ADD */
|
||||
F(0xe78f, VFMA, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC)
|
||||
/* VECTOR FP MULTIPLY AND SUBTRACT */
|
||||
F(0xe78e, VFMS, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC)
|
||||
/* VECTOR FP NEGATIVE MULTIPLY AND ADD */
|
||||
F(0xe79f, VFNMA, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC)
|
||||
/* VECTOR FP NEGATIVE MULTIPLY AND SUBTRACT */
|
||||
F(0xe79e, VFNMS, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC)
|
||||
/* VECTOR FP PERFORM SIGN OPERATION */
|
||||
F(0xe7cc, VFPSO, VRR_a, V, 0, 0, 0, 0, vfpso, 0, IF_VEC)
|
||||
/* VECTOR FP SQUARE ROOT */
|
||||
|
@ -235,10 +235,6 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
const char *cc_name(enum cc_op cc_op);
|
||||
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
|
||||
uint64_t vr);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
||||
|
||||
/* cpu.c */
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@ -288,6 +284,15 @@ uint8_t s390_softfloat_exc_to_ieee(unsigned int exc);
|
||||
int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3);
|
||||
void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode);
|
||||
int float_comp_to_cc(CPUS390XState *env, int float_compare);
|
||||
|
||||
#define DCMASK_ZERO 0x0c00
|
||||
#define DCMASK_NORMAL 0x0300
|
||||
#define DCMASK_SUBNORMAL 0x00c0
|
||||
#define DCMASK_INFINITY 0x0030
|
||||
#define DCMASK_QUIET_NAN 0x000c
|
||||
#define DCMASK_SIGNALING_NAN 0x0003
|
||||
#define DCMASK_NAN 0x000f
|
||||
#define DCMASK_NEGATIVE 0x0555
|
||||
uint16_t float32_dcmask(CPUS390XState *env, float32 f1);
|
||||
uint16_t float64_dcmask(CPUS390XState *env, float64 f1);
|
||||
uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
|
||||
@ -303,7 +308,6 @@ void s390_cpu_gdb_init(CPUState *cs);
|
||||
void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
||||
void do_restart_interrupt(CPUS390XState *env);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
uint64_t get_psw_mask(CPUS390XState *env);
|
||||
void s390_cpu_recompute_watchpoints(CPUState *cs);
|
||||
void s390x_tod_timer(void *opaque);
|
||||
void s390x_cpu_timer(void *opaque);
|
||||
|
@ -49,11 +49,6 @@ int kvm_s390_get_ri(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_s390_get_gs(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
|
||||
{
|
||||
return -ENOSYS;
|
||||
|
@ -154,7 +154,6 @@ static int cap_async_pf;
|
||||
static int cap_mem_op;
|
||||
static int cap_s390_irq;
|
||||
static int cap_ri;
|
||||
static int cap_gs;
|
||||
static int cap_hpage_1m;
|
||||
static int cap_vcpu_resets;
|
||||
static int cap_protected;
|
||||
@ -369,9 +368,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
||||
}
|
||||
}
|
||||
if (cpu_model_allowed()) {
|
||||
if (kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0) == 0) {
|
||||
cap_gs = 1;
|
||||
}
|
||||
kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2039,11 +2036,6 @@ int kvm_s390_get_ri(void)
|
||||
return cap_ri;
|
||||
}
|
||||
|
||||
int kvm_s390_get_gs(void)
|
||||
{
|
||||
return cap_gs;
|
||||
}
|
||||
|
||||
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
|
||||
{
|
||||
struct kvm_mp_state mp_state = {};
|
||||
|
@ -27,7 +27,6 @@ void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
|
||||
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
|
||||
int kvm_s390_get_hpage_1m(void);
|
||||
int kvm_s390_get_ri(void);
|
||||
int kvm_s390_get_gs(void);
|
||||
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
|
||||
int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock);
|
||||
int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock);
|
||||
|
@ -235,7 +235,8 @@ static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
|
||||
cpu_synchronize_state(cs);
|
||||
/*
|
||||
* Set OPERATING (and unhalting) before loading the restart PSW.
|
||||
* load_psw() will then properly halt the CPU again if necessary (TCG).
|
||||
* s390_cpu_set_psw() will then properly halt the CPU again if
|
||||
* necessary (TCG).
|
||||
*/
|
||||
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
|
||||
do_restart_interrupt(&cpu->env);
|
||||
|
@ -327,6 +327,14 @@ static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
|
||||
tcg_temp_free_i64(bh);
|
||||
}
|
||||
|
||||
static DisasJumpType op_vbperm(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), get_field(s, v3), 0,
|
||||
gen_helper_gvec_vbperm);
|
||||
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
const uint8_t es = s->insn->data;
|
||||
@ -1771,6 +1779,56 @@ static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
TCGv_i64 l1, h1, l2, h2;
|
||||
|
||||
if (get_field(s, m4) != ES_64) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
l1 = tcg_temp_new_i64();
|
||||
h1 = tcg_temp_new_i64();
|
||||
l2 = tcg_temp_new_i64();
|
||||
h2 = tcg_temp_new_i64();
|
||||
|
||||
/* Multipy both even elements from v2 and v3 */
|
||||
read_vec_element_i64(l1, get_field(s, v2), 0, ES_64);
|
||||
read_vec_element_i64(h1, get_field(s, v3), 0, ES_64);
|
||||
tcg_gen_mulu2_i64(l1, h1, l1, h1);
|
||||
/* Shift result left by one (x2) if requested */
|
||||
if (extract32(get_field(s, m6), 3, 1)) {
|
||||
tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1);
|
||||
}
|
||||
|
||||
/* Multipy both odd elements from v2 and v3 */
|
||||
read_vec_element_i64(l2, get_field(s, v2), 1, ES_64);
|
||||
read_vec_element_i64(h2, get_field(s, v3), 1, ES_64);
|
||||
tcg_gen_mulu2_i64(l2, h2, l2, h2);
|
||||
/* Shift result left by one (x2) if requested */
|
||||
if (extract32(get_field(s, m6), 2, 1)) {
|
||||
tcg_gen_add2_i64(l2, h2, l2, h2, l2, h2);
|
||||
}
|
||||
|
||||
/* Add both intermediate results */
|
||||
tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
|
||||
/* Add whole v4 */
|
||||
read_vec_element_i64(h2, get_field(s, v4), 0, ES_64);
|
||||
read_vec_element_i64(l2, get_field(s, v4), 1, ES_64);
|
||||
tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
|
||||
|
||||
/* Store final result into v1. */
|
||||
write_vec_element_i64(h1, get_field(s, v1), 0, ES_64);
|
||||
write_vec_element_i64(l1, get_field(s, v1), 1, ES_64);
|
||||
|
||||
tcg_temp_free_i64(l1);
|
||||
tcg_temp_free_i64(h1);
|
||||
tcg_temp_free_i64(l2);
|
||||
tcg_temp_free_i64(h2);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
gen_gvec_fn_3(nand, ES_8, get_field(s, v1),
|
||||
@ -2443,32 +2501,96 @@ static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
const uint8_t fpf = get_field(s, m4);
|
||||
const uint8_t m5 = get_field(s, m5);
|
||||
const bool se = extract32(m5, 3, 1);
|
||||
gen_helper_gvec_3_ptr *fn;
|
||||
|
||||
if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
gen_helper_gvec_3_ptr *fn = NULL;
|
||||
|
||||
switch (s->fields.op2) {
|
||||
case 0xe3:
|
||||
fn = se ? gen_helper_gvec_vfa64s : gen_helper_gvec_vfa64;
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfa32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfa64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfa128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xe5:
|
||||
fn = se ? gen_helper_gvec_vfd64s : gen_helper_gvec_vfd64;
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfd32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfd64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfd128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xe7:
|
||||
fn = se ? gen_helper_gvec_vfm64s : gen_helper_gvec_vfm64;
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfm32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfm64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfm128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xe2:
|
||||
fn = se ? gen_helper_gvec_vfs64s : gen_helper_gvec_vfs64;
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfs32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfs64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfs128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!fn || extract32(m5, 0, 3)) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
|
||||
get_field(s, v3), cpu_env, 0, fn);
|
||||
get_field(s, v3), cpu_env, m5, fn);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
@ -2476,19 +2598,41 @@ static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
const uint8_t fpf = get_field(s, m3);
|
||||
const uint8_t m4 = get_field(s, m4);
|
||||
gen_helper_gvec_2_ptr *fn = NULL;
|
||||
|
||||
if (fpf != FPF_LONG || m4) {
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_wfk32;
|
||||
if (s->fields.op2 == 0xcb) {
|
||||
fn = gen_helper_gvec_wfc32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_wfk64;
|
||||
if (s->fields.op2 == 0xcb) {
|
||||
fn = gen_helper_gvec_wfc64;
|
||||
}
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_wfk128;
|
||||
if (s->fields.op2 == 0xcb) {
|
||||
fn = gen_helper_gvec_wfc128;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
if (!fn || m4) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (s->fields.op2 == 0xcb) {
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
|
||||
cpu_env, 0, gen_helper_gvec_wfc64);
|
||||
} else {
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
|
||||
cpu_env, 0, gen_helper_gvec_wfk64);
|
||||
}
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn);
|
||||
set_cc_static(s);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
@ -2498,46 +2642,68 @@ static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
|
||||
const uint8_t fpf = get_field(s, m4);
|
||||
const uint8_t m5 = get_field(s, m5);
|
||||
const uint8_t m6 = get_field(s, m6);
|
||||
const bool se = extract32(m5, 3, 1);
|
||||
const bool cs = extract32(m6, 0, 1);
|
||||
gen_helper_gvec_3_ptr *fn;
|
||||
const bool sq = extract32(m5, 2, 1);
|
||||
gen_helper_gvec_3_ptr *fn = NULL;
|
||||
|
||||
if (fpf != FPF_LONG || extract32(m5, 0, 3) || extract32(m6, 1, 3)) {
|
||||
switch (s->fields.op2) {
|
||||
case 0xe8:
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32;
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xeb:
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32;
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xea:
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32;
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) ||
|
||||
(!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (cs) {
|
||||
switch (s->fields.op2) {
|
||||
case 0xe8:
|
||||
fn = se ? gen_helper_gvec_vfce64s_cc : gen_helper_gvec_vfce64_cc;
|
||||
break;
|
||||
case 0xeb:
|
||||
fn = se ? gen_helper_gvec_vfch64s_cc : gen_helper_gvec_vfch64_cc;
|
||||
break;
|
||||
case 0xea:
|
||||
fn = se ? gen_helper_gvec_vfche64s_cc : gen_helper_gvec_vfche64_cc;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
} else {
|
||||
switch (s->fields.op2) {
|
||||
case 0xe8:
|
||||
fn = se ? gen_helper_gvec_vfce64s : gen_helper_gvec_vfce64;
|
||||
break;
|
||||
case 0xeb:
|
||||
fn = se ? gen_helper_gvec_vfch64s : gen_helper_gvec_vfch64;
|
||||
break;
|
||||
case 0xea:
|
||||
fn = se ? gen_helper_gvec_vfche64s : gen_helper_gvec_vfche64;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
|
||||
get_field(s, v3), cpu_env, 0, fn);
|
||||
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
|
||||
cpu_env, m5, fn);
|
||||
if (cs) {
|
||||
set_cc_static(s);
|
||||
}
|
||||
@ -2549,36 +2715,72 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
|
||||
const uint8_t fpf = get_field(s, m3);
|
||||
const uint8_t m4 = get_field(s, m4);
|
||||
const uint8_t erm = get_field(s, m5);
|
||||
const bool se = extract32(m4, 3, 1);
|
||||
gen_helper_gvec_2_ptr *fn;
|
||||
gen_helper_gvec_2_ptr *fn = NULL;
|
||||
|
||||
if (fpf != FPF_LONG || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
switch (s->fields.op2) {
|
||||
case 0xc3:
|
||||
fn = se ? gen_helper_gvec_vcdg64s : gen_helper_gvec_vcdg64;
|
||||
if (fpf == FPF_LONG) {
|
||||
fn = gen_helper_gvec_vcdg64;
|
||||
}
|
||||
break;
|
||||
case 0xc1:
|
||||
fn = se ? gen_helper_gvec_vcdlg64s : gen_helper_gvec_vcdlg64;
|
||||
if (fpf == FPF_LONG) {
|
||||
fn = gen_helper_gvec_vcdlg64;
|
||||
}
|
||||
break;
|
||||
case 0xc2:
|
||||
fn = se ? gen_helper_gvec_vcgd64s : gen_helper_gvec_vcgd64;
|
||||
if (fpf == FPF_LONG) {
|
||||
fn = gen_helper_gvec_vcgd64;
|
||||
}
|
||||
break;
|
||||
case 0xc0:
|
||||
fn = se ? gen_helper_gvec_vclgd64s : gen_helper_gvec_vclgd64;
|
||||
if (fpf == FPF_LONG) {
|
||||
fn = gen_helper_gvec_vclgd64;
|
||||
}
|
||||
break;
|
||||
case 0xc7:
|
||||
fn = se ? gen_helper_gvec_vfi64s : gen_helper_gvec_vfi64;
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfi32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfi64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfi128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xc5:
|
||||
fn = se ? gen_helper_gvec_vflr64s : gen_helper_gvec_vflr64;
|
||||
switch (fpf) {
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vflr64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vflr128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
|
||||
deposit32(m4, 4, 4, erm), fn);
|
||||
return DISAS_NEXT;
|
||||
@ -2588,18 +2790,71 @@ static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
const uint8_t fpf = get_field(s, m3);
|
||||
const uint8_t m4 = get_field(s, m4);
|
||||
gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfll32;
|
||||
gen_helper_gvec_2_ptr *fn = NULL;
|
||||
|
||||
if (fpf != FPF_SHORT || extract32(m4, 0, 3)) {
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
fn = gen_helper_gvec_vfll32;
|
||||
break;
|
||||
case FPF_LONG:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfll64;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fn || extract32(m4, 0, 3)) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (extract32(m4, 3, 1)) {
|
||||
fn = gen_helper_gvec_vfll32s;
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
const uint8_t fpf = get_field(s, m4);
|
||||
const uint8_t m6 = get_field(s, m6);
|
||||
const uint8_t m5 = get_field(s, m5);
|
||||
gen_helper_gvec_3_ptr *fn;
|
||||
|
||||
if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
|
||||
0, fn);
|
||||
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s->fields.op2 == 0xef) {
|
||||
fn = gen_helper_gvec_vfmax32;
|
||||
} else {
|
||||
fn = gen_helper_gvec_vfmin32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
if (s->fields.op2 == 0xef) {
|
||||
fn = gen_helper_gvec_vfmax64;
|
||||
} else {
|
||||
fn = gen_helper_gvec_vfmin64;
|
||||
}
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s->fields.op2 == 0xef) {
|
||||
fn = gen_helper_gvec_vfmax128;
|
||||
} else {
|
||||
fn = gen_helper_gvec_vfmin128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
|
||||
cpu_env, deposit32(m5, 4, 4, m6), fn);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
@ -2607,22 +2862,88 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
const uint8_t m5 = get_field(s, m5);
|
||||
const uint8_t fpf = get_field(s, m6);
|
||||
const bool se = extract32(m5, 3, 1);
|
||||
gen_helper_gvec_4_ptr *fn;
|
||||
gen_helper_gvec_4_ptr *fn = NULL;
|
||||
|
||||
if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
|
||||
switch (s->fields.op2) {
|
||||
case 0x8f:
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfma32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfma64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfma128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x8e:
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfms32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfms64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfms128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x9f:
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
fn = gen_helper_gvec_vfnma32;
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfnma64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
fn = gen_helper_gvec_vfnma128;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x9e:
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
fn = gen_helper_gvec_vfnms32;
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfnms64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
fn = gen_helper_gvec_vfnms128;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!fn || extract32(m5, 0, 3)) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (s->fields.op2 == 0x8f) {
|
||||
fn = se ? gen_helper_gvec_vfma64s : gen_helper_gvec_vfma64;
|
||||
} else {
|
||||
fn = se ? gen_helper_gvec_vfms64s : gen_helper_gvec_vfms64;
|
||||
}
|
||||
gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
|
||||
get_field(s, v3), get_field(s, v4), cpu_env,
|
||||
0, fn);
|
||||
get_field(s, v3), get_field(s, v4), cpu_env, m5, fn);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
@ -2633,48 +2954,88 @@ static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
|
||||
const uint8_t fpf = get_field(s, m3);
|
||||
const uint8_t m4 = get_field(s, m4);
|
||||
const uint8_t m5 = get_field(s, m5);
|
||||
const bool se = extract32(m4, 3, 1);
|
||||
TCGv_i64 tmp;
|
||||
|
||||
if (fpf != FPF_LONG || extract32(m4, 0, 3) || m5 > 2) {
|
||||
if ((fpf != FPF_LONG && !s390_has_feat(S390_FEAT_VECTOR_ENH)) ||
|
||||
extract32(m4, 0, 3) || m5 > 2) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (extract32(m4, 3, 1)) {
|
||||
tmp = tcg_temp_new_i64();
|
||||
read_vec_element_i64(tmp, v2, 0, ES_64);
|
||||
switch (m5) {
|
||||
case 0:
|
||||
/* sign bit is inverted (complement) */
|
||||
tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
|
||||
break;
|
||||
case 1:
|
||||
/* sign bit is set to one (negative) */
|
||||
tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
|
||||
break;
|
||||
case 2:
|
||||
/* sign bit is set to zero (positive) */
|
||||
tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
|
||||
break;
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (!se) {
|
||||
switch (m5) {
|
||||
case 0:
|
||||
/* sign bit is inverted (complement) */
|
||||
gen_gvec_fn_2i(xori, ES_32, v1, v2, 1ull << 31);
|
||||
break;
|
||||
case 1:
|
||||
/* sign bit is set to one (negative) */
|
||||
gen_gvec_fn_2i(ori, ES_32, v1, v2, 1ull << 31);
|
||||
break;
|
||||
case 2:
|
||||
/* sign bit is set to zero (positive) */
|
||||
gen_gvec_fn_2i(andi, ES_32, v1, v2, (1ull << 31) - 1);
|
||||
break;
|
||||
}
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
write_vec_element_i64(tmp, v1, 0, ES_64);
|
||||
tcg_temp_free_i64(tmp);
|
||||
} else {
|
||||
switch (m5) {
|
||||
case 0:
|
||||
/* sign bit is inverted (complement) */
|
||||
gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
|
||||
break;
|
||||
case 1:
|
||||
/* sign bit is set to one (negative) */
|
||||
gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
|
||||
break;
|
||||
case 2:
|
||||
/* sign bit is set to zero (positive) */
|
||||
gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
|
||||
break;
|
||||
break;
|
||||
case FPF_LONG:
|
||||
if (!se) {
|
||||
switch (m5) {
|
||||
case 0:
|
||||
/* sign bit is inverted (complement) */
|
||||
gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
|
||||
break;
|
||||
case 1:
|
||||
/* sign bit is set to one (negative) */
|
||||
gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
|
||||
break;
|
||||
case 2:
|
||||
/* sign bit is set to zero (positive) */
|
||||
gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
|
||||
break;
|
||||
}
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
break;
|
||||
case FPF_EXT:
|
||||
/* Only a single element. */
|
||||
break;
|
||||
default:
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
/* With a single element, we are only interested in bit 0. */
|
||||
tmp = tcg_temp_new_i64();
|
||||
read_vec_element_i64(tmp, v2, 0, ES_64);
|
||||
switch (m5) {
|
||||
case 0:
|
||||
/* sign bit is inverted (complement) */
|
||||
tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
|
||||
break;
|
||||
case 1:
|
||||
/* sign bit is set to one (negative) */
|
||||
tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
|
||||
break;
|
||||
case 2:
|
||||
/* sign bit is set to zero (positive) */
|
||||
tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
|
||||
break;
|
||||
}
|
||||
write_vec_element_i64(tmp, v1, 0, ES_64);
|
||||
|
||||
if (fpf == FPF_EXT) {
|
||||
read_vec_element_i64(tmp, v2, 1, ES_64);
|
||||
write_vec_element_i64(tmp, v1, 1, ES_64);
|
||||
}
|
||||
|
||||
tcg_temp_free_i64(tmp);
|
||||
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
@ -2682,18 +3043,32 @@ static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
const uint8_t fpf = get_field(s, m3);
|
||||
const uint8_t m4 = get_field(s, m4);
|
||||
gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfsq64;
|
||||
gen_helper_gvec_2_ptr *fn = NULL;
|
||||
|
||||
if (fpf != FPF_LONG || extract32(m4, 0, 3)) {
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfsq32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vfsq64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vfsq128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fn || extract32(m4, 0, 3)) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (extract32(m4, 3, 1)) {
|
||||
fn = gen_helper_gvec_vfsq64s;
|
||||
}
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
|
||||
0, fn);
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
@ -2702,17 +3077,33 @@ static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
|
||||
const uint16_t i3 = get_field(s, i3);
|
||||
const uint8_t fpf = get_field(s, m4);
|
||||
const uint8_t m5 = get_field(s, m5);
|
||||
gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vftci64;
|
||||
gen_helper_gvec_2_ptr *fn = NULL;
|
||||
|
||||
if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
|
||||
switch (fpf) {
|
||||
case FPF_SHORT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vftci32;
|
||||
}
|
||||
break;
|
||||
case FPF_LONG:
|
||||
fn = gen_helper_gvec_vftci64;
|
||||
break;
|
||||
case FPF_EXT:
|
||||
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
|
||||
fn = gen_helper_gvec_vftci128;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fn || extract32(m5, 0, 3)) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (extract32(m5, 3, 1)) {
|
||||
fn = gen_helper_gvec_vftci64s;
|
||||
}
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, i3, fn);
|
||||
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
|
||||
deposit32(m5, 4, 12, i3), fn);
|
||||
set_cc_static(s);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,28 @@
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3,
|
||||
uint32_t desc)
|
||||
{
|
||||
S390Vector tmp = {};
|
||||
uint16_t result = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
const uint8_t bit_nr = s390_vec_read_element8(v3, i);
|
||||
uint16_t bit;
|
||||
|
||||
if (bit_nr >= 128) {
|
||||
continue;
|
||||
}
|
||||
bit = (s390_vec_read_element8(v2, bit_nr / 8)
|
||||
>> (7 - (bit_nr % 8))) & 1;
|
||||
result |= (bit << (15 - i));
|
||||
}
|
||||
s390_vec_write_element16(&tmp, 3, result);
|
||||
*(S390Vector *)v1 = tmp;
|
||||
}
|
||||
|
||||
void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes)
|
||||
{
|
||||
if (likely(bytes >= 16)) {
|
||||
|
Loading…
Reference in New Issue
Block a user