| /* | |
| * Copyright (c) 2009 The Regents of The University of Michigan | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * Authors: Gabe Black | |
| */ | |
| #include "arch/mips/isa.hh" | |
| #include "arch/mips/mt.hh" | |
| #include "arch/mips/mt_constants.hh" | |
| #include "arch/mips/pra_constants.hh" | |
| #include "base/bitfield.hh" | |
| #include "cpu/base.hh" | |
| #include "cpu/thread_context.hh" | |
| #include "debug/MipsPRA.hh" | |
| #include "params/MipsISA.hh" | |
| namespace MipsISA | |
| { | |
| std::string | |
| ISA::miscRegNames[NumMiscRegs] = | |
| { | |
| "Index", "MVPControl", "MVPConf0", "MVPConf1", "", "", "", "", | |
| "Random", "VPEControl", "VPEConf0", "VPEConf1", | |
| "YQMask", "VPESchedule", "VPEScheFBack", "VPEOpt", | |
| "EntryLo0", "TCStatus", "TCBind", "TCRestart", | |
| "TCHalt", "TCContext", "TCSchedule", "TCScheFBack", | |
| "EntryLo1", "", "", "", "", "", "", "", | |
| "Context", "ContextConfig", "", "", "", "", "", "", | |
| "PageMask", "PageGrain", "", "", "", "", "", "", | |
| "Wired", "SRSConf0", "SRCConf1", "SRSConf2", | |
| "SRSConf3", "SRSConf4", "", "", | |
| "HWREna", "", "", "", "", "", "", "", | |
| "BadVAddr", "", "", "", "", "", "", "", | |
| "Count", "", "", "", "", "", "", "", | |
| "EntryHi", "", "", "", "", "", "", "", | |
| "Compare", "", "", "", "", "", "", "", | |
| "Status", "IntCtl", "SRSCtl", "SRSMap", "", "", "", "", | |
| "Cause", "", "", "", "", "", "", "", | |
| "EPC", "", "", "", "", "", "", "", | |
| "PRId", "EBase", "", "", "", "", "", "", | |
| "Config", "Config1", "Config2", "Config3", "", "", "", "", | |
| "LLAddr", "", "", "", "", "", "", "", | |
| "WatchLo0", "WatchLo1", "WatchLo2", "WatchLo3", | |
| "WatchLo4", "WatchLo5", "WatchLo6", "WatchLo7", | |
| "WatchHi0", "WatchHi1", "WatchHi2", "WatchHi3", | |
| "WatchHi4", "WatchHi5", "WatchHi6", "WatchHi7", | |
| "XCContext64", "", "", "", "", "", "", "", | |
| "", "", "", "", "", "", "", "", | |
| "", "", "", "", "", "", "", "", | |
| "Debug", "TraceControl1", "TraceControl2", "UserTraceData", | |
| "TraceBPC", "", "", "", | |
| "DEPC", "", "", "", "", "", "", "", | |
| "PerfCnt0", "PerfCnt1", "PerfCnt2", "PerfCnt3", | |
| "PerfCnt4", "PerfCnt5", "PerfCnt6", "PerfCnt7", | |
| "ErrCtl", "", "", "", "", "", "", "", | |
| "CacheErr0", "CacheErr1", "CacheErr2", "CacheErr3", "", "", "", "", | |
| "TagLo0", "DataLo1", "TagLo2", "DataLo3", | |
| "TagLo4", "DataLo5", "TagLo6", "DataLo7", | |
| "TagHi0", "DataHi1", "TagHi2", "DataHi3", | |
| "TagHi4", "DataHi5", "TagHi6", "DataHi7", | |
| "ErrorEPC", "", "", "", "", "", "", "", | |
| "DESAVE", "", "", "", "", "", "", "", | |
| "LLFlag" | |
| }; | |
| ISA::ISA(Params *p) | |
| : SimObject(p), numThreads(p->num_threads), numVpes(p->num_vpes) | |
| { | |
| miscRegFile.resize(NumMiscRegs); | |
| bankType.resize(NumMiscRegs); | |
| for (int i=0; i < NumMiscRegs; i++) { | |
| miscRegFile[i].resize(1); | |
| bankType[i] = perProcessor; | |
| } | |
| miscRegFile_WriteMask.resize(NumMiscRegs); | |
| for (int i = 0; i < NumMiscRegs; i++) { | |
| miscRegFile_WriteMask[i].push_back(0); | |
| } | |
| // Initialize all Per-VPE regs | |
| uint32_t per_vpe_regs[] = { MISCREG_VPE_CONTROL, | |
| MISCREG_VPE_CONF0, MISCREG_VPE_CONF1, | |
| MISCREG_YQMASK, | |
| MISCREG_VPE_SCHEDULE, MISCREG_VPE_SCHEFBACK, | |
| MISCREG_VPE_OPT, MISCREG_SRS_CONF0, | |
| MISCREG_SRS_CONF1, MISCREG_SRS_CONF2, | |
| MISCREG_SRS_CONF3, MISCREG_SRS_CONF4, | |
| MISCREG_EBASE | |
| }; | |
| uint32_t num_vpe_regs = sizeof(per_vpe_regs) / 4; | |
| for (int i = 0; i < num_vpe_regs; i++) { | |
| if (numVpes > 1) { | |
| miscRegFile[per_vpe_regs[i]].resize(numVpes); | |
| } | |
| bankType[per_vpe_regs[i]] = perVirtProcessor; | |
| } | |
| // Initialize all Per-TC regs | |
| uint32_t per_tc_regs[] = { MISCREG_STATUS, | |
| MISCREG_TC_STATUS, MISCREG_TC_BIND, | |
| MISCREG_TC_RESTART, MISCREG_TC_HALT, | |
| MISCREG_TC_CONTEXT, MISCREG_TC_SCHEDULE, | |
| MISCREG_TC_SCHEFBACK, | |
| MISCREG_DEBUG, MISCREG_LLADDR | |
| }; | |
| uint32_t num_tc_regs = sizeof(per_tc_regs) / 4; | |
| for (int i = 0; i < num_tc_regs; i++) { | |
| miscRegFile[per_tc_regs[i]].resize(numThreads); | |
| bankType[per_tc_regs[i]] = perThreadContext; | |
| } | |
| clear(); | |
| } | |
| const MipsISAParams * | |
| ISA::params() const | |
| { | |
| return dynamic_cast<const Params *>(_params); | |
| } | |
| void | |
| ISA::clear() | |
| { | |
| for(int i = 0; i < NumMiscRegs; i++) { | |
| for (int j = 0; j < miscRegFile[i].size(); j++) | |
| miscRegFile[i][j] = 0; | |
| for (int k = 0; k < miscRegFile_WriteMask[i].size(); k++) | |
| miscRegFile_WriteMask[i][k] = (long unsigned int)(-1); | |
| } | |
| } | |
| void | |
| ISA::configCP() | |
| { | |
| DPRINTF(MipsPRA, "Resetting CP0 State with %i TCs and %i VPEs\n", | |
| numThreads, numVpes); | |
| CoreSpecific cp; | |
| panic("CP state must be set before the following code is used"); | |
| // Do Default CP0 initialization HERE | |
| // Do Initialization for MT cores here (eventually use | |
| // core_name parameter to toggle this initialization) | |
| // =================================================== | |
| DPRINTF(MipsPRA, "Initializing CP0 State.... "); | |
| PRIdReg procId = readMiscRegNoEffect(MISCREG_PRID); | |
| procId.coOp = cp.CP0_PRId_CompanyOptions; | |
| procId.coId = cp.CP0_PRId_CompanyID; | |
| procId.procId = cp.CP0_PRId_ProcessorID; | |
| procId.rev = cp.CP0_PRId_Revision; | |
| setMiscRegNoEffect(MISCREG_PRID, procId); | |
| // Now, create Write Mask for ProcID register | |
| MiscReg procIDMask = 0; // Read-Only register | |
| replaceBits(procIDMask, 0, 32, 0); | |
| setRegMask(MISCREG_PRID, procIDMask); | |
| // Config | |
| ConfigReg cfg = readMiscRegNoEffect(MISCREG_CONFIG); | |
| cfg.be = cp.CP0_Config_BE; | |
| cfg.at = cp.CP0_Config_AT; | |
| cfg.ar = cp.CP0_Config_AR; | |
| cfg.mt = cp.CP0_Config_MT; | |
| cfg.vi = cp.CP0_Config_VI; | |
| cfg.m = 1; | |
| setMiscRegNoEffect(MISCREG_CONFIG, cfg); | |
| // Now, create Write Mask for Config register | |
| MiscReg cfg_Mask = 0x7FFF0007; | |
| replaceBits(cfg_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_CONFIG, cfg_Mask); | |
| // Config1 | |
| Config1Reg cfg1 = readMiscRegNoEffect(MISCREG_CONFIG1); | |
| cfg1.mmuSize = cp.CP0_Config1_MMU; | |
| cfg1.is = cp.CP0_Config1_IS; | |
| cfg1.il = cp.CP0_Config1_IL; | |
| cfg1.ia = cp.CP0_Config1_IA; | |
| cfg1.ds = cp.CP0_Config1_DS; | |
| cfg1.dl = cp.CP0_Config1_DL; | |
| cfg1.da = cp.CP0_Config1_DA; | |
| cfg1.fp = cp.CP0_Config1_FP; | |
| cfg1.ep = cp.CP0_Config1_EP; | |
| cfg1.wr = cp.CP0_Config1_WR; | |
| cfg1.md = cp.CP0_Config1_MD; | |
| cfg1.c2 = cp.CP0_Config1_C2; | |
| cfg1.pc = cp.CP0_Config1_PC; | |
| cfg1.m = cp.CP0_Config1_M; | |
| setMiscRegNoEffect(MISCREG_CONFIG1, cfg1); | |
| // Now, create Write Mask for Config register | |
| MiscReg cfg1_Mask = 0; // Read Only Register | |
| replaceBits(cfg1_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_CONFIG1, cfg1_Mask); | |
| // Config2 | |
| Config2Reg cfg2 = readMiscRegNoEffect(MISCREG_CONFIG2); | |
| cfg2.tu = cp.CP0_Config2_TU; | |
| cfg2.ts = cp.CP0_Config2_TS; | |
| cfg2.tl = cp.CP0_Config2_TL; | |
| cfg2.ta = cp.CP0_Config2_TA; | |
| cfg2.su = cp.CP0_Config2_SU; | |
| cfg2.ss = cp.CP0_Config2_SS; | |
| cfg2.sl = cp.CP0_Config2_SL; | |
| cfg2.sa = cp.CP0_Config2_SA; | |
| cfg2.m = cp.CP0_Config2_M; | |
| setMiscRegNoEffect(MISCREG_CONFIG2, cfg2); | |
| // Now, create Write Mask for Config register | |
| MiscReg cfg2_Mask = 0x7000F000; // Read Only Register | |
| replaceBits(cfg2_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_CONFIG2, cfg2_Mask); | |
| // Config3 | |
| Config3Reg cfg3 = readMiscRegNoEffect(MISCREG_CONFIG3); | |
| cfg3.dspp = cp.CP0_Config3_DSPP; | |
| cfg3.lpa = cp.CP0_Config3_LPA; | |
| cfg3.veic = cp.CP0_Config3_VEIC; | |
| cfg3.vint = cp.CP0_Config3_VInt; | |
| cfg3.sp = cp.CP0_Config3_SP; | |
| cfg3.mt = cp.CP0_Config3_MT; | |
| cfg3.sm = cp.CP0_Config3_SM; | |
| cfg3.tl = cp.CP0_Config3_TL; | |
| setMiscRegNoEffect(MISCREG_CONFIG3, cfg3); | |
| // Now, create Write Mask for Config register | |
| MiscReg cfg3_Mask = 0; // Read Only Register | |
| replaceBits(cfg3_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_CONFIG3, cfg3_Mask); | |
| // EBase - CPUNum | |
| EBaseReg eBase = readMiscRegNoEffect(MISCREG_EBASE); | |
| eBase.cpuNum = cp.CP0_EBase_CPUNum; | |
| replaceBits(eBase, 31, 31, 1); | |
| setMiscRegNoEffect(MISCREG_EBASE, eBase); | |
| // Now, create Write Mask for Config register | |
| MiscReg EB_Mask = 0x3FFFF000;// Except Exception Base, the | |
| // entire register is read only | |
| replaceBits(EB_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_EBASE, EB_Mask); | |
| // SRS Control - HSS (Highest Shadow Set) | |
| SRSCtlReg scsCtl = readMiscRegNoEffect(MISCREG_SRSCTL); | |
| scsCtl.hss = cp.CP0_SrsCtl_HSS; | |
| setMiscRegNoEffect(MISCREG_SRSCTL, scsCtl); | |
| // Now, create Write Mask for the SRS Ctl register | |
| MiscReg SC_Mask = 0x0000F3C0; | |
| replaceBits(SC_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_SRSCTL, SC_Mask); | |
| // IntCtl - IPTI, IPPCI | |
| IntCtlReg intCtl = readMiscRegNoEffect(MISCREG_INTCTL); | |
| intCtl.ipti = cp.CP0_IntCtl_IPTI; | |
| intCtl.ippci = cp.CP0_IntCtl_IPPCI; | |
| setMiscRegNoEffect(MISCREG_INTCTL, intCtl); | |
| // Now, create Write Mask for the IntCtl register | |
| MiscReg IC_Mask = 0x000003E0; | |
| replaceBits(IC_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_INTCTL, IC_Mask); | |
| // Watch Hi - M - FIXME (More than 1 Watch register) | |
| WatchHiReg watchHi = readMiscRegNoEffect(MISCREG_WATCHHI0); | |
| watchHi.m = cp.CP0_WatchHi_M; | |
| setMiscRegNoEffect(MISCREG_WATCHHI0, watchHi); | |
| // Now, create Write Mask for the IntCtl register | |
| MiscReg wh_Mask = 0x7FFF0FFF; | |
| replaceBits(wh_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_WATCHHI0, wh_Mask); | |
| // Perf Ctr - M - FIXME (More than 1 PerfCnt Pair) | |
| PerfCntCtlReg perfCntCtl = readMiscRegNoEffect(MISCREG_PERFCNT0); | |
| perfCntCtl.m = cp.CP0_PerfCtr_M; | |
| perfCntCtl.w = cp.CP0_PerfCtr_W; | |
| setMiscRegNoEffect(MISCREG_PERFCNT0, perfCntCtl); | |
| // Now, create Write Mask for the IntCtl register | |
| MiscReg pc_Mask = 0x00007FF; | |
| replaceBits(pc_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_PERFCNT0, pc_Mask); | |
| // Random | |
| setMiscRegNoEffect(MISCREG_CP0_RANDOM, 63); | |
| // Now, create Write Mask for the IntCtl register | |
| MiscReg random_Mask = 0; | |
| replaceBits(random_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_CP0_RANDOM, random_Mask); | |
| // PageGrain | |
| PageGrainReg pageGrain = readMiscRegNoEffect(MISCREG_PAGEGRAIN); | |
| pageGrain.esp = cp.CP0_Config3_SP; | |
| setMiscRegNoEffect(MISCREG_PAGEGRAIN, pageGrain); | |
| // Now, create Write Mask for the IntCtl register | |
| MiscReg pg_Mask = 0x10000000; | |
| replaceBits(pg_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_PAGEGRAIN, pg_Mask); | |
| // Status | |
| StatusReg status = readMiscRegNoEffect(MISCREG_STATUS); | |
| // Only CU0 and IE are modified on a reset - everything else needs | |
| // to be controlled on a per CPU model basis | |
| // Enable CP0 on reset | |
| // status.cu0 = 1; | |
| // Enable ERL bit on a reset | |
| status.erl = 1; | |
| // Enable BEV bit on a reset | |
| status.bev = 1; | |
| setMiscRegNoEffect(MISCREG_STATUS, status); | |
| // Now, create Write Mask for the Status register | |
| MiscReg stat_Mask = 0xFF78FF17; | |
| replaceBits(stat_Mask, 0, 32, 0); | |
| setRegMask(MISCREG_STATUS, stat_Mask); | |
| // MVPConf0 | |
| MVPConf0Reg mvpConf0 = readMiscRegNoEffect(MISCREG_MVP_CONF0); | |
| mvpConf0.tca = 1; | |
| mvpConf0.pvpe = numVpes - 1; | |
| mvpConf0.ptc = numThreads - 1; | |
| setMiscRegNoEffect(MISCREG_MVP_CONF0, mvpConf0); | |
| // VPEConf0 | |
| VPEConf0Reg vpeConf0 = readMiscRegNoEffect(MISCREG_VPE_CONF0); | |
| vpeConf0.mvp = 1; | |
| setMiscRegNoEffect(MISCREG_VPE_CONF0, vpeConf0); | |
| // TCBind | |
| for (ThreadID tid = 0; tid < numThreads; tid++) { | |
| TCBindReg tcBind = readMiscRegNoEffect(MISCREG_TC_BIND, tid); | |
| tcBind.curTC = tid; | |
| setMiscRegNoEffect(MISCREG_TC_BIND, tcBind, tid); | |
| } | |
| // TCHalt | |
| TCHaltReg tcHalt = readMiscRegNoEffect(MISCREG_TC_HALT); | |
| tcHalt.h = 0; | |
| setMiscRegNoEffect(MISCREG_TC_HALT, tcHalt); | |
| // TCStatus | |
| // Set TCStatus Activated to 1 for the initial thread that is running | |
| TCStatusReg tcStatus = readMiscRegNoEffect(MISCREG_TC_STATUS); | |
| tcStatus.a = 1; | |
| setMiscRegNoEffect(MISCREG_TC_STATUS, tcStatus); | |
| // Set Dynamically Allocatable bit to 1 for all other threads | |
| for (ThreadID tid = 1; tid < numThreads; tid++) { | |
| tcStatus = readMiscRegNoEffect(MISCREG_TC_STATUS, tid); | |
| tcStatus.da = 1; | |
| setMiscRegNoEffect(MISCREG_TC_STATUS, tcStatus, tid); | |
| } | |
| MiscReg mask = 0x7FFFFFFF; | |
| // Now, create Write Mask for the Index register | |
| replaceBits(mask, 0, 32, 0); | |
| setRegMask(MISCREG_INDEX, mask); | |
| mask = 0x3FFFFFFF; | |
| replaceBits(mask, 0, 32, 0); | |
| setRegMask(MISCREG_ENTRYLO0, mask); | |
| setRegMask(MISCREG_ENTRYLO1, mask); | |
| mask = 0xFF800000; | |
| replaceBits(mask, 0, 32, 0); | |
| setRegMask(MISCREG_CONTEXT, mask); | |
| mask = 0x1FFFF800; | |
| replaceBits(mask, 0, 32, 0); | |
| setRegMask(MISCREG_PAGEMASK, mask); | |
| mask = 0x0; | |
| replaceBits(mask, 0, 32, 0); | |
| setRegMask(MISCREG_BADVADDR, mask); | |
| setRegMask(MISCREG_LLADDR, mask); | |
| mask = 0x08C00300; | |
| replaceBits(mask, 0, 32, 0); | |
| setRegMask(MISCREG_CAUSE, mask); | |
| } | |
| inline unsigned | |
| ISA::getVPENum(ThreadID tid) | |
| { | |
| TCBindReg tcBind = miscRegFile[MISCREG_TC_BIND][tid]; | |
| return tcBind.curVPE; | |
| } | |
| MiscReg | |
| ISA::readMiscRegNoEffect(int misc_reg, ThreadID tid) | |
| { | |
| unsigned reg_sel = (bankType[misc_reg] == perThreadContext) | |
| ? tid : getVPENum(tid); | |
| DPRINTF(MipsPRA, "Reading CP0 Register:%u Select:%u (%s) (%lx).\n", | |
| misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], | |
| miscRegFile[misc_reg][reg_sel]); | |
| return miscRegFile[misc_reg][reg_sel]; | |
| } | |
| //@TODO: MIPS MT's register view automatically connects | |
| // Status to TCStatus depending on current thread | |
| //template <class TC> | |
| MiscReg | |
| ISA::readMiscReg(int misc_reg, ThreadContext *tc, ThreadID tid) | |
| { | |
| unsigned reg_sel = (bankType[misc_reg] == perThreadContext) | |
| ? tid : getVPENum(tid); | |
| DPRINTF(MipsPRA, | |
| "Reading CP0 Register:%u Select:%u (%s) with effect (%lx).\n", | |
| misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], | |
| miscRegFile[misc_reg][reg_sel]); | |
| return miscRegFile[misc_reg][reg_sel]; | |
| } | |
| void | |
| ISA::setMiscRegNoEffect(int misc_reg, const MiscReg &val, ThreadID tid) | |
| { | |
| unsigned reg_sel = (bankType[misc_reg] == perThreadContext) | |
| ? tid : getVPENum(tid); | |
| DPRINTF(MipsPRA, | |
| "[tid:%i]: Setting (direct set) CP0 Register:%u " | |
| "Select:%u (%s) to %#x.\n", | |
| tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val); | |
| miscRegFile[misc_reg][reg_sel] = val; | |
| } | |
| void | |
| ISA::setRegMask(int misc_reg, const MiscReg &val, ThreadID tid) | |
| { | |
| unsigned reg_sel = (bankType[misc_reg] == perThreadContext) | |
| ? tid : getVPENum(tid); | |
| DPRINTF(MipsPRA, | |
| "[tid:%i]: Setting CP0 Register: %u Select: %u (%s) to %#x\n", | |
| tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val); | |
| miscRegFile_WriteMask[misc_reg][reg_sel] = val; | |
| } | |
| // PROGRAMMER'S NOTES: | |
| // (1) Some CP0 Registers have fields that cannot | |
| // be overwritten. Make sure to handle those particular registers | |
| // with care! | |
| void | |
| ISA::setMiscReg(int misc_reg, const MiscReg &val, | |
| ThreadContext *tc, ThreadID tid) | |
| { | |
| int reg_sel = (bankType[misc_reg] == perThreadContext) | |
| ? tid : getVPENum(tid); | |
| DPRINTF(MipsPRA, | |
| "[tid:%i]: Setting CP0 Register:%u " | |
| "Select:%u (%s) to %#x, with effect.\n", | |
| tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val); | |
| MiscReg cp0_val = filterCP0Write(misc_reg, reg_sel, val); | |
| miscRegFile[misc_reg][reg_sel] = cp0_val; | |
| scheduleCP0Update(tc->getCpuPtr(), Cycles(1)); | |
| } | |
| /** | |
| * This method doesn't need to adjust the Control Register Offset | |
| * since it has already been done in the calling method | |
| * (setRegWithEffect) | |
| */ | |
| MiscReg | |
| ISA::filterCP0Write(int misc_reg, int reg_sel, const MiscReg &val) | |
| { | |
| MiscReg retVal = val; | |
| // Mask off read-only regions | |
| retVal &= miscRegFile_WriteMask[misc_reg][reg_sel]; | |
| MiscReg curVal = miscRegFile[misc_reg][reg_sel]; | |
| // Mask off current alue with inverse mask (clear writeable bits) | |
| curVal &= (~miscRegFile_WriteMask[misc_reg][reg_sel]); | |
| retVal |= curVal; // Combine the two | |
| DPRINTF(MipsPRA, | |
| "filterCP0Write: Mask: %lx, Inverse Mask: %lx, write Val: %x, " | |
| "current val: %lx, written val: %x\n", | |
| miscRegFile_WriteMask[misc_reg][reg_sel], | |
| ~miscRegFile_WriteMask[misc_reg][reg_sel], | |
| val, miscRegFile[misc_reg][reg_sel], retVal); | |
| return retVal; | |
| } | |
| void | |
| ISA::scheduleCP0Update(BaseCPU *cpu, Cycles delay) | |
| { | |
| if (!cp0Updated) { | |
| cp0Updated = true; | |
| //schedule UPDATE | |
| CP0Event *cp0_event = new CP0Event(this, cpu, UpdateCP0); | |
| cpu->schedule(cp0_event, cpu->clockEdge(delay)); | |
| } | |
| } | |
| void | |
| ISA::updateCPU(BaseCPU *cpu) | |
| { | |
| /////////////////////////////////////////////////////////////////// | |
| // | |
| // EVALUATE CP0 STATE FOR MIPS MT | |
| // | |
| /////////////////////////////////////////////////////////////////// | |
| MVPConf0Reg mvpConf0 = readMiscRegNoEffect(MISCREG_MVP_CONF0); | |
| ThreadID num_threads = mvpConf0.ptc + 1; | |
| for (ThreadID tid = 0; tid < num_threads; tid++) { | |
| TCStatusReg tcStatus = readMiscRegNoEffect(MISCREG_TC_STATUS, tid); | |
| TCHaltReg tcHalt = readMiscRegNoEffect(MISCREG_TC_HALT, tid); | |
| //@todo: add vpe/mt check here thru mvpcontrol & vpecontrol regs | |
| if (tcHalt.h == 1 || tcStatus.a == 0) { | |
| haltThread(cpu->getContext(tid)); | |
| } else if (tcHalt.h == 0 && tcStatus.a == 1) { | |
| restoreThread(cpu->getContext(tid)); | |
| } | |
| } | |
| num_threads = mvpConf0.ptc + 1; | |
| // Toggle update flag after we finished updating | |
| cp0Updated = false; | |
| } | |
| ISA::CP0Event::CP0Event(CP0 *_cp0, BaseCPU *_cpu, CP0EventType e_type) | |
| : Event(CPU_Tick_Pri), cp0(_cp0), cpu(_cpu), cp0EventType(e_type) | |
| { } | |
| void | |
| ISA::CP0Event::process() | |
| { | |
| switch (cp0EventType) | |
| { | |
| case UpdateCP0: | |
| cp0->updateCPU(cpu); | |
| break; | |
| } | |
| } | |
| const char * | |
| ISA::CP0Event::description() const | |
| { | |
| return "Coprocessor-0 event"; | |
| } | |
| void | |
| ISA::CP0Event::scheduleEvent(Cycles delay) | |
| { | |
| cpu->reschedule(this, cpu->clockEdge(delay), true); | |
| } | |
| void | |
| ISA::CP0Event::unscheduleEvent() | |
| { | |
| if (scheduled()) | |
| squash(); | |
| } | |
| } | |
| MipsISA::ISA * | |
| MipsISAParams::create() | |
| { | |
| return new MipsISA::ISA(this); | |
| } |