cc_helper.c (10935B)
1 /* 2 * Helpers for lazy condition code handling 3 * 4 * Copyright (c) 2003-2005 Fabrice Bellard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "cpu.h" 22 #include "exec/helper-proto.h" 23 24 static uint32_t compute_all_flags(CPUSPARCState *env) 25 { 26 return env->psr & PSR_ICC; 27 } 28 29 static uint32_t compute_C_flags(CPUSPARCState *env) 30 { 31 return env->psr & PSR_CARRY; 32 } 33 34 static inline uint32_t get_NZ_icc(int32_t dst) 35 { 36 uint32_t ret = 0; 37 38 if (dst == 0) { 39 ret = PSR_ZERO; 40 } else if (dst < 0) { 41 ret = PSR_NEG; 42 } 43 return ret; 44 } 45 46 #ifdef TARGET_SPARC64 47 static uint32_t compute_all_flags_xcc(CPUSPARCState *env) 48 { 49 return env->xcc & PSR_ICC; 50 } 51 52 static uint32_t compute_C_flags_xcc(CPUSPARCState *env) 53 { 54 return env->xcc & PSR_CARRY; 55 } 56 57 static inline uint32_t get_NZ_xcc(target_long dst) 58 { 59 uint32_t ret = 0; 60 61 if (!dst) { 62 ret = PSR_ZERO; 63 } else if (dst < 0) { 64 ret = PSR_NEG; 65 } 66 return ret; 67 } 68 #endif 69 70 static inline uint32_t get_V_div_icc(target_ulong src2) 71 { 72 uint32_t ret = 0; 73 74 if (src2 != 0) { 75 ret = PSR_OVF; 76 } 77 return ret; 78 } 79 80 static uint32_t compute_all_div(CPUSPARCState *env) 81 { 82 uint32_t ret; 83 84 ret = get_NZ_icc(CC_DST); 85 ret |= get_V_div_icc(CC_SRC2); 86 return ret; 87 } 88 89 static uint32_t compute_C_div(CPUSPARCState *env) 90 { 91 return 0; 92 } 93 94 static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1) 95 { 96 uint32_t ret = 0; 97 98 if (dst < src1) { 99 ret = PSR_CARRY; 100 } 101 return ret; 102 } 103 104 static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1, 105 uint32_t src2) 106 { 107 uint32_t ret = 0; 108 109 if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) { 110 ret = PSR_CARRY; 111 } 112 return ret; 113 } 114 115 static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1, 116 uint32_t src2) 117 { 118 uint32_t ret = 0; 119 120 if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) { 121 ret = PSR_OVF; 122 } 123 return ret; 124 } 125 126 #ifdef TARGET_SPARC64 127 static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1) 128 { 129 uint32_t ret = 0; 130 131 if (dst < src1) { 132 ret = PSR_CARRY; 133 } 134 return ret; 135 } 136 137 static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1, 138 target_ulong src2) 139 { 140 uint32_t ret = 0; 141 142 if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) { 143 ret = PSR_CARRY; 144 } 145 return ret; 146 } 147 148 static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1, 149 target_ulong src2) 150 { 151 uint32_t ret = 0; 152 153 if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) { 154 ret = PSR_OVF; 155 } 156 return ret; 157 } 158 159 static uint32_t compute_all_add_xcc(CPUSPARCState *env) 160 { 161 uint32_t ret; 162 163 ret = get_NZ_xcc(CC_DST); 164 ret |= get_C_add_xcc(CC_DST, CC_SRC); 165 ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); 166 return ret; 167 } 168 169 static uint32_t compute_C_add_xcc(CPUSPARCState *env) 170 { 171 return get_C_add_xcc(CC_DST, CC_SRC); 172 } 173 #endif 174 175 static uint32_t compute_all_add(CPUSPARCState *env) 176 { 177 uint32_t ret; 178 179 ret = get_NZ_icc(CC_DST); 180 ret |= get_C_add_icc(CC_DST, CC_SRC); 181 ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); 182 return ret; 183 } 184 185 static uint32_t compute_C_add(CPUSPARCState *env) 186 { 187 return get_C_add_icc(CC_DST, CC_SRC); 188 } 189 190 #ifdef TARGET_SPARC64 191 static uint32_t compute_all_addx_xcc(CPUSPARCState *env) 192 { 193 uint32_t ret; 194 195 ret = get_NZ_xcc(CC_DST); 196 ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); 197 ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); 198 return ret; 199 } 200 201 static uint32_t compute_C_addx_xcc(CPUSPARCState *env) 202 { 203 return get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); 204 } 205 #endif 206 207 static uint32_t compute_all_addx(CPUSPARCState *env) 208 { 209 uint32_t ret; 210 211 ret = get_NZ_icc(CC_DST); 212 ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); 213 ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); 214 return ret; 215 } 216 217 static uint32_t compute_C_addx(CPUSPARCState *env) 218 { 219 return get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); 220 } 221 222 static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2) 223 { 224 uint32_t ret = 0; 225 226 if ((src1 | src2) & 0x3) { 227 ret = PSR_OVF; 228 } 229 return ret; 230 } 231 232 static uint32_t compute_all_tadd(CPUSPARCState *env) 233 { 234 uint32_t ret; 235 236 ret = get_NZ_icc(CC_DST); 237 ret |= get_C_add_icc(CC_DST, CC_SRC); 238 ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); 239 ret |= get_V_tag_icc(CC_SRC, CC_SRC2); 240 return ret; 241 } 242 243 static uint32_t compute_all_taddtv(CPUSPARCState *env) 244 { 245 uint32_t ret; 246 247 ret = get_NZ_icc(CC_DST); 248 ret |= get_C_add_icc(CC_DST, CC_SRC); 249 return ret; 250 } 251 252 static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2) 253 { 254 uint32_t ret = 0; 255 256 if (src1 < src2) { 257 ret = PSR_CARRY; 258 } 259 return ret; 260 } 261 262 static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1, 263 uint32_t src2) 264 { 265 uint32_t ret = 0; 266 267 if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) { 268 ret = PSR_CARRY; 269 } 270 return ret; 271 } 272 273 static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1, 274 uint32_t src2) 275 { 276 uint32_t ret = 0; 277 278 if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) { 279 ret = PSR_OVF; 280 } 281 return ret; 282 } 283 284 285 #ifdef TARGET_SPARC64 286 static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2) 287 { 288 uint32_t ret = 0; 289 290 if (src1 < src2) { 291 ret = PSR_CARRY; 292 } 293 return ret; 294 } 295 296 static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1, 297 target_ulong src2) 298 { 299 uint32_t ret = 0; 300 301 if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) { 302 ret = PSR_CARRY; 303 } 304 return ret; 305 } 306 307 static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1, 308 target_ulong src2) 309 { 310 uint32_t ret = 0; 311 312 if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) { 313 ret = PSR_OVF; 314 } 315 return ret; 316 } 317 318 static uint32_t compute_all_sub_xcc(CPUSPARCState *env) 319 { 320 uint32_t ret; 321 322 ret = get_NZ_xcc(CC_DST); 323 ret |= get_C_sub_xcc(CC_SRC, CC_SRC2); 324 ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); 325 return ret; 326 } 327 328 static uint32_t compute_C_sub_xcc(CPUSPARCState *env) 329 { 330 return get_C_sub_xcc(CC_SRC, CC_SRC2); 331 } 332 #endif 333 334 static uint32_t compute_all_sub(CPUSPARCState *env) 335 { 336 uint32_t ret; 337 338 ret = get_NZ_icc(CC_DST); 339 ret |= get_C_sub_icc(CC_SRC, CC_SRC2); 340 ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); 341 return ret; 342 } 343 344 static uint32_t compute_C_sub(CPUSPARCState *env) 345 { 346 return get_C_sub_icc(CC_SRC, CC_SRC2); 347 } 348 349 #ifdef TARGET_SPARC64 350 static uint32_t compute_all_subx_xcc(CPUSPARCState *env) 351 { 352 uint32_t ret; 353 354 ret = get_NZ_xcc(CC_DST); 355 ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); 356 ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); 357 return ret; 358 } 359 360 static uint32_t compute_C_subx_xcc(CPUSPARCState *env) 361 { 362 return get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); 363 } 364 #endif 365 366 static uint32_t compute_all_subx(CPUSPARCState *env) 367 { 368 uint32_t ret; 369 370 ret = get_NZ_icc(CC_DST); 371 ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); 372 ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); 373 return ret; 374 } 375 376 static uint32_t compute_C_subx(CPUSPARCState *env) 377 { 378 return get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); 379 } 380 381 static uint32_t compute_all_tsub(CPUSPARCState *env) 382 { 383 uint32_t ret; 384 385 ret = get_NZ_icc(CC_DST); 386 ret |= get_C_sub_icc(CC_SRC, CC_SRC2); 387 ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); 388 ret |= get_V_tag_icc(CC_SRC, CC_SRC2); 389 return ret; 390 } 391 392 static uint32_t compute_all_tsubtv(CPUSPARCState *env) 393 { 394 uint32_t ret; 395 396 ret = get_NZ_icc(CC_DST); 397 ret |= get_C_sub_icc(CC_SRC, CC_SRC2); 398 return ret; 399 } 400 401 static uint32_t compute_all_logic(CPUSPARCState *env) 402 { 403 return get_NZ_icc(CC_DST); 404 } 405 406 static uint32_t compute_C_logic(CPUSPARCState *env) 407 { 408 return 0; 409 } 410 411 #ifdef TARGET_SPARC64 412 static uint32_t compute_all_logic_xcc(CPUSPARCState *env) 413 { 414 return get_NZ_xcc(CC_DST); 415 } 416 #endif 417 418 typedef struct CCTable { 419 uint32_t (*compute_all)(CPUSPARCState *env); /* return all the flags */ 420 uint32_t (*compute_c)(CPUSPARCState *env); /* return the C flag */ 421 } CCTable; 422 423 static const CCTable icc_table[CC_OP_NB] = { 424 /* CC_OP_DYNAMIC should never happen */ 425 [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags }, 426 [CC_OP_DIV] = { compute_all_div, compute_C_div }, 427 [CC_OP_ADD] = { compute_all_add, compute_C_add }, 428 [CC_OP_ADDX] = { compute_all_addx, compute_C_addx }, 429 [CC_OP_TADD] = { compute_all_tadd, compute_C_add }, 430 [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add }, 431 [CC_OP_SUB] = { compute_all_sub, compute_C_sub }, 432 [CC_OP_SUBX] = { compute_all_subx, compute_C_subx }, 433 [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub }, 434 [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub }, 435 [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic }, 436 }; 437 438 #ifdef TARGET_SPARC64 439 static const CCTable xcc_table[CC_OP_NB] = { 440 /* CC_OP_DYNAMIC should never happen */ 441 [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc }, 442 [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic }, 443 [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc }, 444 [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc }, 445 [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc }, 446 [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc }, 447 [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, 448 [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc }, 449 [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, 450 [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc }, 451 [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic }, 452 }; 453 #endif 454 455 void helper_compute_psr(CPUSPARCState *env) 456 { 457 uint32_t new_psr; 458 459 new_psr = icc_table[CC_OP].compute_all(env); 460 env->psr = new_psr; 461 #ifdef TARGET_SPARC64 462 new_psr = xcc_table[CC_OP].compute_all(env); 463 env->xcc = new_psr; 464 #endif 465 CC_OP = CC_OP_FLAGS; 466 } 467 468 uint32_t helper_compute_C_icc(CPUSPARCState *env) 469 { 470 return icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT; 471 }