void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; ORB orig_orb, orb; uint64_t addr; CPUS390XState *env = &cpu->env; uint8_t ar; addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return; } if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) { s390_cpu_virt_mem_handle_exc(cpu, ra); return; } copy_orb_from_guest(&orb, &orig_orb); if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_orb_valid(&orb)) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("ssch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (!sch || !css_subch_visible(sch)) { setcc(cpu, 3); return; } setcc(cpu, css_do_ssch(sch, &orb)); }
/* DA E9 */ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FUCOMPP(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); BX_CPU_THIS_PTR FPU_update_last_instruction(i); if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1)) { FPU_exception(FPU_EX_Stack_Underflow); setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3); if(BX_CPU_THIS_PTR the_i387.is_IA_masked()) { BX_CPU_THIS_PTR the_i387.FPU_pop(); BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); } float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); int rc = floatx80_compare_quiet(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status); setcc(status_word_flags_fpu_compare(rc)); if (! FPU_exception(status.float_exception_flags)) { BX_CPU_THIS_PTR the_i387.FPU_pop(); BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); }
static void fptan(void) { FPU_REG *st_new_ptr; int q; char arg_sign = FPU_st0_ptr->sign; if (STACK_OVERFLOW) { stack_overflow(); return; } switch (FPU_st0_tag) { case TW_Valid: #ifdef DENORM_OPERAND if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) return; #endif /* DENORM_OPERAND */ FPU_st0_ptr->sign = SIGN_POS; if ((q = trig_arg(FPU_st0_ptr)) != -1) { if (q & 1) reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); poly_tan(FPU_st0_ptr, FPU_st0_ptr); FPU_st0_ptr->sign = (q & 1) ^ arg_sign; if (FPU_st0_ptr->exp <= EXP_UNDER) arith_underflow(FPU_st0_ptr); push(); reg_move(&CONST_1, FPU_st0_ptr); setcc(0); } else { /* Operand is out of range */ setcc(SW_C2); FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ return; } break; case TW_Infinity: /* Operand is out of range */ setcc(SW_C2); FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ return; case TW_Zero: push(); reg_move(&CONST_1, FPU_st0_ptr); setcc(0); break; default: single_arg_error(); break; } }
static void ftst_(void) { switch (FPU_st0_tag) { case TW_Zero: setcc(SW_C3); break; case TW_Valid: if (FPU_st0_ptr->sign == SIGN_POS) setcc(0); else setcc(SW_C0); break; case TW_NaN: setcc(SW_C2); /* Operand is not comparable */ EXCEPTION(EX_Invalid); break; case TW_Infinity: if (FPU_st0_ptr->sign == SIGN_POS) setcc(0); else setcc(SW_C3); /* setcc(SW_C0|SW_C2|SW_C3); */ EXCEPTION(EX_Invalid); break; case TW_Empty: setcc(SW_C0|SW_C2|SW_C3); EXCEPTION(EX_StackUnder); break; default: setcc(SW_C2); /* Operand is not comparable */ EXCEPTION(EX_INTERNAL|0x14); break; } }
static int compare_u_st_st(int nr) { int f = 0, c; FPU_REG *st_ptr; if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { setcc(SW_C3 | SW_C2 | SW_C0); /* */ EXCEPTION(EX_StackUnder); return !(control_word & CW_Invalid); } st_ptr = &st(nr); c = compare(st_ptr, FPU_gettagi(nr)); if (c & COMP_NaN) { setcc(SW_C3 | SW_C2 | SW_C0); if (c & COMP_SNaN) { /* */ EXCEPTION(EX_Invalid); return !(control_word & CW_Invalid); } return 0; } else switch (c & 7) { case COMP_A_lt_B: f = SW_C0; break; case COMP_A_eq_B: f = SW_C3; break; case COMP_A_gt_B: f = 0; break; case COMP_No_Comp: f = SW_C3 | SW_C2 | SW_C0; break; #ifdef PARANOID default: EXCEPTION(EX_INTERNAL | 0x123); f = SW_C3 | SW_C2 | SW_C0; break; #endif /* */ } setcc(f); if (c & COMP_Denormal) { return denormal_operand() < 0; } return 0; }
void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) { CRW *crw; uint64_t addr; int cc; hwaddr len = sizeof(*crw); CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); return; } crw = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!crw || len != sizeof(*crw)) { program_interrupt(env, PGM_ADDRESSING, 2); goto out; } cc = css_do_stcrw(crw); /* 0 - crw stored, 1 - zeroes stored */ setcc(cpu, cc); out: s390_cpu_physical_memory_unmap(env, crw, len, 1); }
void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra) { CRW crw; uint64_t addr; int cc; CPUS390XState *env = &cpu->env; uint8_t ar; addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return; } cc = css_do_stcrw(&crw); /* 0 - crw stored, 1 - zeroes stored */ if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) { setcc(cpu, cc); } else { if (cc == 0) { /* Write failed: requeue CRW since STCRW is suppressing */ css_undo_stcrw(&crw); } s390_cpu_virt_mem_handle_exc(cpu, ra); } }
static void fxam(void) { int c = 0; switch (FPU_st0_tag) { case TW_Empty: c = SW_C3 | SW_C0; break; case TW_Zero: c = SW_C3; break; case TW_Valid: /* This will need to be changed if TW_Denormal is ever used. */ if (FPU_st0_ptr->exp <= EXP_UNDER) c = SW_C2 | SW_C3; /* Denormal */ else c = SW_C3; break; case TW_NaN: c = SW_C0; break; case TW_Infinity: c = SW_C2 | SW_C0; break; } if (FPU_st0_ptr->sign == SIGN_NEG) c |= SW_C1; setcc(c); }
static void fxam(void) { int c=0; switch (FPU_st0_tag) { case TW_Empty: c = SW_C3|SW_C0; break; case TW_Zero: c = SW_C3; break; case TW_Valid: if (FPU_st0_ptr->sigh & 0x80000000) c = SW_C2; else c = SW_C3|SW_C2; break; case TW_NaN: c = SW_C0; break; case TW_Infinity: c = SW_C2|SW_C0; break; } if (FPU_st0_ptr->sign == SIGN_NEG) c |= SW_C1; setcc(c); }
static void fxam(FPU_REG *st0_ptr, u_char st0tag) { int c = 0; switch (st0tag) { case TAG_Empty: c = SW_C3 | SW_C0; break; case TAG_Zero: c = SW_C3; break; case TAG_Valid: c = SW_C2; break; case TAG_Special: switch (FPU_Special(st0_ptr)) { case TW_Denormal: c = SW_C2 | SW_C3; /* Denormal */ break; case TW_NaN: /* We also use NaN for unsupported types. */ if ((st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER)) c = SW_C0; break; case TW_Infinity: c = SW_C2 | SW_C0; break; } } if (getsign(st0_ptr) == SIGN_NEG) c |= SW_C1; setcc(c); }
void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1) { int cssid, ssid, schid, m; SubchDev *sch; int ret = -ENODEV; int cc; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { program_interrupt(&cpu->env, PGM_OPERAND, 2); return; } trace_ioinst_sch_id("hsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { ret = css_do_hsch(sch); } switch (ret) { case -ENODEV: cc = 3; break; case -EBUSY: cc = 2; break; case 0: cc = 0; break; default: cc = 1; break; } setcc(cpu, cc); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_DOUBLE_REAL(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); int pop_stack = i->nnn() & 1, rc; RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i)); BX_CPU_THIS_PTR FPU_update_last_instruction(i); clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3); if(BX_CPU_THIS_PTR the_i387.is_IA_masked()) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); } float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); floatx80 a = BX_READ_FPU_REG(0); if (floatx80_is_nan(a) || floatx80_is_unsupported(a) || float64_is_nan(load_reg)) { rc = float_relation_unordered; float_raise(status, float_flag_invalid); } else { rc = floatx80_compare(a, float64_to_floatx80(load_reg, status), status); } setcc(status_word_flags_fpu_compare(rc)); if (! FPU_exception(status.float_exception_flags)) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); }
void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; uint64_t addr; int cc; SCHIB schib; CPUS390XState *env = &cpu->env; uint8_t ar; addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); return; } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { /* * As operand exceptions have a lower priority than access exceptions, * we check whether the memory area is writeable (injecting the * access execption if it is not) first. */ if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { program_interrupt(env, PGM_OPERAND, 2); } return; } trace_ioinst_sch_id("stsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch) { if (css_subch_visible(sch)) { css_do_stsch(sch, &schib); cc = 0; } else { /* Indicate no more subchannels in this css/ss */ cc = 3; } } else { if (css_schid_final(m, cssid, ssid, schid)) { cc = 3; /* No more subchannels in this css/ss */ } else { /* Store an empty schib. */ memset(&schib, 0, sizeof(schib)); cc = 0; } } if (cc != 3) { if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib, sizeof(schib)) != 0) { return; } } else { /* Access exceptions have a higher priority than cc3 */ if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) { return; } } setcc(cpu, cc); }
void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("hsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (!sch || !css_subch_visible(sch)) { setcc(cpu, 3); return; } setcc(cpu, css_do_hsch(sch)); }
void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; ORB orig_orb, orb; uint64_t addr; int ret = -ENODEV; int cc; CPUS390XState *env = &cpu->env; uint8_t ar; addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); return; } if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) { return; } copy_orb_from_guest(&orb, &orig_orb); if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_orb_valid(&orb)) { program_interrupt(env, PGM_OPERAND, 2); return; } trace_ioinst_sch_id("ssch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { ret = css_do_ssch(sch, &orb); } switch (ret) { case -ENODEV: cc = 3; break; case -EBUSY: cc = 2; break; case -EFAULT: /* * TODO: * I'm wondering whether there is something better * to do for us here (like setting some device or * subchannel status). */ program_interrupt(env, PGM_ADDRESSING, 4); return; case 0: cc = 0; break; default: cc = 1; break; } setcc(cpu, cc); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FICOM_WORD_INTEGER(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); int pop_stack = i->nnn() & 1; RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i)); BX_CPU_THIS_PTR FPU_update_last_instruction(i); clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3); if(BX_CPU_THIS_PTR the_i387.is_IA_masked()) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); } float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); int rc = floatx80_compare(BX_READ_FPU_REG(0), int32_to_floatx80((Bit32s)(load_reg)), status); setcc(status_word_flags_fpu_compare(rc)); if (! FPU_exception(status.float_exception_flags)) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); }
void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; ORB *orig_orb, orb; uint64_t addr; int ret = -ENODEV; int cc; hwaddr len = sizeof(*orig_orb); CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); return; } orig_orb = s390_cpu_physical_memory_map(env, addr, &len, 0); if (!orig_orb || len != sizeof(*orig_orb)) { program_interrupt(env, PGM_ADDRESSING, 2); goto out; } copy_orb_from_guest(&orb, orig_orb); if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_orb_valid(&orb)) { program_interrupt(env, PGM_OPERAND, 2); goto out; } trace_ioinst_sch_id("ssch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { ret = css_do_ssch(sch, &orb); } switch (ret) { case -ENODEV: cc = 3; break; case -EBUSY: cc = 2; break; case 0: cc = 0; break; default: cc = 1; break; } setcc(cpu, cc); out: s390_cpu_physical_memory_unmap(env, orig_orb, len, 0); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_STi(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); BX_CPU_THIS_PTR FPU_update_last_instruction(i); int pop_stack = i->nnn() & 1; // handle special case of FSTP opcode @ 0xDE 0xD0..D7 if (i->b1() == 0xde) pop_stack = 1; clear_C1(); if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i->rm())) { FPU_exception(FPU_EX_Stack_Underflow); setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3); if(BX_CPU_THIS_PTR the_i387.is_IA_masked()) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); } float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); int rc = floatx80_compare(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i->rm()), status); setcc(status_word_flags_fpu_compare(rc)); if (! FPU_exception(status.float_exception_flags)) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); }
void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; uint64_t addr; int cc; SCHIB *schib; hwaddr len = sizeof(*schib); CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); return; } schib = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!schib || len != sizeof(*schib)) { program_interrupt(env, PGM_ADDRESSING, 2); goto out; } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { program_interrupt(env, PGM_OPERAND, 2); goto out; } trace_ioinst_sch_id("stsch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch) { if (css_subch_visible(sch)) { css_do_stsch(sch, schib); cc = 0; } else { /* Indicate no more subchannels in this css/ss */ cc = 3; } } else { if (css_schid_final(m, cssid, ssid, schid)) { cc = 3; /* No more subchannels in this css/ss */ } else { /* Store an empty schib. */ memset(schib, 0, sizeof(*schib)); cc = 0; } } setcc(cpu, cc); out: s390_cpu_physical_memory_unmap(env, schib, len, 1); }
/* D9 E4 */ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FTST(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); BX_CPU_THIS_PTR FPU_update_last_instruction(i); clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3); } else { extern const floatx80 Const_Z; float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); int rc = floatx80_compare(BX_READ_FPU_REG(0), Const_Z, status); setcc(status_word_flags_fpu_compare(rc)); FPU_exception(status.float_exception_flags); } BX_NEXT_INSTR(i); }
int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) { CPUS390XState *env = &cpu->env; int cssid, ssid, schid, m; SubchDev *sch; IRB irb; uint64_t addr; int cc, irb_len; uint8_t ar; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return -EIO; } trace_ioinst_sch_id("tsch", cssid, ssid, schid); addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return -EIO; } sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { cc = css_do_tsch_get_irb(sch, &irb, &irb_len); } else { cc = 3; } /* 0 - status pending, 1 - not status pending, 3 - not operational */ if (cc != 3) { if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) { s390_cpu_virt_mem_handle_exc(cpu, ra); return -EFAULT; } css_do_tsch_update_subch(sch); } else { irb_len = sizeof(irb) - sizeof(irb.emw); /* Access exceptions have a higher priority than cc3 */ if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) { s390_cpu_virt_mem_handle_exc(cpu, ra); return -EFAULT; } } setcc(cpu, cc); return 0; }
void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) { int cssid, ssid, schid, m; SubchDev *sch; SCHIB schib; uint64_t addr; int ret = -ENODEV; int cc; CPUS390XState *env = &cpu->env; uint8_t ar; addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); return; } if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) { return; } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_schib_valid(&schib)) { program_interrupt(env, PGM_OPERAND, 2); return; } trace_ioinst_sch_id("msch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { ret = css_do_msch(sch, &schib); } switch (ret) { case -ENODEV: cc = 3; break; case -EBUSY: cc = 2; break; case 0: cc = 0; break; default: cc = 1; break; } setcc(cpu, cc); }
static void ftst_(void) { switch (FPU_st0_tag) { case TW_Zero: setcc(SW_C3); break; case TW_Valid: #ifdef DENORM_OPERAND if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) return; #endif /* DENORM_OPERAND */ if (FPU_st0_ptr->sign == SIGN_POS) setcc(0); else setcc(SW_C0); break; case TW_NaN: setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ EXCEPTION(EX_Invalid); break; case TW_Infinity: if (FPU_st0_ptr->sign == SIGN_POS) setcc(0); else setcc(SW_C0); EXCEPTION(EX_Invalid); break; case TW_Empty: setcc(SW_C0 | SW_C2 | SW_C3); EXCEPTION(EX_StackUnder); break; default: setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ EXCEPTION(EX_INTERNAL | 0x14); break; } }
void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1) { int cssid, ssid, schid, m; SubchDev *sch; int ret = -ENODEV; int cc; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { program_interrupt(&cpu->env, PGM_OPERAND, 2); return; } trace_ioinst_sch_id("csch", cssid, ssid, schid); sch = css_find_subch(m, cssid, ssid, schid); if (sch && css_subch_visible(sch)) { ret = css_do_csch(sch); } if (ret == -ENODEV) { cc = 3; } else { cc = 0; } setcc(cpu, cc); }
int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) { int f = 0, c; c = compare(loaded_data, loaded_tag); if (c & COMP_NaN) { EXCEPTION(EX_Invalid); f = SW_C3 | SW_C2 | SW_C0; } else switch (c & 7) { case COMP_A_lt_B: f = SW_C0; break; case COMP_A_eq_B: f = SW_C3; break; case COMP_A_gt_B: f = 0; break; case COMP_No_Comp: f = SW_C3 | SW_C2 | SW_C0; break; #ifdef PARANOID default: EXCEPTION(EX_INTERNAL | 0x121); f = SW_C3 | SW_C2 | SW_C0; break; #endif /* */ } setcc(f); if (c & COMP_Denormal) { return denormal_operand() < 0; } return 0; }
rmove() { register struct node *p; register int r; register r1, flt; for (p=first.forw; p!=0; p = p->forw) { flt = 0; switch (p->op) { case MOVF: case MOVFO: case MOVOF: flt = NREG; case MOV: if (p->subop==BYTE) goto dble; dualop(p); if ((r = findrand(regs[RT1], flt)) >= 0) { if (r == flt+isreg(regs[RT2]) && p->forw->op!=CBR && p->forw->op!=SXT && p->forw->op!=CFCC) { p->forw->back = p->back; p->back->forw = p->forw; redunm++; continue; } } if (equstr(regs[RT1], "$0")) { p->op = CLR; strcpy(regs[RT1], regs[RT2]); regs[RT2][0] = 0; p->code = copy(1, regs[RT1]); goto sngl; } repladdr(p, 0, flt); r = isreg(regs[RT1]); r1 = isreg(regs[RT2]); dest(regs[RT2], flt); if (r >= 0) if (r1 >= 0) savereg(r1+flt, regs[r+flt]); else savereg(r+flt, regs[RT2]); else if (r1 >= 0) savereg(r1+flt, regs[RT1]); else setcon(regs[RT1], regs[RT2]); source(regs[RT1]); setcc(regs[RT2]); continue; case ADDF: case SUBF: case DIVF: case MULF: flt = NREG; goto dble; case ADD: case SUB: case BIC: case BIS: case MUL: case DIV: case ASH: dble: dualop(p); if (p->op==BIC && (equstr(regs[RT1], "$-1") || equstr(regs[RT1], "$177777"))) { p->op = CLR; strcpy(regs[RT1], regs[RT2]); regs[RT2][0] = 0; p->code = copy(1, regs[RT1]); goto sngl; } if ((p->op==BIC || p->op==BIS) && equstr(regs[RT1], "$0")) { if (p->forw->op!=CBR) { p->back->forw = p->forw; p->forw->back = p->back; continue; } } repladdr(p, 0, flt); source(regs[RT1]); dest(regs[RT2], flt); if (p->op==DIV && (r = isreg(regs[RT2])>=0)) regs[r+1][0] = 0; ccloc[0] = 0; continue; case CLRF: case NEGF: flt = NREG; case CLR: case COM: case INC: case DEC: case NEG: case ASR: case ASL: case SXT: singop(p); sngl: dest(regs[RT1], flt); if (p->op==CLR && flt==0) if ((r = isreg(regs[RT1])) >= 0) savereg(r, "$0"); else setcon("$0", regs[RT1]); ccloc[0] = 0; continue; case TSTF: flt = NREG; case TST: singop(p); repladdr(p, 0, flt); source(regs[RT1]); if (equstr(regs[RT1], ccloc)) { p->back->forw = p->forw; p->forw->back = p->back; p = p->back; nrtst++; nchange++; } continue; case CMPF: flt = NREG; case CMP: case BIT: dualop(p); source(regs[RT1]); source(regs[RT2]); if(p->op==BIT) { if (equstr(regs[RT1], "$-1") || equstr(regs[RT1], "$177777")) { p->op = TST; strcpy(regs[RT1], regs[RT2]); regs[RT2][0] = 0; p->code = copy(1, regs[RT1]); nchange++; nsaddr++; } else if (equstr(regs[RT2], "$-1") || equstr(regs[RT2], "$177777")) { p->op = TST; regs[RT2][0] = 0; p->code = copy(1, regs[RT1]); nchange++; nsaddr++; } if (equstr(regs[RT1], "$0")) { p->op = TST; regs[RT2][0] = 0; p->code = copy(1, regs[RT1]); nchange++; nsaddr++; } else if (equstr(regs[RT2], "$0")) { p->op = TST; strcpy(regs[RT1], regs[RT2]); regs[RT2][0] = 0; p->code = copy(1, regs[RT1]); nchange++; nsaddr++; } } repladdr(p, 1, flt); ccloc[0] = 0; continue; case CBR: if (p->back->op==TST || p->back->op==CMP) { if (p->back->op==TST) { singop(p->back); savereg(RT2, "$0"); } else dualop(p->back); r = compare(p->subop, findcon(RT1), findcon(RT2)); if (r==0) { p->back->back->forw = p->forw; p->forw->back = p->back->back; decref(p->ref); p = p->back->back; nchange++; } else if (r>0) { p->op = JBR; p->subop = 0; p->back->back->forw = p; p->back = p->back->back; p = p->back; nchange++; } } case CFCC: ccloc[0] = 0; continue; case JBR: redunbr(p); default: clearreg(); } } }
static void fptan(FPU_REG *st0_ptr, u_char st0_tag) { FPU_REG *st_new_ptr; int q; u_char arg_sign = getsign(st0_ptr); if (st0_tag == TAG_Empty) { FPU_stack_underflow(); if (control_word & CW_Invalid) { st_new_ptr = &st(-1); push(); FPU_stack_underflow(); } return; } if (STACK_OVERFLOW) { FPU_stack_overflow(); return; } if (st0_tag == TAG_Valid) { if (exponent(st0_ptr) > -40) { if ((q = trig_arg(st0_ptr, 0)) == -1) { return; } poly_tan(st0_ptr); setsign(st0_ptr, (q & 1) ^ (arg_sign != 0)); set_precision_flag_up(); } else { denormal_arg: FPU_to_exp16(st0_ptr, st0_ptr); st0_tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign); FPU_settag0(st0_tag); } push(); FPU_copy_to_reg0(&CONST_1, TAG_Valid); return; } if (st0_tag == TAG_Zero) { push(); FPU_copy_to_reg0(&CONST_1, TAG_Valid); setcc(0); return; } if (st0_tag == TAG_Special) st0_tag = FPU_Special(st0_ptr); if (st0_tag == TW_Denormal) { if (denormal_operand() < 0) return; goto denormal_arg; } if (st0_tag == TW_Infinity) { if (arith_invalid(0) >= 0) { st_new_ptr = &st(-1); push(); arith_invalid(0); } return; } single_arg_2_error(st0_ptr, st0_tag); }
rmove() { register struct node *p; register char *cp; register int r; int r1, flt; for (p=first.forw; p!=0; p = p->forw) { if (debug) { for (r=0; r<2*NREG; r++) if (regs[r][0]) printf("%d: %s\n", r, regs[r]); printf("-\n"); } flt = 0; switch (p->op) { case MOVF: case MOVFO: case MOVOF: flt = NREG; case MOV: dualop(p); if ((r = findrand(regs[RT1], flt)) >= 0) { if (r == flt+isreg(regs[RT2]) && p->forw->op!=CBR) { p->forw->back = p->back; p->back->forw = p->forw; redunm++; continue; } } repladdr(p, 0, flt); r = isreg(regs[RT1]); r1 = isreg(regs[RT2]); dest(regs[RT2], flt); if (r >= 0) if (r1 >= 0) savereg(r1+flt, regs[r+flt]); else savereg(r+flt, regs[RT2]); else if (r1 >= 0) savereg(r1+flt, regs[RT1]); else setcon(regs[RT1], regs[RT2]); source(regs[RT1]); setcc(regs[RT2]); continue; case ADDF: case SUBF: case DIVF: case MULF: flt = NREG; case ADD: case SUB: case BIC: case BIS: case MUL: case DIV: case ASH: dualop(p); repladdr(p, 0, flt); source(regs[RT1]); dest(regs[RT2], flt); if (p->op==DIV && (r = isreg(regs[RT2])>=0)) regs[r+1][0] = 0; ccloc[0] = 0; continue; case CLRF: case NEGF: flt = NREG; case CLR: case COM: case INC: case DEC: case NEG: case ASR: case ASL: case SXT: singop(p); dest(regs[RT1], flt); if (p->op==CLR && flt==0) if ((r = isreg(regs[RT1])) >= 0) savereg(r, "$0"); else setcon("$0", regs[RT1]); setcc(regs[RT1]); continue; case TSTF: flt = NREG; case TST: singop(p); repladdr(p, 0, flt); source(regs[RT1]); if (equstr(regs[RT1], ccloc)) { p->back->forw = p->forw; p->forw->back = p->back; p = p->back; nrtst++; nchange++; } continue; case CMPF: flt = NREG; case CMP: case BIT: dualop(p); source(regs[RT1]); source(regs[RT2]); repladdr(p, 1, flt); ccloc[0] = 0; continue; case CBR: case CFCC: ccloc[0] = 0; continue; case JBR: redunbr(p); default: clearreg(); } } }
static void ftst_(FPU_REG *st0_ptr, u_char st0tag) { switch (st0tag) { case TAG_Zero: setcc(SW_C3); break; case TAG_Valid: if (getsign(st0_ptr) == SIGN_POS) setcc(0); else setcc(SW_C0); break; case TAG_Special: switch (FPU_Special(st0_ptr)) { case TW_Denormal: if (getsign(st0_ptr) == SIGN_POS) setcc(0); else setcc(SW_C0); if (denormal_operand() < 0) { #ifdef PECULIAR_486 /* This is weird! */ if (getsign(st0_ptr) == SIGN_POS) setcc(SW_C3); #endif /* PECULIAR_486 */ return; } break; case TW_NaN: setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ EXCEPTION(EX_Invalid); break; case TW_Infinity: if (getsign(st0_ptr) == SIGN_POS) setcc(0); else setcc(SW_C0); break; default: setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ EXCEPTION(EX_INTERNAL | 0x14); break; } break; case TAG_Empty: setcc(SW_C0 | SW_C2 | SW_C3); EXCEPTION(EX_StackUnder); break; } }
/* D9 E5 */ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FXAM(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); BX_CPU_THIS_PTR FPU_update_last_instruction(i); floatx80 reg = BX_READ_FPU_REG(0); int sign = floatx80_sign(reg); /* * Examine the contents of the ST(0) register and sets the condition * code flags C0, C2 and C3 in the FPU status word to indicate the * class of value or number in the register. */ if (IS_TAG_EMPTY(0)) { setcc(FPU_SW_C3|FPU_SW_C1|FPU_SW_C0); } else { float_class_t aClass = floatx80_class(reg); switch(aClass) { case float_zero: setcc(FPU_SW_C3|FPU_SW_C1); break; case float_NaN: // unsupported handled as NaNs if (floatx80_is_unsupported(reg)) { setcc(FPU_SW_C1); } else { setcc(FPU_SW_C1|FPU_SW_C0); } break; case float_negative_inf: case float_positive_inf: setcc(FPU_SW_C2|FPU_SW_C1|FPU_SW_C0); break; case float_denormal: setcc(FPU_SW_C3|FPU_SW_C2|FPU_SW_C1); break; case float_normalized: setcc(FPU_SW_C2|FPU_SW_C1); break; } } /* * The C1 flag is set to the sign of the value in ST(0), regardless * of whether the register is empty or full. */ if (! sign) clear_C1(); BX_NEXT_INSTR(i); }