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 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 25 #ifndef CONFIG_USER_ONLY 26 27 void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, 28 int mmu_idx, uintptr_t retaddr) 29 { 30 int ret; 31 32 ret = superh_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); 33 if (ret) { 34 /* now we have a real cpu fault */ 35 if (retaddr) { 36 cpu_restore_state(cs, retaddr); 37 } 38 cpu_loop_exit(cs); 39 } 40 } 41 42 #endif 43 44 void helper_ldtlb(CPUSH4State *env) 45 { 46 #ifdef CONFIG_USER_ONLY 47 SuperHCPU *cpu = sh_env_get_cpu(env); 48 49 /* XXXXX */ 50 cpu_abort(CPU(cpu), "Unhandled ldtlb"); 51 #else 52 cpu_load_tlb(env); 53 #endif 54 } 55 56 static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index, 57 uintptr_t retaddr) 58 { 59 CPUState *cs = CPU(sh_env_get_cpu(env)); 60 61 cs->exception_index = index; 62 if (retaddr) { 63 cpu_restore_state(cs, retaddr); 64 } 65 cpu_loop_exit(cs); 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_debug(CPUSH4State *env) 89 { 90 raise_exception(env, EXCP_DEBUG, 0); 91 } 92 93 void helper_sleep(CPUSH4State *env) 94 { 95 CPUState *cs = CPU(sh_env_get_cpu(env)); 96 97 cs->halted = 1; 98 env->in_sleep = 1; 99 raise_exception(env, EXCP_HLT, 0); 100 } 101 102 void helper_trapa(CPUSH4State *env, uint32_t tra) 103 { 104 env->tra = tra << 2; 105 raise_exception(env, 0x160, 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, uint32_t arg0, uint32_t arg1) 161 { 162 int64_t res; 163 164 res = ((uint64_t) env->mach << 32) | env->macl; 165 res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1; 166 env->mach = (res >> 32) & 0xffffffff; 167 env->macl = res & 0xffffffff; 168 if (env->sr & (1u << SR_S)) { 169 if (res < 0) 170 env->mach |= 0xffff0000; 171 else 172 env->mach &= 0x00007fff; 173 } 174 } 175 176 void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1) 177 { 178 int64_t res; 179 180 res = ((uint64_t) env->mach << 32) | env->macl; 181 res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1; 182 env->mach = (res >> 32) & 0xffffffff; 183 env->macl = res & 0xffffffff; 184 if (env->sr & (1u << SR_S)) { 185 if (res < -0x80000000) { 186 env->mach = 1; 187 env->macl = 0x80000000; 188 } else if (res > 0x000000007fffffff) { 189 env->mach = 1; 190 env->macl = 0x7fffffff; 191 } 192 } 193 } 194 195 void helper_ld_fpscr(CPUSH4State *env, uint32_t val) 196 { 197 env->fpscr = val & FPSCR_MASK; 198 if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) { 199 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 200 } else { 201 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 202 } 203 set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status); 204 } 205 206 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr) 207 { 208 int xcpt, cause, enable; 209 210 xcpt = get_float_exception_flags(&env->fp_status); 211 212 /* Clear the flag entries */ 213 env->fpscr &= ~FPSCR_FLAG_MASK; 214 215 if (unlikely(xcpt)) { 216 if (xcpt & float_flag_invalid) { 217 env->fpscr |= FPSCR_FLAG_V; 218 } 219 if (xcpt & float_flag_divbyzero) { 220 env->fpscr |= FPSCR_FLAG_Z; 221 } 222 if (xcpt & float_flag_overflow) { 223 env->fpscr |= FPSCR_FLAG_O; 224 } 225 if (xcpt & float_flag_underflow) { 226 env->fpscr |= FPSCR_FLAG_U; 227 } 228 if (xcpt & float_flag_inexact) { 229 env->fpscr |= FPSCR_FLAG_I; 230 } 231 232 /* Accumulate in cause entries */ 233 env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK) 234 << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT); 235 236 /* Generate an exception if enabled */ 237 cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT; 238 enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT; 239 if (cause & enable) { 240 raise_exception(env, 0x120, retaddr); 241 } 242 } 243 } 244 245 float32 helper_fabs_FT(float32 t0) 246 { 247 return float32_abs(t0); 248 } 249 250 float64 helper_fabs_DT(float64 t0) 251 { 252 return float64_abs(t0); 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 void 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 if (unlikely(relation == float_relation_unordered)) { 278 update_fpscr(env, GETPC()); 279 } else { 280 env->sr_t = (relation == float_relation_equal); 281 } 282 } 283 284 void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1) 285 { 286 int relation; 287 288 set_float_exception_flags(0, &env->fp_status); 289 relation = float64_compare(t0, t1, &env->fp_status); 290 if (unlikely(relation == float_relation_unordered)) { 291 update_fpscr(env, GETPC()); 292 } else { 293 env->sr_t = (relation == float_relation_equal); 294 } 295 } 296 297 void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1) 298 { 299 int relation; 300 301 set_float_exception_flags(0, &env->fp_status); 302 relation = float32_compare(t0, t1, &env->fp_status); 303 if (unlikely(relation == float_relation_unordered)) { 304 update_fpscr(env, GETPC()); 305 } else { 306 env->sr_t = (relation == float_relation_greater); 307 } 308 } 309 310 void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1) 311 { 312 int relation; 313 314 set_float_exception_flags(0, &env->fp_status); 315 relation = float64_compare(t0, t1, &env->fp_status); 316 if (unlikely(relation == float_relation_unordered)) { 317 update_fpscr(env, GETPC()); 318 } else { 319 env->sr_t = (relation == float_relation_greater); 320 } 321 } 322 323 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0) 324 { 325 float64 ret; 326 set_float_exception_flags(0, &env->fp_status); 327 ret = float32_to_float64(t0, &env->fp_status); 328 update_fpscr(env, GETPC()); 329 return ret; 330 } 331 332 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0) 333 { 334 float32 ret; 335 set_float_exception_flags(0, &env->fp_status); 336 ret = float64_to_float32(t0, &env->fp_status); 337 update_fpscr(env, GETPC()); 338 return ret; 339 } 340 341 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1) 342 { 343 set_float_exception_flags(0, &env->fp_status); 344 t0 = float32_div(t0, t1, &env->fp_status); 345 update_fpscr(env, GETPC()); 346 return t0; 347 } 348 349 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1) 350 { 351 set_float_exception_flags(0, &env->fp_status); 352 t0 = float64_div(t0, t1, &env->fp_status); 353 update_fpscr(env, GETPC()); 354 return t0; 355 } 356 357 float32 helper_float_FT(CPUSH4State *env, uint32_t t0) 358 { 359 float32 ret; 360 set_float_exception_flags(0, &env->fp_status); 361 ret = int32_to_float32(t0, &env->fp_status); 362 update_fpscr(env, GETPC()); 363 return ret; 364 } 365 366 float64 helper_float_DT(CPUSH4State *env, uint32_t t0) 367 { 368 float64 ret; 369 set_float_exception_flags(0, &env->fp_status); 370 ret = int32_to_float64(t0, &env->fp_status); 371 update_fpscr(env, GETPC()); 372 return ret; 373 } 374 375 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2) 376 { 377 set_float_exception_flags(0, &env->fp_status); 378 t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status); 379 update_fpscr(env, GETPC()); 380 return t0; 381 } 382 383 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1) 384 { 385 set_float_exception_flags(0, &env->fp_status); 386 t0 = float32_mul(t0, t1, &env->fp_status); 387 update_fpscr(env, GETPC()); 388 return t0; 389 } 390 391 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1) 392 { 393 set_float_exception_flags(0, &env->fp_status); 394 t0 = float64_mul(t0, t1, &env->fp_status); 395 update_fpscr(env, GETPC()); 396 return t0; 397 } 398 399 float32 helper_fneg_T(float32 t0) 400 { 401 return float32_chs(t0); 402 } 403 404 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0) 405 { 406 set_float_exception_flags(0, &env->fp_status); 407 t0 = float32_sqrt(t0, &env->fp_status); 408 update_fpscr(env, GETPC()); 409 return t0; 410 } 411 412 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0) 413 { 414 set_float_exception_flags(0, &env->fp_status); 415 t0 = float64_sqrt(t0, &env->fp_status); 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