1 /* 2 * SH4 emulation 3 * 4 * Copyright (c) 2005 Samuel Tardieu 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 #include "qemu/osdep.h" 20 #include "cpu.h" 21 #include "exec/helper-proto.h" 22 #include "accel/tcg/cpu-ldst.h" 23 #include "fpu/softfloat.h" 24 25 #ifndef CONFIG_USER_ONLY 26 27 void superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 28 MMUAccessType access_type, 29 int mmu_idx, uintptr_t retaddr) 30 { 31 cpu_env(cs)->tea = addr; 32 switch (access_type) { 33 case MMU_INST_FETCH: 34 case MMU_DATA_LOAD: 35 cs->exception_index = 0x0e0; 36 break; 37 case MMU_DATA_STORE: 38 cs->exception_index = 0x100; 39 break; 40 default: 41 g_assert_not_reached(); 42 } 43 cpu_loop_exit_restore(cs, retaddr); 44 } 45 46 #endif 47 48 void helper_ldtlb(CPUSH4State *env) 49 { 50 #ifdef CONFIG_USER_ONLY 51 cpu_abort(env_cpu(env), "Unhandled ldtlb"); 52 #else 53 cpu_load_tlb(env); 54 #endif 55 } 56 57 static inline G_NORETURN 58 void raise_exception(CPUSH4State *env, int index, 59 uintptr_t retaddr) 60 { 61 CPUState *cs = env_cpu(env); 62 63 cs->exception_index = index; 64 cpu_loop_exit_restore(cs, retaddr); 65 } 66 67 void helper_raise_illegal_instruction(CPUSH4State *env) 68 { 69 raise_exception(env, 0x180, 0); 70 } 71 72 void helper_raise_slot_illegal_instruction(CPUSH4State *env) 73 { 74 raise_exception(env, 0x1a0, 0); 75 } 76 77 void helper_raise_fpu_disable(CPUSH4State *env) 78 { 79 raise_exception(env, 0x800, 0); 80 } 81 82 void helper_raise_slot_fpu_disable(CPUSH4State *env) 83 { 84 raise_exception(env, 0x820, 0); 85 } 86 87 void helper_sleep(CPUSH4State *env) 88 { 89 CPUState *cs = env_cpu(env); 90 91 cs->halted = 1; 92 env->in_sleep = 1; 93 raise_exception(env, EXCP_HLT, 0); 94 } 95 96 void helper_trapa(CPUSH4State *env, uint32_t tra) 97 { 98 env->tra = tra << 2; 99 raise_exception(env, 0x160, 0); 100 } 101 102 void helper_exclusive(CPUSH4State *env) 103 { 104 /* We do not want cpu_restore_state to run. */ 105 cpu_loop_exit_atomic(env_cpu(env), 0); 106 } 107 108 void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value) 109 { 110 if (cpu_sh4_is_cached (env, address)) 111 { 112 memory_content *r = g_new(memory_content, 1); 113 114 r->address = address; 115 r->value = value; 116 r->next = NULL; 117 118 *(env->movcal_backup_tail) = r; 119 env->movcal_backup_tail = &(r->next); 120 } 121 } 122 123 void helper_discard_movcal_backup(CPUSH4State *env) 124 { 125 memory_content *current = env->movcal_backup; 126 127 while(current) 128 { 129 memory_content *next = current->next; 130 g_free(current); 131 env->movcal_backup = current = next; 132 if (current == NULL) 133 env->movcal_backup_tail = &(env->movcal_backup); 134 } 135 } 136 137 void helper_ocbi(CPUSH4State *env, uint32_t address) 138 { 139 memory_content **current = &(env->movcal_backup); 140 while (*current) 141 { 142 uint32_t a = (*current)->address; 143 if ((a & ~0x1F) == (address & ~0x1F)) 144 { 145 memory_content *next = (*current)->next; 146 cpu_stl_data(env, a, (*current)->value); 147 148 if (next == NULL) 149 { 150 env->movcal_backup_tail = current; 151 } 152 153 g_free(*current); 154 *current = next; 155 break; 156 } 157 } 158 } 159 160 void helper_macl(CPUSH4State *env, int32_t arg0, int32_t arg1) 161 { 162 const int64_t min = -(1ll << 47); 163 const int64_t max = (1ll << 47) - 1; 164 int64_t mul = (int64_t)arg0 * arg1; 165 int64_t mac = env->mac; 166 int64_t res; 167 168 if (!(env->sr & (1u << SR_S))) { 169 res = mac + mul; 170 } else if (sadd64_overflow(mac, mul, &res)) { 171 res = mac < 0 ? min : max; 172 } else { 173 res = MIN(MAX(res, min), max); 174 } 175 176 env->mac = res; 177 } 178 179 void helper_macw(CPUSH4State *env, int32_t arg0, int32_t arg1) 180 { 181 /* Inputs are already sign-extended from 16 bits. */ 182 int32_t mul = arg0 * arg1; 183 184 if (env->sr & (1u << SR_S)) { 185 /* 186 * In saturation arithmetic mode, the accumulator is 32-bit 187 * with carry. MACH is not considered during the addition 188 * operation nor the 32-bit saturation logic. 189 */ 190 int32_t res, macl = env->macl; 191 192 if (sadd32_overflow(macl, mul, &res)) { 193 res = macl < 0 ? INT32_MIN : INT32_MAX; 194 /* If overflow occurs, the MACH register is set to 1. */ 195 env->mach = 1; 196 } 197 env->macl = res; 198 } else { 199 /* In non-saturation arithmetic mode, the accumulator is 64-bit */ 200 env->mac += mul; 201 } 202 } 203 204 void helper_ld_fpscr(CPUSH4State *env, uint32_t val) 205 { 206 env->fpscr = val & FPSCR_MASK; 207 if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) { 208 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 209 } else { 210 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 211 } 212 set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status); 213 } 214 215 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr) 216 { 217 int xcpt, cause, enable; 218 219 xcpt = get_float_exception_flags(&env->fp_status); 220 221 /* Clear the cause entries */ 222 env->fpscr &= ~FPSCR_CAUSE_MASK; 223 224 if (unlikely(xcpt)) { 225 if (xcpt & float_flag_invalid) { 226 env->fpscr |= FPSCR_CAUSE_V; 227 } 228 if (xcpt & float_flag_divbyzero) { 229 env->fpscr |= FPSCR_CAUSE_Z; 230 } 231 if (xcpt & float_flag_overflow) { 232 env->fpscr |= FPSCR_CAUSE_O; 233 } 234 if (xcpt & float_flag_underflow) { 235 env->fpscr |= FPSCR_CAUSE_U; 236 } 237 if (xcpt & float_flag_inexact) { 238 env->fpscr |= FPSCR_CAUSE_I; 239 } 240 241 /* Accumulate in flag entries */ 242 env->fpscr |= (env->fpscr & FPSCR_CAUSE_MASK) 243 >> (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT); 244 245 /* Generate an exception if enabled */ 246 cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT; 247 enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT; 248 if (cause & enable) { 249 raise_exception(env, 0x120, retaddr); 250 } 251 } 252 } 253 254 float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1) 255 { 256 set_float_exception_flags(0, &env->fp_status); 257 t0 = float32_add(t0, t1, &env->fp_status); 258 update_fpscr(env, GETPC()); 259 return t0; 260 } 261 262 float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1) 263 { 264 set_float_exception_flags(0, &env->fp_status); 265 t0 = float64_add(t0, t1, &env->fp_status); 266 update_fpscr(env, GETPC()); 267 return t0; 268 } 269 270 uint32_t helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1) 271 { 272 int relation; 273 274 set_float_exception_flags(0, &env->fp_status); 275 relation = float32_compare(t0, t1, &env->fp_status); 276 update_fpscr(env, GETPC()); 277 return relation == float_relation_equal; 278 } 279 280 uint32_t helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1) 281 { 282 int relation; 283 284 set_float_exception_flags(0, &env->fp_status); 285 relation = float64_compare(t0, t1, &env->fp_status); 286 update_fpscr(env, GETPC()); 287 return relation == float_relation_equal; 288 } 289 290 uint32_t helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1) 291 { 292 int relation; 293 294 set_float_exception_flags(0, &env->fp_status); 295 relation = float32_compare(t0, t1, &env->fp_status); 296 update_fpscr(env, GETPC()); 297 return relation == float_relation_greater; 298 } 299 300 uint32_t helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1) 301 { 302 int relation; 303 304 set_float_exception_flags(0, &env->fp_status); 305 relation = float64_compare(t0, t1, &env->fp_status); 306 update_fpscr(env, GETPC()); 307 return relation == float_relation_greater; 308 } 309 310 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0) 311 { 312 float64 ret; 313 set_float_exception_flags(0, &env->fp_status); 314 ret = float32_to_float64(t0, &env->fp_status); 315 update_fpscr(env, GETPC()); 316 return ret; 317 } 318 319 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0) 320 { 321 float32 ret; 322 set_float_exception_flags(0, &env->fp_status); 323 ret = float64_to_float32(t0, &env->fp_status); 324 update_fpscr(env, GETPC()); 325 return ret; 326 } 327 328 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1) 329 { 330 set_float_exception_flags(0, &env->fp_status); 331 t0 = float32_div(t0, t1, &env->fp_status); 332 update_fpscr(env, GETPC()); 333 return t0; 334 } 335 336 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1) 337 { 338 set_float_exception_flags(0, &env->fp_status); 339 t0 = float64_div(t0, t1, &env->fp_status); 340 update_fpscr(env, GETPC()); 341 return t0; 342 } 343 344 float32 helper_float_FT(CPUSH4State *env, uint32_t t0) 345 { 346 float32 ret; 347 set_float_exception_flags(0, &env->fp_status); 348 ret = int32_to_float32(t0, &env->fp_status); 349 update_fpscr(env, GETPC()); 350 return ret; 351 } 352 353 float64 helper_float_DT(CPUSH4State *env, uint32_t t0) 354 { 355 float64 ret; 356 set_float_exception_flags(0, &env->fp_status); 357 ret = int32_to_float64(t0, &env->fp_status); 358 update_fpscr(env, GETPC()); 359 return ret; 360 } 361 362 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2) 363 { 364 set_float_exception_flags(0, &env->fp_status); 365 t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status); 366 update_fpscr(env, GETPC()); 367 return t0; 368 } 369 370 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1) 371 { 372 set_float_exception_flags(0, &env->fp_status); 373 t0 = float32_mul(t0, t1, &env->fp_status); 374 update_fpscr(env, GETPC()); 375 return t0; 376 } 377 378 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1) 379 { 380 set_float_exception_flags(0, &env->fp_status); 381 t0 = float64_mul(t0, t1, &env->fp_status); 382 update_fpscr(env, GETPC()); 383 return t0; 384 } 385 386 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0) 387 { 388 set_float_exception_flags(0, &env->fp_status); 389 t0 = float32_sqrt(t0, &env->fp_status); 390 update_fpscr(env, GETPC()); 391 return t0; 392 } 393 394 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0) 395 { 396 set_float_exception_flags(0, &env->fp_status); 397 t0 = float64_sqrt(t0, &env->fp_status); 398 update_fpscr(env, GETPC()); 399 return t0; 400 } 401 402 float32 helper_fsrra_FT(CPUSH4State *env, float32 t0) 403 { 404 set_float_exception_flags(0, &env->fp_status); 405 /* "Approximate" 1/sqrt(x) via actual computation. */ 406 t0 = float32_sqrt(t0, &env->fp_status); 407 t0 = float32_div(float32_one, t0, &env->fp_status); 408 /* 409 * Since this is supposed to be an approximation, an imprecision 410 * exception is required. One supposes this also follows the usual 411 * IEEE rule that other exceptions take precedence. 412 */ 413 if (get_float_exception_flags(&env->fp_status) == 0) { 414 set_float_exception_flags(float_flag_inexact, &env->fp_status); 415 } 416 update_fpscr(env, GETPC()); 417 return t0; 418 } 419 420 float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1) 421 { 422 set_float_exception_flags(0, &env->fp_status); 423 t0 = float32_sub(t0, t1, &env->fp_status); 424 update_fpscr(env, GETPC()); 425 return t0; 426 } 427 428 float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1) 429 { 430 set_float_exception_flags(0, &env->fp_status); 431 t0 = float64_sub(t0, t1, &env->fp_status); 432 update_fpscr(env, GETPC()); 433 return t0; 434 } 435 436 uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0) 437 { 438 uint32_t ret; 439 set_float_exception_flags(0, &env->fp_status); 440 ret = float32_to_int32_round_to_zero(t0, &env->fp_status); 441 update_fpscr(env, GETPC()); 442 return ret; 443 } 444 445 uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0) 446 { 447 uint32_t ret; 448 set_float_exception_flags(0, &env->fp_status); 449 ret = float64_to_int32_round_to_zero(t0, &env->fp_status); 450 update_fpscr(env, GETPC()); 451 return ret; 452 } 453 454 void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n) 455 { 456 int bank, i; 457 float32 r, p; 458 459 bank = (env->sr & FPSCR_FR) ? 16 : 0; 460 r = float32_zero; 461 set_float_exception_flags(0, &env->fp_status); 462 463 for (i = 0 ; i < 4 ; i++) { 464 p = float32_mul(env->fregs[bank + m + i], 465 env->fregs[bank + n + i], 466 &env->fp_status); 467 r = float32_add(r, p, &env->fp_status); 468 } 469 update_fpscr(env, GETPC()); 470 471 env->fregs[bank + n + 3] = r; 472 } 473 474 void helper_ftrv(CPUSH4State *env, uint32_t n) 475 { 476 int bank_matrix, bank_vector; 477 int i, j; 478 float32 r[4]; 479 float32 p; 480 481 bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16; 482 bank_vector = (env->sr & FPSCR_FR) ? 16 : 0; 483 set_float_exception_flags(0, &env->fp_status); 484 for (i = 0 ; i < 4 ; i++) { 485 r[i] = float32_zero; 486 for (j = 0 ; j < 4 ; j++) { 487 p = float32_mul(env->fregs[bank_matrix + 4 * j + i], 488 env->fregs[bank_vector + j], 489 &env->fp_status); 490 r[i] = float32_add(r[i], p, &env->fp_status); 491 } 492 } 493 update_fpscr(env, GETPC()); 494 495 for (i = 0 ; i < 4 ; i++) { 496 env->fregs[bank_vector + i] = r[i]; 497 } 498 } 499