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(uint64_t src, int shift) 272 { 273 uint64_t mask = -1ULL << (63 - shift); 274 uint64_t sign = 1ULL << 63; 275 uint64_t match; 276 int64_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_flogr(uint64_t dst) 299 { 300 return dst ? 2 : 0; 301 } 302 303 static uint32_t cc_calc_lcbb(uint64_t dst) 304 { 305 return dst == 16 ? 0 : 3; 306 } 307 308 static uint32_t cc_calc_vc(uint64_t low, uint64_t high) 309 { 310 if (high == -1ull && low == -1ull) { 311 /* all elements match */ 312 return 0; 313 } else if (high == 0 && low == 0) { 314 /* no elements match */ 315 return 3; 316 } else { 317 /* some elements but not all match */ 318 return 1; 319 } 320 } 321 322 static uint32_t cc_calc_muls_32(int64_t res) 323 { 324 const int64_t tmp = res >> 31; 325 326 if (!res) { 327 return 0; 328 } else if (tmp && tmp != -1) { 329 return 3; 330 } else if (res < 0) { 331 return 1; 332 } 333 return 2; 334 } 335 336 static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low) 337 { 338 if (!res_high && !res_low) { 339 return 0; 340 } else if (res_high + (res_low >> 63) != 0) { 341 return 3; 342 } else if (res_high < 0) { 343 return 1; 344 } 345 return 2; 346 } 347 348 static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, 349 uint64_t src, uint64_t dst, uint64_t vr) 350 { 351 uint32_t r = 0; 352 353 switch (cc_op) { 354 case CC_OP_CONST0: 355 case CC_OP_CONST1: 356 case CC_OP_CONST2: 357 case CC_OP_CONST3: 358 /* cc_op value _is_ cc */ 359 r = cc_op; 360 break; 361 case CC_OP_LTGT0_32: 362 r = cc_calc_ltgt0_32(dst); 363 break; 364 case CC_OP_LTGT0_64: 365 r = cc_calc_ltgt0_64(dst); 366 break; 367 case CC_OP_LTGT_32: 368 r = cc_calc_ltgt_32(src, dst); 369 break; 370 case CC_OP_LTGT_64: 371 r = cc_calc_ltgt_64(src, dst); 372 break; 373 case CC_OP_LTUGTU_32: 374 r = cc_calc_ltugtu_32(src, dst); 375 break; 376 case CC_OP_LTUGTU_64: 377 r = cc_calc_ltugtu_64(src, dst); 378 break; 379 case CC_OP_TM_32: 380 r = cc_calc_tm_32(src, dst); 381 break; 382 case CC_OP_TM_64: 383 r = cc_calc_tm_64(src, dst); 384 break; 385 case CC_OP_NZ: 386 r = cc_calc_nz(dst); 387 break; 388 case CC_OP_ADDU: 389 r = cc_calc_addu(src, dst); 390 break; 391 case CC_OP_SUBU: 392 r = cc_calc_subu(src, dst); 393 break; 394 case CC_OP_ADD_64: 395 r = cc_calc_add_64(src, dst, vr); 396 break; 397 case CC_OP_SUB_64: 398 r = cc_calc_sub_64(src, dst, vr); 399 break; 400 case CC_OP_ABS_64: 401 r = cc_calc_abs_64(dst); 402 break; 403 case CC_OP_NABS_64: 404 r = cc_calc_nabs_64(dst); 405 break; 406 case CC_OP_COMP_64: 407 r = cc_calc_comp_64(dst); 408 break; 409 case CC_OP_MULS_64: 410 r = cc_calc_muls_64(src, dst); 411 break; 412 413 case CC_OP_ADD_32: 414 r = cc_calc_add_32(src, dst, vr); 415 break; 416 case CC_OP_SUB_32: 417 r = cc_calc_sub_32(src, dst, vr); 418 break; 419 case CC_OP_ABS_32: 420 r = cc_calc_abs_32(dst); 421 break; 422 case CC_OP_NABS_32: 423 r = cc_calc_nabs_32(dst); 424 break; 425 case CC_OP_COMP_32: 426 r = cc_calc_comp_32(dst); 427 break; 428 case CC_OP_MULS_32: 429 r = cc_calc_muls_32(dst); 430 break; 431 432 case CC_OP_ICM: 433 r = cc_calc_icm(src, dst); 434 break; 435 case CC_OP_SLA: 436 r = cc_calc_sla(src, dst); 437 break; 438 case CC_OP_FLOGR: 439 r = cc_calc_flogr(dst); 440 break; 441 case CC_OP_LCBB: 442 r = cc_calc_lcbb(dst); 443 break; 444 case CC_OP_VC: 445 r = cc_calc_vc(src, dst); 446 break; 447 448 case CC_OP_NZ_F32: 449 r = set_cc_nz_f32(dst); 450 break; 451 case CC_OP_NZ_F64: 452 r = set_cc_nz_f64(dst); 453 break; 454 case CC_OP_NZ_F128: 455 r = set_cc_nz_f128(make_float128(src, dst)); 456 break; 457 458 default: 459 cpu_abort(env_cpu(env), "Unknown CC operation: %s\n", cc_name(cc_op)); 460 } 461 462 HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, 463 cc_name(cc_op), src, dst, vr, r); 464 return r; 465 } 466 467 uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, 468 uint64_t vr) 469 { 470 return do_calc_cc(env, cc_op, src, dst, vr); 471 } 472 473 uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, 474 uint64_t dst, uint64_t vr) 475 { 476 return do_calc_cc(env, cc_op, src, dst, vr); 477 } 478 479 #ifndef CONFIG_USER_ONLY 480 void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) 481 { 482 s390_cpu_set_psw(env, mask, addr); 483 cpu_loop_exit(env_cpu(env)); 484 } 485 486 void HELPER(sacf)(CPUS390XState *env, uint64_t a1) 487 { 488 HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); 489 490 switch (a1 & 0xf00) { 491 case 0x000: 492 env->psw.mask &= ~PSW_MASK_ASC; 493 env->psw.mask |= PSW_ASC_PRIMARY; 494 break; 495 case 0x100: 496 env->psw.mask &= ~PSW_MASK_ASC; 497 env->psw.mask |= PSW_ASC_SECONDARY; 498 break; 499 case 0x300: 500 env->psw.mask &= ~PSW_MASK_ASC; 501 env->psw.mask |= PSW_ASC_HOME; 502 break; 503 default: 504 HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1); 505 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 506 } 507 } 508 #endif 509