1 /* 2 * S/390 condition code helper routines 3 * 4 * Copyright (c) 2009 Ulrich Hecht 5 * Copyright (c) 2009 Alexander Graf 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "cpu.h" 23 #include "s390x-internal.h" 24 #include "tcg_s390x.h" 25 #include "exec/helper-proto.h" 26 #include "qemu/host-utils.h" 27 28 /* #define DEBUG_HELPER */ 29 #ifdef DEBUG_HELPER 30 #define HELPER_LOG(x...) qemu_log(x) 31 #else 32 #define HELPER_LOG(x...) 33 #endif 34 35 static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst) 36 { 37 if (src == dst) { 38 return 0; 39 } else if (src < dst) { 40 return 1; 41 } else { 42 return 2; 43 } 44 } 45 46 static uint32_t cc_calc_ltgt0_32(int32_t dst) 47 { 48 return cc_calc_ltgt_32(dst, 0); 49 } 50 51 static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst) 52 { 53 if (src == dst) { 54 return 0; 55 } else if (src < dst) { 56 return 1; 57 } else { 58 return 2; 59 } 60 } 61 62 static uint32_t cc_calc_ltgt0_64(int64_t dst) 63 { 64 return cc_calc_ltgt_64(dst, 0); 65 } 66 67 static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst) 68 { 69 if (src == dst) { 70 return 0; 71 } else if (src < dst) { 72 return 1; 73 } else { 74 return 2; 75 } 76 } 77 78 static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst) 79 { 80 if (src == dst) { 81 return 0; 82 } else if (src < dst) { 83 return 1; 84 } else { 85 return 2; 86 } 87 } 88 89 static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask) 90 { 91 uint32_t r = val & mask; 92 93 if (r == 0) { 94 return 0; 95 } else if (r == mask) { 96 return 3; 97 } else { 98 return 1; 99 } 100 } 101 102 static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask) 103 { 104 uint64_t r = val & mask; 105 106 if (r == 0) { 107 return 0; 108 } else if (r == mask) { 109 return 3; 110 } else { 111 int top = clz64(mask); 112 if ((int64_t)(val << top) < 0) { 113 return 2; 114 } else { 115 return 1; 116 } 117 } 118 } 119 120 static uint32_t cc_calc_nz(uint64_t dst) 121 { 122 return !!dst; 123 } 124 125 static uint32_t cc_calc_addu(uint64_t carry_out, uint64_t result) 126 { 127 g_assert(carry_out <= 1); 128 return (result != 0) + 2 * carry_out; 129 } 130 131 static uint32_t cc_calc_subu(uint64_t borrow_out, uint64_t result) 132 { 133 return cc_calc_addu(borrow_out + 1, result); 134 } 135 136 static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar) 137 { 138 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar >= 0)) { 139 return 3; /* overflow */ 140 } else { 141 if (ar < 0) { 142 return 1; 143 } else if (ar > 0) { 144 return 2; 145 } else { 146 return 0; 147 } 148 } 149 } 150 151 static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar) 152 { 153 if ((a1 >= 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { 154 return 3; /* overflow */ 155 } else { 156 if (ar < 0) { 157 return 1; 158 } else if (ar > 0) { 159 return 2; 160 } else { 161 return 0; 162 } 163 } 164 } 165 166 static uint32_t cc_calc_abs_64(int64_t dst) 167 { 168 if ((uint64_t)dst == 0x8000000000000000ULL) { 169 return 3; 170 } else if (dst) { 171 return 2; 172 } else { 173 return 0; 174 } 175 } 176 177 static uint32_t cc_calc_nabs_64(int64_t dst) 178 { 179 return !!dst; 180 } 181 182 static uint32_t cc_calc_comp_64(int64_t dst) 183 { 184 if ((uint64_t)dst == 0x8000000000000000ULL) { 185 return 3; 186 } else if (dst < 0) { 187 return 1; 188 } else if (dst > 0) { 189 return 2; 190 } else { 191 return 0; 192 } 193 } 194 195 196 static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar) 197 { 198 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar >= 0)) { 199 return 3; /* overflow */ 200 } else { 201 if (ar < 0) { 202 return 1; 203 } else if (ar > 0) { 204 return 2; 205 } else { 206 return 0; 207 } 208 } 209 } 210 211 static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar) 212 { 213 if ((a1 >= 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { 214 return 3; /* overflow */ 215 } else { 216 if (ar < 0) { 217 return 1; 218 } else if (ar > 0) { 219 return 2; 220 } else { 221 return 0; 222 } 223 } 224 } 225 226 static uint32_t cc_calc_abs_32(int32_t dst) 227 { 228 if ((uint32_t)dst == 0x80000000UL) { 229 return 3; 230 } else if (dst) { 231 return 2; 232 } else { 233 return 0; 234 } 235 } 236 237 static uint32_t cc_calc_nabs_32(int32_t dst) 238 { 239 return !!dst; 240 } 241 242 static uint32_t cc_calc_comp_32(int32_t dst) 243 { 244 if ((uint32_t)dst == 0x80000000UL) { 245 return 3; 246 } else if (dst < 0) { 247 return 1; 248 } else if (dst > 0) { 249 return 2; 250 } else { 251 return 0; 252 } 253 } 254 255 /* calculate condition code for insert character under mask insn */ 256 static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) 257 { 258 if ((val & mask) == 0) { 259 return 0; 260 } else { 261 int top = clz64(mask); 262 if ((int64_t)(val << top) < 0) { 263 return 1; 264 } else { 265 return 2; 266 } 267 } 268 } 269 270 static uint32_t cc_calc_sla(uint64_t src, int shift) 271 { 272 uint64_t mask = -1ULL << (63 - shift); 273 uint64_t sign = 1ULL << 63; 274 uint64_t match; 275 int64_t r; 276 277 /* Check if the sign bit stays the same. */ 278 if (src & sign) { 279 match = mask; 280 } else { 281 match = 0; 282 } 283 if ((src & mask) != match) { 284 /* Overflow. */ 285 return 3; 286 } 287 288 r = ((src << shift) & ~sign) | (src & sign); 289 if (r == 0) { 290 return 0; 291 } else if (r < 0) { 292 return 1; 293 } 294 return 2; 295 } 296 297 static uint32_t cc_calc_flogr(uint64_t dst) 298 { 299 return dst ? 2 : 0; 300 } 301 302 static uint32_t cc_calc_lcbb(uint64_t dst) 303 { 304 return dst == 16 ? 0 : 3; 305 } 306 307 static uint32_t cc_calc_vc(uint64_t low, uint64_t high) 308 { 309 if (high == -1ull && low == -1ull) { 310 /* all elements match */ 311 return 0; 312 } else if (high == 0 && low == 0) { 313 /* no elements match */ 314 return 3; 315 } else { 316 /* some elements but not all match */ 317 return 1; 318 } 319 } 320 321 static uint32_t cc_calc_muls_32(int64_t res) 322 { 323 const int64_t tmp = res >> 31; 324 325 if (!res) { 326 return 0; 327 } else if (tmp && tmp != -1) { 328 return 3; 329 } else if (res < 0) { 330 return 1; 331 } 332 return 2; 333 } 334 335 static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low) 336 { 337 if (!res_high && !res_low) { 338 return 0; 339 } else if (res_high + (res_low >> 63) != 0) { 340 return 3; 341 } else if (res_high < 0) { 342 return 1; 343 } 344 return 2; 345 } 346 347 static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, 348 uint64_t src, uint64_t dst, uint64_t vr) 349 { 350 uint32_t r = 0; 351 352 switch (cc_op) { 353 case CC_OP_CONST0: 354 case CC_OP_CONST1: 355 case CC_OP_CONST2: 356 case CC_OP_CONST3: 357 /* cc_op value _is_ cc */ 358 r = cc_op; 359 break; 360 case CC_OP_LTGT0_32: 361 r = cc_calc_ltgt0_32(dst); 362 break; 363 case CC_OP_LTGT0_64: 364 r = cc_calc_ltgt0_64(dst); 365 break; 366 case CC_OP_LTGT_32: 367 r = cc_calc_ltgt_32(src, dst); 368 break; 369 case CC_OP_LTGT_64: 370 r = cc_calc_ltgt_64(src, dst); 371 break; 372 case CC_OP_LTUGTU_32: 373 r = cc_calc_ltugtu_32(src, dst); 374 break; 375 case CC_OP_LTUGTU_64: 376 r = cc_calc_ltugtu_64(src, dst); 377 break; 378 case CC_OP_TM_32: 379 r = cc_calc_tm_32(src, dst); 380 break; 381 case CC_OP_TM_64: 382 r = cc_calc_tm_64(src, dst); 383 break; 384 case CC_OP_NZ: 385 r = cc_calc_nz(dst); 386 break; 387 case CC_OP_ADDU: 388 r = cc_calc_addu(src, dst); 389 break; 390 case CC_OP_SUBU: 391 r = cc_calc_subu(src, dst); 392 break; 393 case CC_OP_ADD_64: 394 r = cc_calc_add_64(src, dst, vr); 395 break; 396 case CC_OP_SUB_64: 397 r = cc_calc_sub_64(src, dst, vr); 398 break; 399 case CC_OP_ABS_64: 400 r = cc_calc_abs_64(dst); 401 break; 402 case CC_OP_NABS_64: 403 r = cc_calc_nabs_64(dst); 404 break; 405 case CC_OP_COMP_64: 406 r = cc_calc_comp_64(dst); 407 break; 408 case CC_OP_MULS_64: 409 r = cc_calc_muls_64(src, dst); 410 break; 411 412 case CC_OP_ADD_32: 413 r = cc_calc_add_32(src, dst, vr); 414 break; 415 case CC_OP_SUB_32: 416 r = cc_calc_sub_32(src, dst, vr); 417 break; 418 case CC_OP_ABS_32: 419 r = cc_calc_abs_32(dst); 420 break; 421 case CC_OP_NABS_32: 422 r = cc_calc_nabs_32(dst); 423 break; 424 case CC_OP_COMP_32: 425 r = cc_calc_comp_32(dst); 426 break; 427 case CC_OP_MULS_32: 428 r = cc_calc_muls_32(dst); 429 break; 430 431 case CC_OP_ICM: 432 r = cc_calc_icm(src, dst); 433 break; 434 case CC_OP_SLA: 435 r = cc_calc_sla(src, dst); 436 break; 437 case CC_OP_FLOGR: 438 r = cc_calc_flogr(dst); 439 break; 440 case CC_OP_LCBB: 441 r = cc_calc_lcbb(dst); 442 break; 443 case CC_OP_VC: 444 r = cc_calc_vc(src, dst); 445 break; 446 447 case CC_OP_NZ_F32: 448 r = set_cc_nz_f32(dst); 449 break; 450 case CC_OP_NZ_F64: 451 r = set_cc_nz_f64(dst); 452 break; 453 case CC_OP_NZ_F128: 454 r = set_cc_nz_f128(make_float128(src, dst)); 455 break; 456 457 default: 458 cpu_abort(env_cpu(env), "Unknown CC operation: %s\n", cc_name(cc_op)); 459 } 460 461 HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, 462 cc_name(cc_op), src, dst, vr, r); 463 return r; 464 } 465 466 uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, 467 uint64_t vr) 468 { 469 return do_calc_cc(env, cc_op, src, dst, vr); 470 } 471 472 uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, 473 uint64_t dst, uint64_t vr) 474 { 475 return do_calc_cc(env, cc_op, src, dst, vr); 476 } 477 478 #ifndef CONFIG_USER_ONLY 479 void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) 480 { 481 s390_cpu_set_psw(env, mask, addr); 482 cpu_loop_exit(env_cpu(env)); 483 } 484 485 void HELPER(sacf)(CPUS390XState *env, uint64_t a1) 486 { 487 HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); 488 489 if (!(env->psw.mask & PSW_MASK_DAT)) { 490 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC()); 491 } 492 493 switch (a1 & 0xf00) { 494 case 0x000: 495 env->psw.mask &= ~PSW_MASK_ASC; 496 env->psw.mask |= PSW_ASC_PRIMARY; 497 break; 498 case 0x100: 499 env->psw.mask &= ~PSW_MASK_ASC; 500 env->psw.mask |= PSW_ASC_SECONDARY; 501 break; 502 case 0x300: 503 if ((env->psw.mask & PSW_MASK_PSTATE) != 0) { 504 tcg_s390_program_interrupt(env, PGM_PRIVILEGED, GETPC()); 505 } 506 env->psw.mask &= ~PSW_MASK_ASC; 507 env->psw.mask |= PSW_ASC_HOME; 508 break; 509 default: 510 HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1); 511 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 512 } 513 } 514 #endif 515