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