cp0_helper.c (47170B)
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. */ 34static 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 46static 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 54static 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 66static 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 78static 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 88static 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 */ 112static 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. */ 154static 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. */ 186static 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 */ 204uint32_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 */ 229target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env) 230{ 231 return env->mvp->CP0_MVPControl; 232} 233 234target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env) 235{ 236 return env->mvp->CP0_MVPConf0; 237} 238 239target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env) 240{ 241 return env->mvp->CP0_MVPConf1; 242} 243 244target_ulong helper_mfc0_random(CPUMIPSState *env) 245{ 246 return (int32_t)cpu_mips_get_random(env); 247} 248 249target_ulong helper_mfc0_tcstatus(CPUMIPSState *env) 250{ 251 return env->active_tc.CP0_TCStatus; 252} 253 254target_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 266target_ulong helper_mfc0_tcbind(CPUMIPSState *env) 267{ 268 return env->active_tc.CP0_TCBind; 269} 270 271target_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 283target_ulong helper_mfc0_tcrestart(CPUMIPSState *env) 284{ 285 return env->active_tc.PC; 286} 287 288target_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 300target_ulong helper_mfc0_tchalt(CPUMIPSState *env) 301{ 302 return env->active_tc.CP0_TCHalt; 303} 304 305target_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 317target_ulong helper_mfc0_tccontext(CPUMIPSState *env) 318{ 319 return env->active_tc.CP0_TCContext; 320} 321 322target_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 334target_ulong helper_mfc0_tcschedule(CPUMIPSState *env) 335{ 336 return env->active_tc.CP0_TCSchedule; 337} 338 339target_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 351target_ulong helper_mfc0_tcschefback(CPUMIPSState *env) 352{ 353 return env->active_tc.CP0_TCScheFBack; 354} 355 356target_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 368target_ulong helper_mfc0_count(CPUMIPSState *env) 369{ 370 return (int32_t)cpu_mips_get_count(env); 371} 372 373target_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 381target_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 389target_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 397target_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 405target_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 413target_ulong helper_mfc0_lladdr(CPUMIPSState *env) 414{ 415 return (int32_t)(env->CP0_LLAddr >> env->CP0_LLAddr_shift); 416} 417 418target_ulong helper_mfc0_maar(CPUMIPSState *env) 419{ 420 return (int32_t) env->CP0_MAAR[env->CP0_MAARI]; 421} 422 423target_ulong helper_mfhc0_maar(CPUMIPSState *env) 424{ 425 return env->CP0_MAAR[env->CP0_MAARI] >> 32; 426} 427 428target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel) 429{ 430 return (int32_t)env->CP0_WatchLo[sel]; 431} 432 433target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel) 434{ 435 return (int32_t) env->CP0_WatchHi[sel]; 436} 437 438target_ulong helper_mfhc0_watchhi(CPUMIPSState *env, uint32_t sel) 439{ 440 return env->CP0_WatchHi[sel] >> 32; 441} 442 443target_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 453target_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) 471target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env) 472{ 473 return env->active_tc.PC; 474} 475 476target_ulong helper_dmfc0_tchalt(CPUMIPSState *env) 477{ 478 return env->active_tc.CP0_TCHalt; 479} 480 481target_ulong helper_dmfc0_tccontext(CPUMIPSState *env) 482{ 483 return env->active_tc.CP0_TCContext; 484} 485 486target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env) 487{ 488 return env->active_tc.CP0_TCSchedule; 489} 490 491target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env) 492{ 493 return env->active_tc.CP0_TCScheFBack; 494} 495 496target_ulong helper_dmfc0_lladdr(CPUMIPSState *env) 497{ 498 return env->CP0_LLAddr >> env->CP0_LLAddr_shift; 499} 500 501target_ulong helper_dmfc0_maar(CPUMIPSState *env) 502{ 503 return env->CP0_MAAR[env->CP0_MAARI]; 504} 505 506target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel) 507{ 508 return env->CP0_WatchLo[sel]; 509} 510 511target_ulong helper_dmfc0_watchhi(CPUMIPSState *env, uint32_t sel) 512{ 513 return env->CP0_WatchHi[sel]; 514} 515 516target_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 525void 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 537void 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 556void 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 575void 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 591target_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 599target_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 607void 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 625void 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 639void 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 657void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1) 658{ 659 /* Yield qualifier inputs not implemented. */ 660 env->CP0_YQMask = 0x00000000; 661} 662 663void 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 670void 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 681void 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 688void 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 699void 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 712void 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 724void 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 743void 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 752void 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 772void 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 786void 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 807void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1) 808{ 809 env->active_tc.CP0_TCContext = arg1; 810} 811 812void 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 824void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1) 825{ 826 env->active_tc.CP0_TCSchedule = arg1; 827} 828 829void 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 841void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1) 842{ 843 env->active_tc.CP0_TCScheFBack = arg1; 844} 845 846void 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 858void 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) 867void 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 874void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1) 875{ 876 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF); 877} 878 879void 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 890void 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 911invalid: 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 917void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) 918{ 919 update_pagemask(env, arg1, &env->CP0_PageMask); 920} 921 922void 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 932void 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 940void 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 948void 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 956void 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 1018void 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 1027void 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 1038void 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 1048void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1) 1049{ 1050 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask; 1051} 1052 1053void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1) 1054{ 1055 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask; 1056} 1057 1058void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1) 1059{ 1060 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask; 1061} 1062 1063void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1) 1064{ 1065 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask; 1066} 1067 1068void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1) 1069{ 1070 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask; 1071} 1072 1073void 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 1097void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1) 1098{ 1099 cpu_mips_store_count(env, arg1); 1100} 1101 1102void 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 1110void 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 1125void 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 1142void 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 1177void 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 1186void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1) 1187{ 1188 cpu_mips_store_compare(env, arg1); 1189} 1190 1191void 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 1224void 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 1234void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1) 1235{ 1236 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0); 1237} 1238 1239void 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 1245void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1) 1246{ 1247 cpu_mips_store_cause(env, arg1); 1248} 1249 1250void 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 1258target_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 1266target_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 1274void 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 1283void 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 1294target_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 1313void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1) 1314{ 1315 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007); 1316} 1317 1318void 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 1324void 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 1332void 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 1338void 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 1347void 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 1357void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1) 1358{ 1359 env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env); 1360} 1361 1362void 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 1369void 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 1387void 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 1396void 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 1406void 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 1412void 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 1418void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1) 1419{ 1420 env->CP0_Framemask = arg1; /* XXX */ 1421} 1422 1423void 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 1433void 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 1450void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1) 1451{ 1452 env->CP0_Performance0 = arg1 & 0x000007ff; 1453} 1454 1455void 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 1470void 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 1484void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1) 1485{ 1486 env->CP0_DataLo = arg1; /* XXX */ 1487} 1488 1489void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1) 1490{ 1491 env->CP0_TagHi = arg1; /* XXX */ 1492} 1493 1494void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1) 1495{ 1496 env->CP0_DataHi = arg1; /* XXX */ 1497} 1498 1499/* MIPS MT functions */ 1500target_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 1512target_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 1524target_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 1536target_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 1548target_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 1560void 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 1572void 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 1584void 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 1596void 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 1608void 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 */ 1621target_ulong helper_dmt(void) 1622{ 1623 /* TODO */ 1624 return 0; 1625} 1626 1627target_ulong helper_emt(void) 1628{ 1629 /* TODO */ 1630 return 0; 1631} 1632 1633target_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 1649target_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 */ 1669target_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 1687target_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}