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