1 /* 2 * Helpers for emulation of CP0-related MIPS instructions. 3 * 4 * Copyright (C) 2004-2005 Jocelyn Mayer 5 * Copyright (C) 2020 Wave Computing, Inc. 6 * Copyright (C) 2020 Aleksandar Markovic <amarkovic@wavecomp.com> 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 20 * 21 */ 22 23 #include "qemu/osdep.h" 24 #include "qemu/log.h" 25 #include "qemu/main-loop.h" 26 #include "cpu.h" 27 #include "internal.h" 28 #include "qemu/host-utils.h" 29 #include "exec/helper-proto.h" 30 #include "exec/exec-all.h" 31 32 33 /* SMP helpers. */ 34 static bool mips_vpe_is_wfi(MIPSCPU *c) 35 { 36 CPUState *cpu = CPU(c); 37 CPUMIPSState *env = &c->env; 38 39 /* 40 * If the VPE is halted but otherwise active, it means it's waiting for 41 * an interrupt.\ 42 */ 43 return cpu->halted && mips_vpe_active(env); 44 } 45 46 static bool mips_vp_is_wfi(MIPSCPU *c) 47 { 48 CPUState *cpu = CPU(c); 49 CPUMIPSState *env = &c->env; 50 51 return cpu->halted && mips_vp_active(env); 52 } 53 54 static inline void mips_vpe_wake(MIPSCPU *c) 55 { 56 /* 57 * Don't set ->halted = 0 directly, let it be done via cpu_has_work 58 * because there might be other conditions that state that c should 59 * be sleeping. 60 */ 61 qemu_mutex_lock_iothread(); 62 cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE); 63 qemu_mutex_unlock_iothread(); 64 } 65 66 static inline void mips_vpe_sleep(MIPSCPU *cpu) 67 { 68 CPUState *cs = CPU(cpu); 69 70 /* 71 * The VPE was shut off, really go to bed. 72 * Reset any old _WAKE requests. 73 */ 74 cs->halted = 1; 75 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); 76 } 77 78 static inline void mips_tc_wake(MIPSCPU *cpu, int tc) 79 { 80 CPUMIPSState *c = &cpu->env; 81 82 /* FIXME: TC reschedule. */ 83 if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) { 84 mips_vpe_wake(cpu); 85 } 86 } 87 88 static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) 89 { 90 CPUMIPSState *c = &cpu->env; 91 92 /* FIXME: TC reschedule. */ 93 if (!mips_vpe_active(c)) { 94 mips_vpe_sleep(cpu); 95 } 96 } 97 98 /** 99 * mips_cpu_map_tc: 100 * @env: CPU from which mapping is performed. 101 * @tc: Should point to an int with the value of the global TC index. 102 * 103 * This function will transform @tc into a local index within the 104 * returned #CPUMIPSState. 105 */ 106 107 /* 108 * FIXME: This code assumes that all VPEs have the same number of TCs, 109 * which depends on runtime setup. Can probably be fixed by 110 * walking the list of CPUMIPSStates. 111 */ 112 static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) 113 { 114 MIPSCPU *cpu; 115 CPUState *cs; 116 CPUState *other_cs; 117 int vpe_idx; 118 int tc_idx = *tc; 119 120 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) { 121 /* Not allowed to address other CPUs. */ 122 *tc = env->current_tc; 123 return env; 124 } 125 126 cs = env_cpu(env); 127 vpe_idx = tc_idx / cs->nr_threads; 128 *tc = tc_idx % cs->nr_threads; 129 other_cs = qemu_get_cpu(vpe_idx); 130 if (other_cs == NULL) { 131 return env; 132 } 133 cpu = MIPS_CPU(other_cs); 134 return &cpu->env; 135 } 136 137 /* 138 * The per VPE CP0_Status register shares some fields with the per TC 139 * CP0_TCStatus registers. These fields are wired to the same registers, 140 * so changes to either of them should be reflected on both registers. 141 * 142 * Also, EntryHi shares the bottom 8 bit ASID with TCStauts. 143 * 144 * These helper call synchronizes the regs for a given cpu. 145 */ 146 147 /* 148 * Called for updates to CP0_Status. Defined in "cpu.h" for gdbstub.c. 149 * static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, 150 * int tc); 151 */ 152 153 /* Called for updates to CP0_TCStatus. */ 154 static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, 155 target_ulong v) 156 { 157 uint32_t status; 158 uint32_t tcu, tmx, tasid, tksu; 159 uint32_t mask = ((1U << CP0St_CU3) 160 | (1 << CP0St_CU2) 161 | (1 << CP0St_CU1) 162 | (1 << CP0St_CU0) 163 | (1 << CP0St_MX) 164 | (3 << CP0St_KSU)); 165 166 tcu = (v >> CP0TCSt_TCU0) & 0xf; 167 tmx = (v >> CP0TCSt_TMX) & 0x1; 168 tasid = v & cpu->CP0_EntryHi_ASID_mask; 169 tksu = (v >> CP0TCSt_TKSU) & 0x3; 170 171 status = tcu << CP0St_CU0; 172 status |= tmx << CP0St_MX; 173 status |= tksu << CP0St_KSU; 174 175 cpu->CP0_Status &= ~mask; 176 cpu->CP0_Status |= status; 177 178 /* Sync the TASID with EntryHi. */ 179 cpu->CP0_EntryHi &= ~cpu->CP0_EntryHi_ASID_mask; 180 cpu->CP0_EntryHi |= tasid; 181 182 compute_hflags(cpu); 183 } 184 185 /* Called for updates to CP0_EntryHi. */ 186 static void sync_c0_entryhi(CPUMIPSState *cpu, int tc) 187 { 188 int32_t *tcst; 189 uint32_t asid, v = cpu->CP0_EntryHi; 190 191 asid = v & cpu->CP0_EntryHi_ASID_mask; 192 193 if (tc == cpu->current_tc) { 194 tcst = &cpu->active_tc.CP0_TCStatus; 195 } else { 196 tcst = &cpu->tcs[tc].CP0_TCStatus; 197 } 198 199 *tcst &= ~cpu->CP0_EntryHi_ASID_mask; 200 *tcst |= asid; 201 } 202 203 /* XXX: do not use a global */ 204 uint32_t cpu_mips_get_random(CPUMIPSState *env) 205 { 206 static uint32_t seed = 1; 207 static uint32_t prev_idx; 208 uint32_t idx; 209 uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired; 210 211 if (nb_rand_tlb == 1) { 212 return env->tlb->nb_tlb - 1; 213 } 214 215 /* Don't return same value twice, so get another value */ 216 do { 217 /* 218 * Use a simple algorithm of Linear Congruential Generator 219 * from ISO/IEC 9899 standard. 220 */ 221 seed = 1103515245 * seed + 12345; 222 idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired; 223 } while (idx == prev_idx); 224 prev_idx = idx; 225 return idx; 226 } 227 228 /* CP0 helpers */ 229 target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env) 230 { 231 return env->mvp->CP0_MVPControl; 232 } 233 234 target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env) 235 { 236 return env->mvp->CP0_MVPConf0; 237 } 238 239 target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env) 240 { 241 return env->mvp->CP0_MVPConf1; 242 } 243 244 target_ulong helper_mfc0_random(CPUMIPSState *env) 245 { 246 return (int32_t)cpu_mips_get_random(env); 247 } 248 249 target_ulong helper_mfc0_tcstatus(CPUMIPSState *env) 250 { 251 return env->active_tc.CP0_TCStatus; 252 } 253 254 target_ulong helper_mftc0_tcstatus(CPUMIPSState *env) 255 { 256 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 257 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 258 259 if (other_tc == other->current_tc) { 260 return other->active_tc.CP0_TCStatus; 261 } else { 262 return other->tcs[other_tc].CP0_TCStatus; 263 } 264 } 265 266 target_ulong helper_mfc0_tcbind(CPUMIPSState *env) 267 { 268 return env->active_tc.CP0_TCBind; 269 } 270 271 target_ulong helper_mftc0_tcbind(CPUMIPSState *env) 272 { 273 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 274 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 275 276 if (other_tc == other->current_tc) { 277 return other->active_tc.CP0_TCBind; 278 } else { 279 return other->tcs[other_tc].CP0_TCBind; 280 } 281 } 282 283 target_ulong helper_mfc0_tcrestart(CPUMIPSState *env) 284 { 285 return env->active_tc.PC; 286 } 287 288 target_ulong helper_mftc0_tcrestart(CPUMIPSState *env) 289 { 290 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 291 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 292 293 if (other_tc == other->current_tc) { 294 return other->active_tc.PC; 295 } else { 296 return other->tcs[other_tc].PC; 297 } 298 } 299 300 target_ulong helper_mfc0_tchalt(CPUMIPSState *env) 301 { 302 return env->active_tc.CP0_TCHalt; 303 } 304 305 target_ulong helper_mftc0_tchalt(CPUMIPSState *env) 306 { 307 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 308 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 309 310 if (other_tc == other->current_tc) { 311 return other->active_tc.CP0_TCHalt; 312 } else { 313 return other->tcs[other_tc].CP0_TCHalt; 314 } 315 } 316 317 target_ulong helper_mfc0_tccontext(CPUMIPSState *env) 318 { 319 return env->active_tc.CP0_TCContext; 320 } 321 322 target_ulong helper_mftc0_tccontext(CPUMIPSState *env) 323 { 324 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 325 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 326 327 if (other_tc == other->current_tc) { 328 return other->active_tc.CP0_TCContext; 329 } else { 330 return other->tcs[other_tc].CP0_TCContext; 331 } 332 } 333 334 target_ulong helper_mfc0_tcschedule(CPUMIPSState *env) 335 { 336 return env->active_tc.CP0_TCSchedule; 337 } 338 339 target_ulong helper_mftc0_tcschedule(CPUMIPSState *env) 340 { 341 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 342 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 343 344 if (other_tc == other->current_tc) { 345 return other->active_tc.CP0_TCSchedule; 346 } else { 347 return other->tcs[other_tc].CP0_TCSchedule; 348 } 349 } 350 351 target_ulong helper_mfc0_tcschefback(CPUMIPSState *env) 352 { 353 return env->active_tc.CP0_TCScheFBack; 354 } 355 356 target_ulong helper_mftc0_tcschefback(CPUMIPSState *env) 357 { 358 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 359 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 360 361 if (other_tc == other->current_tc) { 362 return other->active_tc.CP0_TCScheFBack; 363 } else { 364 return other->tcs[other_tc].CP0_TCScheFBack; 365 } 366 } 367 368 target_ulong helper_mfc0_count(CPUMIPSState *env) 369 { 370 return (int32_t)cpu_mips_get_count(env); 371 } 372 373 target_ulong helper_mfc0_saar(CPUMIPSState *env) 374 { 375 if ((env->CP0_SAARI & 0x3f) < 2) { 376 return (int32_t) env->CP0_SAAR[env->CP0_SAARI & 0x3f]; 377 } 378 return 0; 379 } 380 381 target_ulong helper_mfhc0_saar(CPUMIPSState *env) 382 { 383 if ((env->CP0_SAARI & 0x3f) < 2) { 384 return env->CP0_SAAR[env->CP0_SAARI & 0x3f] >> 32; 385 } 386 return 0; 387 } 388 389 target_ulong helper_mftc0_entryhi(CPUMIPSState *env) 390 { 391 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 392 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 393 394 return other->CP0_EntryHi; 395 } 396 397 target_ulong helper_mftc0_cause(CPUMIPSState *env) 398 { 399 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 400 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 401 402 return other->CP0_Cause; 403 } 404 405 target_ulong helper_mftc0_status(CPUMIPSState *env) 406 { 407 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 408 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 409 410 return other->CP0_Status; 411 } 412 413 target_ulong helper_mfc0_lladdr(CPUMIPSState *env) 414 { 415 return (int32_t)(env->CP0_LLAddr >> env->CP0_LLAddr_shift); 416 } 417 418 target_ulong helper_mfc0_maar(CPUMIPSState *env) 419 { 420 return (int32_t) env->CP0_MAAR[env->CP0_MAARI]; 421 } 422 423 target_ulong helper_mfhc0_maar(CPUMIPSState *env) 424 { 425 return env->CP0_MAAR[env->CP0_MAARI] >> 32; 426 } 427 428 target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel) 429 { 430 return (int32_t)env->CP0_WatchLo[sel]; 431 } 432 433 target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel) 434 { 435 return (int32_t) env->CP0_WatchHi[sel]; 436 } 437 438 target_ulong helper_mfhc0_watchhi(CPUMIPSState *env, uint32_t sel) 439 { 440 return env->CP0_WatchHi[sel] >> 32; 441 } 442 443 target_ulong helper_mfc0_debug(CPUMIPSState *env) 444 { 445 target_ulong t0 = env->CP0_Debug; 446 if (env->hflags & MIPS_HFLAG_DM) { 447 t0 |= 1 << CP0DB_DM; 448 } 449 450 return t0; 451 } 452 453 target_ulong helper_mftc0_debug(CPUMIPSState *env) 454 { 455 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 456 int32_t tcstatus; 457 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 458 459 if (other_tc == other->current_tc) { 460 tcstatus = other->active_tc.CP0_Debug_tcstatus; 461 } else { 462 tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus; 463 } 464 465 /* XXX: Might be wrong, check with EJTAG spec. */ 466 return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | 467 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); 468 } 469 470 #if defined(TARGET_MIPS64) 471 target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env) 472 { 473 return env->active_tc.PC; 474 } 475 476 target_ulong helper_dmfc0_tchalt(CPUMIPSState *env) 477 { 478 return env->active_tc.CP0_TCHalt; 479 } 480 481 target_ulong helper_dmfc0_tccontext(CPUMIPSState *env) 482 { 483 return env->active_tc.CP0_TCContext; 484 } 485 486 target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env) 487 { 488 return env->active_tc.CP0_TCSchedule; 489 } 490 491 target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env) 492 { 493 return env->active_tc.CP0_TCScheFBack; 494 } 495 496 target_ulong helper_dmfc0_lladdr(CPUMIPSState *env) 497 { 498 return env->CP0_LLAddr >> env->CP0_LLAddr_shift; 499 } 500 501 target_ulong helper_dmfc0_maar(CPUMIPSState *env) 502 { 503 return env->CP0_MAAR[env->CP0_MAARI]; 504 } 505 506 target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel) 507 { 508 return env->CP0_WatchLo[sel]; 509 } 510 511 target_ulong helper_dmfc0_watchhi(CPUMIPSState *env, uint32_t sel) 512 { 513 return env->CP0_WatchHi[sel]; 514 } 515 516 target_ulong helper_dmfc0_saar(CPUMIPSState *env) 517 { 518 if ((env->CP0_SAARI & 0x3f) < 2) { 519 return env->CP0_SAAR[env->CP0_SAARI & 0x3f]; 520 } 521 return 0; 522 } 523 #endif /* TARGET_MIPS64 */ 524 525 void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1) 526 { 527 uint32_t index_p = env->CP0_Index & 0x80000000; 528 uint32_t tlb_index = arg1 & 0x7fffffff; 529 if (tlb_index < env->tlb->nb_tlb) { 530 if (env->insn_flags & ISA_MIPS_R6) { 531 index_p |= arg1 & 0x80000000; 532 } 533 env->CP0_Index = index_p | tlb_index; 534 } 535 } 536 537 void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1) 538 { 539 uint32_t mask = 0; 540 uint32_t newval; 541 542 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { 543 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) | 544 (1 << CP0MVPCo_EVP); 545 } 546 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) { 547 mask |= (1 << CP0MVPCo_STLB); 548 } 549 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask); 550 551 /* TODO: Enable/disable shared TLB, enable/disable VPEs. */ 552 553 env->mvp->CP0_MVPControl = newval; 554 } 555 556 void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1) 557 { 558 uint32_t mask; 559 uint32_t newval; 560 561 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | 562 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); 563 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask); 564 565 /* 566 * Yield scheduler intercept not implemented. 567 * Gating storage scheduler intercept not implemented. 568 */ 569 570 /* TODO: Enable/disable TCs. */ 571 572 env->CP0_VPEControl = newval; 573 } 574 575 void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1) 576 { 577 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 578 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 579 uint32_t mask; 580 uint32_t newval; 581 582 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | 583 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); 584 newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask); 585 586 /* TODO: Enable/disable TCs. */ 587 588 other->CP0_VPEControl = newval; 589 } 590 591 target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env) 592 { 593 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 594 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 595 /* FIXME: Mask away return zero on read bits. */ 596 return other->CP0_VPEControl; 597 } 598 599 target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env) 600 { 601 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 602 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 603 604 return other->CP0_VPEConf0; 605 } 606 607 void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1) 608 { 609 uint32_t mask = 0; 610 uint32_t newval; 611 612 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { 613 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) { 614 mask |= (0xff << CP0VPEC0_XTC); 615 } 616 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); 617 } 618 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask); 619 620 /* TODO: TC exclusive handling due to ERL/EXL. */ 621 622 env->CP0_VPEConf0 = newval; 623 } 624 625 void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1) 626 { 627 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 628 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 629 uint32_t mask = 0; 630 uint32_t newval; 631 632 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); 633 newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask); 634 635 /* TODO: TC exclusive handling due to ERL/EXL. */ 636 other->CP0_VPEConf0 = newval; 637 } 638 639 void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1) 640 { 641 uint32_t mask = 0; 642 uint32_t newval; 643 644 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) 645 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) | 646 (0xff << CP0VPEC1_NCP1); 647 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask); 648 649 /* UDI not implemented. */ 650 /* CP2 not implemented. */ 651 652 /* TODO: Handle FPU (CP1) binding. */ 653 654 env->CP0_VPEConf1 = newval; 655 } 656 657 void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1) 658 { 659 /* Yield qualifier inputs not implemented. */ 660 env->CP0_YQMask = 0x00000000; 661 } 662 663 void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1) 664 { 665 env->CP0_VPEOpt = arg1 & 0x0000ffff; 666 } 667 668 #define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF) 669 670 void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1) 671 { 672 /* 1k pages not implemented */ 673 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); 674 env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env)) 675 | (rxi << (CP0EnLo_XI - 30)); 676 } 677 678 #if defined(TARGET_MIPS64) 679 #define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6) 680 681 void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1) 682 { 683 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); 684 env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi; 685 } 686 #endif 687 688 void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1) 689 { 690 uint32_t mask = env->CP0_TCStatus_rw_bitmask; 691 uint32_t newval; 692 693 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask); 694 695 env->active_tc.CP0_TCStatus = newval; 696 sync_c0_tcstatus(env, env->current_tc, newval); 697 } 698 699 void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1) 700 { 701 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 702 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 703 704 if (other_tc == other->current_tc) { 705 other->active_tc.CP0_TCStatus = arg1; 706 } else { 707 other->tcs[other_tc].CP0_TCStatus = arg1; 708 } 709 sync_c0_tcstatus(other, other_tc, arg1); 710 } 711 712 void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1) 713 { 714 uint32_t mask = (1 << CP0TCBd_TBE); 715 uint32_t newval; 716 717 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) { 718 mask |= (1 << CP0TCBd_CurVPE); 719 } 720 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask); 721 env->active_tc.CP0_TCBind = newval; 722 } 723 724 void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1) 725 { 726 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 727 uint32_t mask = (1 << CP0TCBd_TBE); 728 uint32_t newval; 729 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 730 731 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) { 732 mask |= (1 << CP0TCBd_CurVPE); 733 } 734 if (other_tc == other->current_tc) { 735 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask); 736 other->active_tc.CP0_TCBind = newval; 737 } else { 738 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask); 739 other->tcs[other_tc].CP0_TCBind = newval; 740 } 741 } 742 743 void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1) 744 { 745 env->active_tc.PC = arg1; 746 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); 747 env->CP0_LLAddr = 0; 748 env->lladdr = 0; 749 /* MIPS16 not implemented. */ 750 } 751 752 void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1) 753 { 754 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 755 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 756 757 if (other_tc == other->current_tc) { 758 other->active_tc.PC = arg1; 759 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); 760 other->CP0_LLAddr = 0; 761 other->lladdr = 0; 762 /* MIPS16 not implemented. */ 763 } else { 764 other->tcs[other_tc].PC = arg1; 765 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS); 766 other->CP0_LLAddr = 0; 767 other->lladdr = 0; 768 /* MIPS16 not implemented. */ 769 } 770 } 771 772 void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1) 773 { 774 MIPSCPU *cpu = env_archcpu(env); 775 776 env->active_tc.CP0_TCHalt = arg1 & 0x1; 777 778 /* TODO: Halt TC / Restart (if allocated+active) TC. */ 779 if (env->active_tc.CP0_TCHalt & 1) { 780 mips_tc_sleep(cpu, env->current_tc); 781 } else { 782 mips_tc_wake(cpu, env->current_tc); 783 } 784 } 785 786 void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1) 787 { 788 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 789 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 790 MIPSCPU *other_cpu = env_archcpu(other); 791 792 /* TODO: Halt TC / Restart (if allocated+active) TC. */ 793 794 if (other_tc == other->current_tc) { 795 other->active_tc.CP0_TCHalt = arg1; 796 } else { 797 other->tcs[other_tc].CP0_TCHalt = arg1; 798 } 799 800 if (arg1 & 1) { 801 mips_tc_sleep(other_cpu, other_tc); 802 } else { 803 mips_tc_wake(other_cpu, other_tc); 804 } 805 } 806 807 void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1) 808 { 809 env->active_tc.CP0_TCContext = arg1; 810 } 811 812 void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1) 813 { 814 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 815 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 816 817 if (other_tc == other->current_tc) { 818 other->active_tc.CP0_TCContext = arg1; 819 } else { 820 other->tcs[other_tc].CP0_TCContext = arg1; 821 } 822 } 823 824 void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1) 825 { 826 env->active_tc.CP0_TCSchedule = arg1; 827 } 828 829 void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1) 830 { 831 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 832 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 833 834 if (other_tc == other->current_tc) { 835 other->active_tc.CP0_TCSchedule = arg1; 836 } else { 837 other->tcs[other_tc].CP0_TCSchedule = arg1; 838 } 839 } 840 841 void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1) 842 { 843 env->active_tc.CP0_TCScheFBack = arg1; 844 } 845 846 void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1) 847 { 848 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 849 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 850 851 if (other_tc == other->current_tc) { 852 other->active_tc.CP0_TCScheFBack = arg1; 853 } else { 854 other->tcs[other_tc].CP0_TCScheFBack = arg1; 855 } 856 } 857 858 void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1) 859 { 860 /* 1k pages not implemented */ 861 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); 862 env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env)) 863 | (rxi << (CP0EnLo_XI - 30)); 864 } 865 866 #if defined(TARGET_MIPS64) 867 void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1) 868 { 869 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); 870 env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi; 871 } 872 #endif 873 874 void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1) 875 { 876 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF); 877 } 878 879 void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1) 880 { 881 int32_t old; 882 old = env->CP0_MemoryMapID; 883 env->CP0_MemoryMapID = (int32_t) arg1; 884 /* If the MemoryMapID changes, flush qemu's TLB. */ 885 if (old != env->CP0_MemoryMapID) { 886 cpu_mips_tlb_flush(env); 887 } 888 } 889 890 void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask) 891 { 892 uint32_t mask; 893 int maskbits; 894 895 /* Don't care MASKX as we don't support 1KB page */ 896 mask = extract32((uint32_t)arg1, CP0PM_MASK, 16); 897 maskbits = cto32(mask); 898 899 /* Ensure no more set bit after first zero */ 900 if ((mask >> maskbits) != 0) { 901 goto invalid; 902 } 903 /* We don't support VTLB entry smaller than target page */ 904 if ((maskbits + TARGET_PAGE_BITS_MIN) < TARGET_PAGE_BITS) { 905 goto invalid; 906 } 907 env->CP0_PageMask = mask << CP0PM_MASK; 908 909 return; 910 911 invalid: 912 /* When invalid, set to default target page size. */ 913 mask = (~TARGET_PAGE_MASK >> TARGET_PAGE_BITS_MIN); 914 env->CP0_PageMask = mask << CP0PM_MASK; 915 } 916 917 void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) 918 { 919 update_pagemask(env, arg1, &env->CP0_PageMask); 920 } 921 922 void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) 923 { 924 /* SmartMIPS not implemented */ 925 /* 1k pages not implemented */ 926 env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) | 927 (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask); 928 compute_hflags(env); 929 restore_pamask(env); 930 } 931 932 void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1) 933 { 934 CPUState *cs = env_cpu(env); 935 936 env->CP0_SegCtl0 = arg1 & CP0SC0_MASK; 937 tlb_flush(cs); 938 } 939 940 void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1) 941 { 942 CPUState *cs = env_cpu(env); 943 944 env->CP0_SegCtl1 = arg1 & CP0SC1_MASK; 945 tlb_flush(cs); 946 } 947 948 void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1) 949 { 950 CPUState *cs = env_cpu(env); 951 952 env->CP0_SegCtl2 = arg1 & CP0SC2_MASK; 953 tlb_flush(cs); 954 } 955 956 void helper_mtc0_pwfield(CPUMIPSState *env, target_ulong arg1) 957 { 958 #if defined(TARGET_MIPS64) 959 uint64_t mask = 0x3F3FFFFFFFULL; 960 uint32_t old_ptei = (env->CP0_PWField >> CP0PF_PTEI) & 0x3FULL; 961 uint32_t new_ptei = (arg1 >> CP0PF_PTEI) & 0x3FULL; 962 963 if ((env->insn_flags & ISA_MIPS_R6)) { 964 if (((arg1 >> CP0PF_BDI) & 0x3FULL) < 12) { 965 mask &= ~(0x3FULL << CP0PF_BDI); 966 } 967 if (((arg1 >> CP0PF_GDI) & 0x3FULL) < 12) { 968 mask &= ~(0x3FULL << CP0PF_GDI); 969 } 970 if (((arg1 >> CP0PF_UDI) & 0x3FULL) < 12) { 971 mask &= ~(0x3FULL << CP0PF_UDI); 972 } 973 if (((arg1 >> CP0PF_MDI) & 0x3FULL) < 12) { 974 mask &= ~(0x3FULL << CP0PF_MDI); 975 } 976 if (((arg1 >> CP0PF_PTI) & 0x3FULL) < 12) { 977 mask &= ~(0x3FULL << CP0PF_PTI); 978 } 979 } 980 env->CP0_PWField = arg1 & mask; 981 982 if ((new_ptei >= 32) || 983 ((env->insn_flags & ISA_MIPS_R6) && 984 (new_ptei == 0 || new_ptei == 1))) { 985 env->CP0_PWField = (env->CP0_PWField & ~0x3FULL) | 986 (old_ptei << CP0PF_PTEI); 987 } 988 #else 989 uint32_t mask = 0x3FFFFFFF; 990 uint32_t old_ptew = (env->CP0_PWField >> CP0PF_PTEW) & 0x3F; 991 uint32_t new_ptew = (arg1 >> CP0PF_PTEW) & 0x3F; 992 993 if ((env->insn_flags & ISA_MIPS_R6)) { 994 if (((arg1 >> CP0PF_GDW) & 0x3F) < 12) { 995 mask &= ~(0x3F << CP0PF_GDW); 996 } 997 if (((arg1 >> CP0PF_UDW) & 0x3F) < 12) { 998 mask &= ~(0x3F << CP0PF_UDW); 999 } 1000 if (((arg1 >> CP0PF_MDW) & 0x3F) < 12) { 1001 mask &= ~(0x3F << CP0PF_MDW); 1002 } 1003 if (((arg1 >> CP0PF_PTW) & 0x3F) < 12) { 1004 mask &= ~(0x3F << CP0PF_PTW); 1005 } 1006 } 1007 env->CP0_PWField = arg1 & mask; 1008 1009 if ((new_ptew >= 32) || 1010 ((env->insn_flags & ISA_MIPS_R6) && 1011 (new_ptew == 0 || new_ptew == 1))) { 1012 env->CP0_PWField = (env->CP0_PWField & ~0x3F) | 1013 (old_ptew << CP0PF_PTEW); 1014 } 1015 #endif 1016 } 1017 1018 void helper_mtc0_pwsize(CPUMIPSState *env, target_ulong arg1) 1019 { 1020 #if defined(TARGET_MIPS64) 1021 env->CP0_PWSize = arg1 & 0x3F7FFFFFFFULL; 1022 #else 1023 env->CP0_PWSize = arg1 & 0x3FFFFFFF; 1024 #endif 1025 } 1026 1027 void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) 1028 { 1029 if (env->insn_flags & ISA_MIPS_R6) { 1030 if (arg1 < env->tlb->nb_tlb) { 1031 env->CP0_Wired = arg1; 1032 } 1033 } else { 1034 env->CP0_Wired = arg1 % env->tlb->nb_tlb; 1035 } 1036 } 1037 1038 void helper_mtc0_pwctl(CPUMIPSState *env, target_ulong arg1) 1039 { 1040 #if defined(TARGET_MIPS64) 1041 /* PWEn = 0. Hardware page table walking is not implemented. */ 1042 env->CP0_PWCtl = (env->CP0_PWCtl & 0x000000C0) | (arg1 & 0x5C00003F); 1043 #else 1044 env->CP0_PWCtl = (arg1 & 0x800000FF); 1045 #endif 1046 } 1047 1048 void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1) 1049 { 1050 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask; 1051 } 1052 1053 void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1) 1054 { 1055 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask; 1056 } 1057 1058 void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1) 1059 { 1060 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask; 1061 } 1062 1063 void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1) 1064 { 1065 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask; 1066 } 1067 1068 void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1) 1069 { 1070 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask; 1071 } 1072 1073 void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1) 1074 { 1075 uint32_t mask = 0x0000000F; 1076 1077 if ((env->CP0_Config1 & (1 << CP0C1_PC)) && 1078 (env->insn_flags & ISA_MIPS_R6)) { 1079 mask |= (1 << 4); 1080 } 1081 if (env->insn_flags & ISA_MIPS_R6) { 1082 mask |= (1 << 5); 1083 } 1084 if (env->CP0_Config3 & (1 << CP0C3_ULRI)) { 1085 mask |= (1 << 29); 1086 1087 if (arg1 & (1 << 29)) { 1088 env->hflags |= MIPS_HFLAG_HWRENA_ULR; 1089 } else { 1090 env->hflags &= ~MIPS_HFLAG_HWRENA_ULR; 1091 } 1092 } 1093 1094 env->CP0_HWREna = arg1 & mask; 1095 } 1096 1097 void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1) 1098 { 1099 cpu_mips_store_count(env, arg1); 1100 } 1101 1102 void helper_mtc0_saari(CPUMIPSState *env, target_ulong arg1) 1103 { 1104 uint32_t target = arg1 & 0x3f; 1105 if (target <= 1) { 1106 env->CP0_SAARI = target; 1107 } 1108 } 1109 1110 void helper_mtc0_saar(CPUMIPSState *env, target_ulong arg1) 1111 { 1112 uint32_t target = env->CP0_SAARI & 0x3f; 1113 if (target < 2) { 1114 env->CP0_SAAR[target] = arg1 & 0x00000ffffffff03fULL; 1115 switch (target) { 1116 case 0: 1117 if (env->itu) { 1118 itc_reconfigure(env->itu); 1119 } 1120 break; 1121 } 1122 } 1123 } 1124 1125 void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1) 1126 { 1127 uint32_t target = env->CP0_SAARI & 0x3f; 1128 if (target < 2) { 1129 env->CP0_SAAR[target] = 1130 (((uint64_t) arg1 << 32) & 0x00000fff00000000ULL) | 1131 (env->CP0_SAAR[target] & 0x00000000ffffffffULL); 1132 switch (target) { 1133 case 0: 1134 if (env->itu) { 1135 itc_reconfigure(env->itu); 1136 } 1137 break; 1138 } 1139 } 1140 } 1141 1142 void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) 1143 { 1144 target_ulong old, val, mask; 1145 mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask; 1146 if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) { 1147 mask |= 1 << CP0EnHi_EHINV; 1148 } 1149 1150 /* 1k pages not implemented */ 1151 #if defined(TARGET_MIPS64) 1152 if (env->insn_flags & ISA_MIPS_R6) { 1153 int entryhi_r = extract64(arg1, 62, 2); 1154 int config0_at = extract32(env->CP0_Config0, 13, 2); 1155 bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0; 1156 if ((entryhi_r == 2) || 1157 (entryhi_r == 1 && (no_supervisor || config0_at == 1))) { 1158 /* skip EntryHi.R field if new value is reserved */ 1159 mask &= ~(0x3ull << 62); 1160 } 1161 } 1162 mask &= env->SEGMask; 1163 #endif 1164 old = env->CP0_EntryHi; 1165 val = (arg1 & mask) | (old & ~mask); 1166 env->CP0_EntryHi = val; 1167 if (ase_mt_available(env)) { 1168 sync_c0_entryhi(env, env->current_tc); 1169 } 1170 /* If the ASID changes, flush qemu's TLB. */ 1171 if ((old & env->CP0_EntryHi_ASID_mask) != 1172 (val & env->CP0_EntryHi_ASID_mask)) { 1173 tlb_flush(env_cpu(env)); 1174 } 1175 } 1176 1177 void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1) 1178 { 1179 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1180 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1181 1182 other->CP0_EntryHi = arg1; 1183 sync_c0_entryhi(other, other_tc); 1184 } 1185 1186 void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1) 1187 { 1188 cpu_mips_store_compare(env, arg1); 1189 } 1190 1191 void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) 1192 { 1193 uint32_t val, old; 1194 1195 old = env->CP0_Status; 1196 cpu_mips_store_status(env, arg1); 1197 val = env->CP0_Status; 1198 1199 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 1200 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x", 1201 old, old & env->CP0_Cause & CP0Ca_IP_mask, 1202 val, val & env->CP0_Cause & CP0Ca_IP_mask, 1203 env->CP0_Cause); 1204 switch (cpu_mmu_index(env, false)) { 1205 case 3: 1206 qemu_log(", ERL\n"); 1207 break; 1208 case MIPS_HFLAG_UM: 1209 qemu_log(", UM\n"); 1210 break; 1211 case MIPS_HFLAG_SM: 1212 qemu_log(", SM\n"); 1213 break; 1214 case MIPS_HFLAG_KM: 1215 qemu_log("\n"); 1216 break; 1217 default: 1218 cpu_abort(env_cpu(env), "Invalid MMU mode!\n"); 1219 break; 1220 } 1221 } 1222 } 1223 1224 void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1) 1225 { 1226 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1227 uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018; 1228 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1229 1230 other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask); 1231 sync_c0_status(env, other, other_tc); 1232 } 1233 1234 void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1) 1235 { 1236 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0); 1237 } 1238 1239 void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1) 1240 { 1241 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); 1242 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask); 1243 } 1244 1245 void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1) 1246 { 1247 cpu_mips_store_cause(env, arg1); 1248 } 1249 1250 void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1) 1251 { 1252 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1253 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1254 1255 cpu_mips_store_cause(other, arg1); 1256 } 1257 1258 target_ulong helper_mftc0_epc(CPUMIPSState *env) 1259 { 1260 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1261 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1262 1263 return other->CP0_EPC; 1264 } 1265 1266 target_ulong helper_mftc0_ebase(CPUMIPSState *env) 1267 { 1268 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1269 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1270 1271 return other->CP0_EBase; 1272 } 1273 1274 void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1) 1275 { 1276 target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask; 1277 if (arg1 & env->CP0_EBaseWG_rw_bitmask) { 1278 mask |= ~0x3FFFFFFF; 1279 } 1280 env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask); 1281 } 1282 1283 void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1) 1284 { 1285 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1286 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1287 target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask; 1288 if (arg1 & env->CP0_EBaseWG_rw_bitmask) { 1289 mask |= ~0x3FFFFFFF; 1290 } 1291 other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask); 1292 } 1293 1294 target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx) 1295 { 1296 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1297 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1298 1299 switch (idx) { 1300 case 0: return other->CP0_Config0; 1301 case 1: return other->CP0_Config1; 1302 case 2: return other->CP0_Config2; 1303 case 3: return other->CP0_Config3; 1304 /* 4 and 5 are reserved. */ 1305 case 6: return other->CP0_Config6; 1306 case 7: return other->CP0_Config7; 1307 default: 1308 break; 1309 } 1310 return 0; 1311 } 1312 1313 void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1) 1314 { 1315 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007); 1316 } 1317 1318 void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1) 1319 { 1320 /* tertiary/secondary caches not implemented */ 1321 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); 1322 } 1323 1324 void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1) 1325 { 1326 if (env->insn_flags & ASE_MICROMIPS) { 1327 env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) | 1328 (arg1 & (1 << CP0C3_ISA_ON_EXC)); 1329 } 1330 } 1331 1332 void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1) 1333 { 1334 env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) | 1335 (arg1 & env->CP0_Config4_rw_bitmask); 1336 } 1337 1338 void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1) 1339 { 1340 env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) | 1341 (arg1 & env->CP0_Config5_rw_bitmask); 1342 env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ? 1343 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff; 1344 compute_hflags(env); 1345 } 1346 1347 void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1) 1348 { 1349 target_long mask = env->CP0_LLAddr_rw_bitmask; 1350 arg1 = arg1 << env->CP0_LLAddr_shift; 1351 env->CP0_LLAddr = (env->CP0_LLAddr & ~mask) | (arg1 & mask); 1352 } 1353 1354 #define MTC0_MAAR_MASK(env) \ 1355 ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3) 1356 1357 void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1) 1358 { 1359 env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env); 1360 } 1361 1362 void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1) 1363 { 1364 env->CP0_MAAR[env->CP0_MAARI] = 1365 (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) | 1366 (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL); 1367 } 1368 1369 void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1) 1370 { 1371 int index = arg1 & 0x3f; 1372 if (index == 0x3f) { 1373 /* 1374 * Software may write all ones to INDEX to determine the 1375 * maximum value supported. 1376 */ 1377 env->CP0_MAARI = MIPS_MAAR_MAX - 1; 1378 } else if (index < MIPS_MAAR_MAX) { 1379 env->CP0_MAARI = index; 1380 } 1381 /* 1382 * Other than the all ones, if the value written is not supported, 1383 * then INDEX is unchanged from its previous value. 1384 */ 1385 } 1386 1387 void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel) 1388 { 1389 /* 1390 * Watch exceptions for instructions, data loads, data stores 1391 * not implemented. 1392 */ 1393 env->CP0_WatchLo[sel] = (arg1 & ~0x7); 1394 } 1395 1396 void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel) 1397 { 1398 uint64_t mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID); 1399 if ((env->CP0_Config5 >> CP0C5_MI) & 1) { 1400 mask |= 0xFFFFFFFF00000000ULL; /* MMID */ 1401 } 1402 env->CP0_WatchHi[sel] = arg1 & mask; 1403 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7); 1404 } 1405 1406 void helper_mthc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel) 1407 { 1408 env->CP0_WatchHi[sel] = ((uint64_t) (arg1) << 32) | 1409 (env->CP0_WatchHi[sel] & 0x00000000ffffffffULL); 1410 } 1411 1412 void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1) 1413 { 1414 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; 1415 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask); 1416 } 1417 1418 void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1) 1419 { 1420 env->CP0_Framemask = arg1; /* XXX */ 1421 } 1422 1423 void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1) 1424 { 1425 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120); 1426 if (arg1 & (1 << CP0DB_DM)) { 1427 env->hflags |= MIPS_HFLAG_DM; 1428 } else { 1429 env->hflags &= ~MIPS_HFLAG_DM; 1430 } 1431 } 1432 1433 void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1) 1434 { 1435 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1436 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); 1437 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1438 1439 /* XXX: Might be wrong, check with EJTAG spec. */ 1440 if (other_tc == other->current_tc) { 1441 other->active_tc.CP0_Debug_tcstatus = val; 1442 } else { 1443 other->tcs[other_tc].CP0_Debug_tcstatus = val; 1444 } 1445 other->CP0_Debug = (other->CP0_Debug & 1446 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | 1447 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); 1448 } 1449 1450 void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1) 1451 { 1452 env->CP0_Performance0 = arg1 & 0x000007ff; 1453 } 1454 1455 void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1) 1456 { 1457 int32_t wst = arg1 & (1 << CP0EC_WST); 1458 int32_t spr = arg1 & (1 << CP0EC_SPR); 1459 int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0; 1460 1461 env->CP0_ErrCtl = wst | spr | itc; 1462 1463 if (itc && !wst && !spr) { 1464 env->hflags |= MIPS_HFLAG_ITC_CACHE; 1465 } else { 1466 env->hflags &= ~MIPS_HFLAG_ITC_CACHE; 1467 } 1468 } 1469 1470 void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1) 1471 { 1472 if (env->hflags & MIPS_HFLAG_ITC_CACHE) { 1473 /* 1474 * If CACHE instruction is configured for ITC tags then make all 1475 * CP0.TagLo bits writable. The actual write to ITC Configuration 1476 * Tag will take care of the read-only bits. 1477 */ 1478 env->CP0_TagLo = arg1; 1479 } else { 1480 env->CP0_TagLo = arg1 & 0xFFFFFCF6; 1481 } 1482 } 1483 1484 void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1) 1485 { 1486 env->CP0_DataLo = arg1; /* XXX */ 1487 } 1488 1489 void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1) 1490 { 1491 env->CP0_TagHi = arg1; /* XXX */ 1492 } 1493 1494 void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1) 1495 { 1496 env->CP0_DataHi = arg1; /* XXX */ 1497 } 1498 1499 /* MIPS MT functions */ 1500 target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel) 1501 { 1502 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1503 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1504 1505 if (other_tc == other->current_tc) { 1506 return other->active_tc.gpr[sel]; 1507 } else { 1508 return other->tcs[other_tc].gpr[sel]; 1509 } 1510 } 1511 1512 target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel) 1513 { 1514 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1515 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1516 1517 if (other_tc == other->current_tc) { 1518 return other->active_tc.LO[sel]; 1519 } else { 1520 return other->tcs[other_tc].LO[sel]; 1521 } 1522 } 1523 1524 target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel) 1525 { 1526 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1527 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1528 1529 if (other_tc == other->current_tc) { 1530 return other->active_tc.HI[sel]; 1531 } else { 1532 return other->tcs[other_tc].HI[sel]; 1533 } 1534 } 1535 1536 target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel) 1537 { 1538 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1539 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1540 1541 if (other_tc == other->current_tc) { 1542 return other->active_tc.ACX[sel]; 1543 } else { 1544 return other->tcs[other_tc].ACX[sel]; 1545 } 1546 } 1547 1548 target_ulong helper_mftdsp(CPUMIPSState *env) 1549 { 1550 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1551 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1552 1553 if (other_tc == other->current_tc) { 1554 return other->active_tc.DSPControl; 1555 } else { 1556 return other->tcs[other_tc].DSPControl; 1557 } 1558 } 1559 1560 void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel) 1561 { 1562 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1563 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1564 1565 if (other_tc == other->current_tc) { 1566 other->active_tc.gpr[sel] = arg1; 1567 } else { 1568 other->tcs[other_tc].gpr[sel] = arg1; 1569 } 1570 } 1571 1572 void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel) 1573 { 1574 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1575 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1576 1577 if (other_tc == other->current_tc) { 1578 other->active_tc.LO[sel] = arg1; 1579 } else { 1580 other->tcs[other_tc].LO[sel] = arg1; 1581 } 1582 } 1583 1584 void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel) 1585 { 1586 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1587 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1588 1589 if (other_tc == other->current_tc) { 1590 other->active_tc.HI[sel] = arg1; 1591 } else { 1592 other->tcs[other_tc].HI[sel] = arg1; 1593 } 1594 } 1595 1596 void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel) 1597 { 1598 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1599 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1600 1601 if (other_tc == other->current_tc) { 1602 other->active_tc.ACX[sel] = arg1; 1603 } else { 1604 other->tcs[other_tc].ACX[sel] = arg1; 1605 } 1606 } 1607 1608 void helper_mttdsp(CPUMIPSState *env, target_ulong arg1) 1609 { 1610 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); 1611 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); 1612 1613 if (other_tc == other->current_tc) { 1614 other->active_tc.DSPControl = arg1; 1615 } else { 1616 other->tcs[other_tc].DSPControl = arg1; 1617 } 1618 } 1619 1620 /* MIPS MT functions */ 1621 target_ulong helper_dmt(void) 1622 { 1623 /* TODO */ 1624 return 0; 1625 } 1626 1627 target_ulong helper_emt(void) 1628 { 1629 /* TODO */ 1630 return 0; 1631 } 1632 1633 target_ulong helper_dvpe(CPUMIPSState *env) 1634 { 1635 CPUState *other_cs = first_cpu; 1636 target_ulong prev = env->mvp->CP0_MVPControl; 1637 1638 CPU_FOREACH(other_cs) { 1639 MIPSCPU *other_cpu = MIPS_CPU(other_cs); 1640 /* Turn off all VPEs except the one executing the dvpe. */ 1641 if (&other_cpu->env != env) { 1642 other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); 1643 mips_vpe_sleep(other_cpu); 1644 } 1645 } 1646 return prev; 1647 } 1648 1649 target_ulong helper_evpe(CPUMIPSState *env) 1650 { 1651 CPUState *other_cs = first_cpu; 1652 target_ulong prev = env->mvp->CP0_MVPControl; 1653 1654 CPU_FOREACH(other_cs) { 1655 MIPSCPU *other_cpu = MIPS_CPU(other_cs); 1656 1657 if (&other_cpu->env != env 1658 /* If the VPE is WFI, don't disturb its sleep. */ 1659 && !mips_vpe_is_wfi(other_cpu)) { 1660 /* Enable the VPE. */ 1661 other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); 1662 mips_vpe_wake(other_cpu); /* And wake it up. */ 1663 } 1664 } 1665 return prev; 1666 } 1667 1668 /* R6 Multi-threading */ 1669 target_ulong helper_dvp(CPUMIPSState *env) 1670 { 1671 CPUState *other_cs = first_cpu; 1672 target_ulong prev = env->CP0_VPControl; 1673 1674 if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) { 1675 CPU_FOREACH(other_cs) { 1676 MIPSCPU *other_cpu = MIPS_CPU(other_cs); 1677 /* Turn off all VPs except the one executing the dvp. */ 1678 if (&other_cpu->env != env) { 1679 mips_vpe_sleep(other_cpu); 1680 } 1681 } 1682 env->CP0_VPControl |= (1 << CP0VPCtl_DIS); 1683 } 1684 return prev; 1685 } 1686 1687 target_ulong helper_evp(CPUMIPSState *env) 1688 { 1689 CPUState *other_cs = first_cpu; 1690 target_ulong prev = env->CP0_VPControl; 1691 1692 if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) { 1693 CPU_FOREACH(other_cs) { 1694 MIPSCPU *other_cpu = MIPS_CPU(other_cs); 1695 if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) { 1696 /* 1697 * If the VP is WFI, don't disturb its sleep. 1698 * Otherwise, wake it up. 1699 */ 1700 mips_vpe_wake(other_cpu); 1701 } 1702 } 1703 env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS); 1704 } 1705 return prev; 1706 } 1707