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 24static uint32_t compute_all_flags(CPUSPARCState *env) 25{ 26 return env->psr & PSR_ICC; 27} 28 29static uint32_t compute_C_flags(CPUSPARCState *env) 30{ 31 return env->psr & PSR_CARRY; 32} 33 34static 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 47static uint32_t compute_all_flags_xcc(CPUSPARCState *env) 48{ 49 return env->xcc & PSR_ICC; 50} 51 52static uint32_t compute_C_flags_xcc(CPUSPARCState *env) 53{ 54 return env->xcc & PSR_CARRY; 55} 56 57static 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 70static 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 80static 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 89static uint32_t compute_C_div(CPUSPARCState *env) 90{ 91 return 0; 92} 93 94static 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 104static 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 115static 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 127static 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 137static 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 148static 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 159static 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 169static uint32_t compute_C_add_xcc(CPUSPARCState *env) 170{ 171 return get_C_add_xcc(CC_DST, CC_SRC); 172} 173#endif 174 175static 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 185static uint32_t compute_C_add(CPUSPARCState *env) 186{ 187 return get_C_add_icc(CC_DST, CC_SRC); 188} 189 190#ifdef TARGET_SPARC64 191static 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 201static 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 207static 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 217static uint32_t compute_C_addx(CPUSPARCState *env) 218{ 219 return get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); 220} 221 222static 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 232static 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 243static 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 252static 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 262static 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 273static 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 286static 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 296static 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 307static 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 318static 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 328static uint32_t compute_C_sub_xcc(CPUSPARCState *env) 329{ 330 return get_C_sub_xcc(CC_SRC, CC_SRC2); 331} 332#endif 333 334static 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 344static uint32_t compute_C_sub(CPUSPARCState *env) 345{ 346 return get_C_sub_icc(CC_SRC, CC_SRC2); 347} 348 349#ifdef TARGET_SPARC64 350static 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 360static 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 366static 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 376static uint32_t compute_C_subx(CPUSPARCState *env) 377{ 378 return get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); 379} 380 381static 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 392static 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 401static uint32_t compute_all_logic(CPUSPARCState *env) 402{ 403 return get_NZ_icc(CC_DST); 404} 405 406static uint32_t compute_C_logic(CPUSPARCState *env) 407{ 408 return 0; 409} 410 411#ifdef TARGET_SPARC64 412static uint32_t compute_all_logic_xcc(CPUSPARCState *env) 413{ 414 return get_NZ_xcc(CC_DST); 415} 416#endif 417 418typedef 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 423static 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 439static 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 455void 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 468uint32_t helper_compute_C_icc(CPUSPARCState *env) 469{ 470 return icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT; 471}