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 superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 28 MMUAccessType access_type, 29 int mmu_idx, uintptr_t retaddr) 30 { 31 switch (access_type) { 32 case MMU_INST_FETCH: 33 case MMU_DATA_LOAD: 34 cs->exception_index = 0x0e0; 35 break; 36 case MMU_DATA_STORE: 37 cs->exception_index = 0x100; 38 break; 39 } 40 cpu_loop_exit_restore(cs, retaddr); 41 } 42 43 void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, 44 int mmu_idx, uintptr_t retaddr) 45 { 46 int ret; 47 48 ret = superh_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); 49 if (ret) { 50 /* now we have a real cpu fault */ 51 cpu_loop_exit_restore(cs, retaddr); 52 } 53 } 54 55 #endif 56 57 void helper_ldtlb(CPUSH4State *env) 58 { 59 #ifdef CONFIG_USER_ONLY 60 SuperHCPU *cpu = sh_env_get_cpu(env); 61 62 /* XXXXX */ 63 cpu_abort(CPU(cpu), "Unhandled ldtlb"); 64 #else 65 cpu_load_tlb(env); 66 #endif 67 } 68 69 static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index, 70 uintptr_t retaddr) 71 { 72 CPUState *cs = CPU(sh_env_get_cpu(env)); 73 74 cs->exception_index = index; 75 cpu_loop_exit_restore(cs, retaddr); 76 } 77 78 void helper_raise_illegal_instruction(CPUSH4State *env) 79 { 80 raise_exception(env, 0x180, 0); 81 } 82 83 void helper_raise_slot_illegal_instruction(CPUSH4State *env) 84 { 85 raise_exception(env, 0x1a0, 0); 86 } 87 88 void helper_raise_fpu_disable(CPUSH4State *env) 89 { 90 raise_exception(env, 0x800, 0); 91 } 92 93 void helper_raise_slot_fpu_disable(CPUSH4State *env) 94 { 95 raise_exception(env, 0x820, 0); 96 } 97 98 void helper_debug(CPUSH4State *env) 99 { 100 raise_exception(env, EXCP_DEBUG, 0); 101 } 102 103 void helper_sleep(CPUSH4State *env) 104 { 105 CPUState *cs = CPU(sh_env_get_cpu(env)); 106 107 cs->halted = 1; 108 env->in_sleep = 1; 109 raise_exception(env, EXCP_HLT, 0); 110 } 111 112 void helper_trapa(CPUSH4State *env, uint32_t tra) 113 { 114 env->tra = tra << 2; 115 raise_exception(env, 0x160, 0); 116 } 117 118 void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value) 119 { 120 if (cpu_sh4_is_cached (env, address)) 121 { 122 memory_content *r = g_new(memory_content, 1); 123 124 r->address = address; 125 r->value = value; 126 r->next = NULL; 127 128 *(env->movcal_backup_tail) = r; 129 env->movcal_backup_tail = &(r->next); 130 } 131 } 132 133 void helper_discard_movcal_backup(CPUSH4State *env) 134 { 135 memory_content *current = env->movcal_backup; 136 137 while(current) 138 { 139 memory_content *next = current->next; 140 g_free(current); 141 env->movcal_backup = current = next; 142 if (current == NULL) 143 env->movcal_backup_tail = &(env->movcal_backup); 144 } 145 } 146 147 void helper_ocbi(CPUSH4State *env, uint32_t address) 148 { 149 memory_content **current = &(env->movcal_backup); 150 while (*current) 151 { 152 uint32_t a = (*current)->address; 153 if ((a & ~0x1F) == (address & ~0x1F)) 154 { 155 memory_content *next = (*current)->next; 156 cpu_stl_data(env, a, (*current)->value); 157 158 if (next == NULL) 159 { 160 env->movcal_backup_tail = current; 161 } 162 163 g_free(*current); 164 *current = next; 165 break; 166 } 167 } 168 } 169 170 void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1) 171 { 172 int64_t res; 173 174 res = ((uint64_t) env->mach << 32) | env->macl; 175 res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1; 176 env->mach = (res >> 32) & 0xffffffff; 177 env->macl = res & 0xffffffff; 178 if (env->sr & (1u << SR_S)) { 179 if (res < 0) 180 env->mach |= 0xffff0000; 181 else 182 env->mach &= 0x00007fff; 183 } 184 } 185 186 void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1) 187 { 188 int64_t res; 189 190 res = ((uint64_t) env->mach << 32) | env->macl; 191 res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1; 192 env->mach = (res >> 32) & 0xffffffff; 193 env->macl = res & 0xffffffff; 194 if (env->sr & (1u << SR_S)) { 195 if (res < -0x80000000) { 196 env->mach = 1; 197 env->macl = 0x80000000; 198 } else if (res > 0x000000007fffffff) { 199 env->mach = 1; 200 env->macl = 0x7fffffff; 201 } 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 flag entries */ 223 env->fpscr &= ~FPSCR_FLAG_MASK; 224 225 if (unlikely(xcpt)) { 226 if (xcpt & float_flag_invalid) { 227 env->fpscr |= FPSCR_FLAG_V; 228 } 229 if (xcpt & float_flag_divbyzero) { 230 env->fpscr |= FPSCR_FLAG_Z; 231 } 232 if (xcpt & float_flag_overflow) { 233 env->fpscr |= FPSCR_FLAG_O; 234 } 235 if (xcpt & float_flag_underflow) { 236 env->fpscr |= FPSCR_FLAG_U; 237 } 238 if (xcpt & float_flag_inexact) { 239 env->fpscr |= FPSCR_FLAG_I; 240 } 241 242 /* Accumulate in cause entries */ 243 env->fpscr |= (env->fpscr & FPSCR_FLAG_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_fabs_FT(float32 t0) 256 { 257 return float32_abs(t0); 258 } 259 260 float64 helper_fabs_DT(float64 t0) 261 { 262 return float64_abs(t0); 263 } 264 265 float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1) 266 { 267 set_float_exception_flags(0, &env->fp_status); 268 t0 = float32_add(t0, t1, &env->fp_status); 269 update_fpscr(env, GETPC()); 270 return t0; 271 } 272 273 float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1) 274 { 275 set_float_exception_flags(0, &env->fp_status); 276 t0 = float64_add(t0, t1, &env->fp_status); 277 update_fpscr(env, GETPC()); 278 return t0; 279 } 280 281 void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1) 282 { 283 int relation; 284 285 set_float_exception_flags(0, &env->fp_status); 286 relation = float32_compare(t0, t1, &env->fp_status); 287 if (unlikely(relation == float_relation_unordered)) { 288 update_fpscr(env, GETPC()); 289 } else { 290 env->sr_t = (relation == float_relation_equal); 291 } 292 } 293 294 void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1) 295 { 296 int relation; 297 298 set_float_exception_flags(0, &env->fp_status); 299 relation = float64_compare(t0, t1, &env->fp_status); 300 if (unlikely(relation == float_relation_unordered)) { 301 update_fpscr(env, GETPC()); 302 } else { 303 env->sr_t = (relation == float_relation_equal); 304 } 305 } 306 307 void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1) 308 { 309 int relation; 310 311 set_float_exception_flags(0, &env->fp_status); 312 relation = float32_compare(t0, t1, &env->fp_status); 313 if (unlikely(relation == float_relation_unordered)) { 314 update_fpscr(env, GETPC()); 315 } else { 316 env->sr_t = (relation == float_relation_greater); 317 } 318 } 319 320 void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1) 321 { 322 int relation; 323 324 set_float_exception_flags(0, &env->fp_status); 325 relation = float64_compare(t0, t1, &env->fp_status); 326 if (unlikely(relation == float_relation_unordered)) { 327 update_fpscr(env, GETPC()); 328 } else { 329 env->sr_t = (relation == float_relation_greater); 330 } 331 } 332 333 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0) 334 { 335 float64 ret; 336 set_float_exception_flags(0, &env->fp_status); 337 ret = float32_to_float64(t0, &env->fp_status); 338 update_fpscr(env, GETPC()); 339 return ret; 340 } 341 342 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0) 343 { 344 float32 ret; 345 set_float_exception_flags(0, &env->fp_status); 346 ret = float64_to_float32(t0, &env->fp_status); 347 update_fpscr(env, GETPC()); 348 return ret; 349 } 350 351 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1) 352 { 353 set_float_exception_flags(0, &env->fp_status); 354 t0 = float32_div(t0, t1, &env->fp_status); 355 update_fpscr(env, GETPC()); 356 return t0; 357 } 358 359 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1) 360 { 361 set_float_exception_flags(0, &env->fp_status); 362 t0 = float64_div(t0, t1, &env->fp_status); 363 update_fpscr(env, GETPC()); 364 return t0; 365 } 366 367 float32 helper_float_FT(CPUSH4State *env, uint32_t t0) 368 { 369 float32 ret; 370 set_float_exception_flags(0, &env->fp_status); 371 ret = int32_to_float32(t0, &env->fp_status); 372 update_fpscr(env, GETPC()); 373 return ret; 374 } 375 376 float64 helper_float_DT(CPUSH4State *env, uint32_t t0) 377 { 378 float64 ret; 379 set_float_exception_flags(0, &env->fp_status); 380 ret = int32_to_float64(t0, &env->fp_status); 381 update_fpscr(env, GETPC()); 382 return ret; 383 } 384 385 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2) 386 { 387 set_float_exception_flags(0, &env->fp_status); 388 t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status); 389 update_fpscr(env, GETPC()); 390 return t0; 391 } 392 393 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1) 394 { 395 set_float_exception_flags(0, &env->fp_status); 396 t0 = float32_mul(t0, t1, &env->fp_status); 397 update_fpscr(env, GETPC()); 398 return t0; 399 } 400 401 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1) 402 { 403 set_float_exception_flags(0, &env->fp_status); 404 t0 = float64_mul(t0, t1, &env->fp_status); 405 update_fpscr(env, GETPC()); 406 return t0; 407 } 408 409 float32 helper_fneg_T(float32 t0) 410 { 411 return float32_chs(t0); 412 } 413 414 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0) 415 { 416 set_float_exception_flags(0, &env->fp_status); 417 t0 = float32_sqrt(t0, &env->fp_status); 418 update_fpscr(env, GETPC()); 419 return t0; 420 } 421 422 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0) 423 { 424 set_float_exception_flags(0, &env->fp_status); 425 t0 = float64_sqrt(t0, &env->fp_status); 426 update_fpscr(env, GETPC()); 427 return t0; 428 } 429 430 float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1) 431 { 432 set_float_exception_flags(0, &env->fp_status); 433 t0 = float32_sub(t0, t1, &env->fp_status); 434 update_fpscr(env, GETPC()); 435 return t0; 436 } 437 438 float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1) 439 { 440 set_float_exception_flags(0, &env->fp_status); 441 t0 = float64_sub(t0, t1, &env->fp_status); 442 update_fpscr(env, GETPC()); 443 return t0; 444 } 445 446 uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0) 447 { 448 uint32_t ret; 449 set_float_exception_flags(0, &env->fp_status); 450 ret = float32_to_int32_round_to_zero(t0, &env->fp_status); 451 update_fpscr(env, GETPC()); 452 return ret; 453 } 454 455 uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0) 456 { 457 uint32_t ret; 458 set_float_exception_flags(0, &env->fp_status); 459 ret = float64_to_int32_round_to_zero(t0, &env->fp_status); 460 update_fpscr(env, GETPC()); 461 return ret; 462 } 463 464 void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n) 465 { 466 int bank, i; 467 float32 r, p; 468 469 bank = (env->sr & FPSCR_FR) ? 16 : 0; 470 r = float32_zero; 471 set_float_exception_flags(0, &env->fp_status); 472 473 for (i = 0 ; i < 4 ; i++) { 474 p = float32_mul(env->fregs[bank + m + i], 475 env->fregs[bank + n + i], 476 &env->fp_status); 477 r = float32_add(r, p, &env->fp_status); 478 } 479 update_fpscr(env, GETPC()); 480 481 env->fregs[bank + n + 3] = r; 482 } 483 484 void helper_ftrv(CPUSH4State *env, uint32_t n) 485 { 486 int bank_matrix, bank_vector; 487 int i, j; 488 float32 r[4]; 489 float32 p; 490 491 bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16; 492 bank_vector = (env->sr & FPSCR_FR) ? 16 : 0; 493 set_float_exception_flags(0, &env->fp_status); 494 for (i = 0 ; i < 4 ; i++) { 495 r[i] = float32_zero; 496 for (j = 0 ; j < 4 ; j++) { 497 p = float32_mul(env->fregs[bank_matrix + 4 * j + i], 498 env->fregs[bank_vector + j], 499 &env->fp_status); 500 r[i] = float32_add(r[i], p, &env->fp_status); 501 } 502 } 503 update_fpscr(env, GETPC()); 504 505 for (i = 0 ; i < 4 ; i++) { 506 env->fregs[bank_vector + i] = r[i]; 507 } 508 } 509