| /* |
| * 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. |
| */ |
| |
| #include "arch/mips/isa.hh" |
| |
| #include "arch/mips/mt.hh" |
| #include "arch/mips/mt_constants.hh" |
| #include "arch/mips/pra_constants.hh" |
| #include "arch/mips/regs/float.hh" |
| #include "arch/mips/regs/int.hh" |
| #include "arch/mips/regs/misc.hh" |
| #include "base/bitfield.hh" |
| #include "cpu/base.hh" |
| #include "cpu/reg_class.hh" |
| #include "cpu/thread_context.hh" |
| #include "debug/MatRegs.hh" |
| #include "debug/MipsPRA.hh" |
| #include "params/MipsISA.hh" |
| |
| namespace gem5 |
| { |
| |
| namespace MipsISA |
| { |
| |
| std::string |
| ISA::miscRegNames[misc_reg::NumRegs] = |
| { |
| "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" |
| }; |
| |
| namespace |
| { |
| |
| /* Not applicable to MIPS. */ |
| constexpr RegClass vecRegClass(VecRegClass, VecRegClassName, 1, |
| debug::IntRegs); |
| constexpr RegClass vecElemClass(VecElemClass, VecElemClassName, 2, |
| debug::IntRegs); |
| constexpr RegClass vecPredRegClass(VecPredRegClass, VecPredRegClassName, 1, |
| debug::IntRegs); |
| constexpr RegClass matRegClass(MatRegClass, MatRegClassName, 1, debug::MatRegs); |
| constexpr RegClass ccRegClass(CCRegClass, CCRegClassName, 0, debug::IntRegs); |
| |
| } // anonymous namespace |
| |
| ISA::ISA(const Params &p) : BaseISA(p), numThreads(p.num_threads), |
| numVpes(p.num_vpes) |
| { |
| _regClasses.push_back(&intRegClass); |
| _regClasses.push_back(&floatRegClass); |
| _regClasses.push_back(&vecRegClass); |
| _regClasses.push_back(&vecElemClass); |
| _regClasses.push_back(&vecPredRegClass); |
| _regClasses.push_back(&matRegClass); |
| _regClasses.push_back(&ccRegClass); |
| _regClasses.push_back(&miscRegClass); |
| |
| miscRegFile.resize(misc_reg::NumRegs); |
| bankType.resize(misc_reg::NumRegs); |
| |
| for (int i = 0; i < misc_reg::NumRegs; i++) { |
| miscRegFile[i].resize(1); |
| bankType[i] = perProcessor; |
| } |
| |
| miscRegFile_WriteMask.resize(misc_reg::NumRegs); |
| |
| for (int i = 0; i < misc_reg::NumRegs; i++) { |
| miscRegFile_WriteMask[i].push_back(0); |
| } |
| |
| // Initialize all Per-VPE regs |
| uint32_t per_vpe_regs[] = { misc_reg::VpeControl, |
| misc_reg::VpeConf0, misc_reg::VpeConf1, |
| misc_reg::Yqmask, |
| misc_reg::VpeSchedule, misc_reg::VpeSchefback, |
| misc_reg::VpeOpt, misc_reg::SrsConf0, |
| misc_reg::SrsConf1, misc_reg::SrsConf2, |
| misc_reg::SrsConf3, misc_reg::SrsConf4, |
| misc_reg::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[] = { misc_reg::Status, |
| misc_reg::TcStatus, misc_reg::TcBind, |
| misc_reg::TcRestart, misc_reg::TcHalt, |
| misc_reg::TcContext, misc_reg::TcSchedule, |
| misc_reg::TcSchefback, |
| misc_reg::Debug, misc_reg::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(); |
| } |
| |
| void |
| ISA::clear() |
| { |
| for (int i = 0; i < misc_reg::NumRegs; 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::copyRegsFrom(ThreadContext *src) |
| { |
| // First loop through the integer registers. |
| for (auto &id: intRegClass) |
| tc->setReg(id, src->getReg(id)); |
| |
| // Then loop through the floating point registers. |
| for (auto &id: floatRegClass) |
| tc->setReg(id, src->getReg(id)); |
| |
| // Copy misc. registers |
| for (int i = 0; i < misc_reg::NumRegs; i++) |
| tc->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i)); |
| |
| // Copy over the PC State |
| tc->pcState(src->pcState()); |
| } |
| |
| |
| 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(misc_reg::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(misc_reg::Prid, procId); |
| |
| // Now, create Write Mask for ProcID register |
| RegVal procIDMask = 0; // Read-Only register |
| replaceBits(procIDMask, 32, 0, 0); |
| setRegMask(misc_reg::Prid, procIDMask); |
| |
| // Config |
| ConfigReg cfg = readMiscRegNoEffect(misc_reg::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(misc_reg::Config, cfg); |
| // Now, create Write Mask for Config register |
| RegVal cfg_Mask = 0x7FFF0007; |
| replaceBits(cfg_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Config, cfg_Mask); |
| |
| // Config1 |
| Config1Reg cfg1 = readMiscRegNoEffect(misc_reg::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(misc_reg::Config1, cfg1); |
| // Now, create Write Mask for Config register |
| RegVal cfg1_Mask = 0; // Read Only Register |
| replaceBits(cfg1_Mask, 32,0 , 0); |
| setRegMask(misc_reg::Config1, cfg1_Mask); |
| |
| // Config2 |
| Config2Reg cfg2 = readMiscRegNoEffect(misc_reg::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(misc_reg::Config2, cfg2); |
| // Now, create Write Mask for Config register |
| RegVal cfg2_Mask = 0x7000F000; // Read Only Register |
| replaceBits(cfg2_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Config2, cfg2_Mask); |
| |
| // Config3 |
| Config3Reg cfg3 = readMiscRegNoEffect(misc_reg::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(misc_reg::Config3, cfg3); |
| // Now, create Write Mask for Config register |
| RegVal cfg3_Mask = 0; // Read Only Register |
| replaceBits(cfg3_Mask, 32,0 , 0); |
| setRegMask(misc_reg::Config3, cfg3_Mask); |
| |
| // EBase - CPUNum |
| EBaseReg eBase = readMiscRegNoEffect(misc_reg::Ebase); |
| eBase.cpuNum = cp.CP0_EBase_CPUNum; |
| replaceBits(eBase, 31, 31, 1); |
| setMiscRegNoEffect(misc_reg::Ebase, eBase); |
| // Now, create Write Mask for Config register |
| RegVal EB_Mask = 0x3FFFF000;// Except Exception Base, the |
| // entire register is read only |
| replaceBits(EB_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Ebase, EB_Mask); |
| |
| // SRS Control - HSS (Highest Shadow Set) |
| SRSCtlReg scsCtl = readMiscRegNoEffect(misc_reg::Srsctl); |
| scsCtl.hss = cp.CP0_SrsCtl_HSS; |
| setMiscRegNoEffect(misc_reg::Srsctl, scsCtl); |
| // Now, create Write Mask for the SRS Ctl register |
| RegVal SC_Mask = 0x0000F3C0; |
| replaceBits(SC_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Srsctl, SC_Mask); |
| |
| // IntCtl - IPTI, IPPCI |
| IntCtlReg intCtl = readMiscRegNoEffect(misc_reg::Intctl); |
| intCtl.ipti = cp.CP0_IntCtl_IPTI; |
| intCtl.ippci = cp.CP0_IntCtl_IPPCI; |
| setMiscRegNoEffect(misc_reg::Intctl, intCtl); |
| // Now, create Write Mask for the IntCtl register |
| RegVal IC_Mask = 0x000003E0; |
| replaceBits(IC_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Intctl, IC_Mask); |
| |
| // Watch Hi - M - FIXME (More than 1 Watch register) |
| WatchHiReg watchHi = readMiscRegNoEffect(misc_reg::Watchhi0); |
| watchHi.m = cp.CP0_WatchHi_M; |
| setMiscRegNoEffect(misc_reg::Watchhi0, watchHi); |
| // Now, create Write Mask for the IntCtl register |
| RegVal wh_Mask = 0x7FFF0FFF; |
| replaceBits(wh_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Watchhi0, wh_Mask); |
| |
| // Perf Ctr - M - FIXME (More than 1 PerfCnt Pair) |
| PerfCntCtlReg perfCntCtl = readMiscRegNoEffect(misc_reg::Perfcnt0); |
| perfCntCtl.m = cp.CP0_PerfCtr_M; |
| perfCntCtl.w = cp.CP0_PerfCtr_W; |
| setMiscRegNoEffect(misc_reg::Perfcnt0, perfCntCtl); |
| // Now, create Write Mask for the IntCtl register |
| RegVal pc_Mask = 0x00007FF; |
| replaceBits(pc_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Perfcnt0, pc_Mask); |
| |
| // Random |
| setMiscRegNoEffect(misc_reg::Cp0Random, 63); |
| // Now, create Write Mask for the IntCtl register |
| RegVal random_Mask = 0; |
| replaceBits(random_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Cp0Random, random_Mask); |
| |
| // PageGrain |
| PageGrainReg pageGrain = readMiscRegNoEffect(misc_reg::Pagegrain); |
| pageGrain.esp = cp.CP0_Config3_SP; |
| setMiscRegNoEffect(misc_reg::Pagegrain, pageGrain); |
| // Now, create Write Mask for the IntCtl register |
| RegVal pg_Mask = 0x10000000; |
| replaceBits(pg_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Pagegrain, pg_Mask); |
| |
| // Status |
| StatusReg status = readMiscRegNoEffect(misc_reg::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(misc_reg::Status, status); |
| // Now, create Write Mask for the Status register |
| RegVal stat_Mask = 0xFF78FF17; |
| replaceBits(stat_Mask, 32, 0, 0); |
| setRegMask(misc_reg::Status, stat_Mask); |
| |
| |
| // MVPConf0 |
| MVPConf0Reg mvpConf0 = readMiscRegNoEffect(misc_reg::MvpConf0); |
| mvpConf0.tca = 1; |
| mvpConf0.pvpe = numVpes - 1; |
| mvpConf0.ptc = numThreads - 1; |
| setMiscRegNoEffect(misc_reg::MvpConf0, mvpConf0); |
| |
| // VPEConf0 |
| VPEConf0Reg vpeConf0 = readMiscRegNoEffect(misc_reg::VpeConf0); |
| vpeConf0.mvp = 1; |
| setMiscRegNoEffect(misc_reg::VpeConf0, vpeConf0); |
| |
| // TCBind |
| for (ThreadID tid = 0; tid < numThreads; tid++) { |
| TCBindReg tcBind = readMiscRegNoEffect(misc_reg::TcBind, tid); |
| tcBind.curTC = tid; |
| setMiscRegNoEffect(misc_reg::TcBind, tcBind, tid); |
| } |
| // TCHalt |
| TCHaltReg tcHalt = readMiscRegNoEffect(misc_reg::TcHalt); |
| tcHalt.h = 0; |
| setMiscRegNoEffect(misc_reg::TcHalt, tcHalt); |
| |
| // TCStatus |
| // Set TCStatus Activated to 1 for the initial thread that is running |
| TCStatusReg tcStatus = readMiscRegNoEffect(misc_reg::TcStatus); |
| tcStatus.a = 1; |
| setMiscRegNoEffect(misc_reg::TcStatus, tcStatus); |
| |
| // Set Dynamically Allocatable bit to 1 for all other threads |
| for (ThreadID tid = 1; tid < numThreads; tid++) { |
| tcStatus = readMiscRegNoEffect(misc_reg::TcStatus, tid); |
| tcStatus.da = 1; |
| setMiscRegNoEffect(misc_reg::TcStatus, tcStatus, tid); |
| } |
| |
| |
| RegVal mask = 0x7FFFFFFF; |
| |
| // Now, create Write Mask for the Index register |
| replaceBits(mask, 32, 0, 0); |
| setRegMask(misc_reg::Index, mask); |
| |
| mask = 0x3FFFFFFF; |
| replaceBits(mask, 32, 0, 0); |
| setRegMask(misc_reg::Entrylo0, mask); |
| setRegMask(misc_reg::Entrylo1, mask); |
| |
| mask = 0xFF800000; |
| replaceBits(mask, 32, 0, 0); |
| setRegMask(misc_reg::Context, mask); |
| |
| mask = 0x1FFFF800; |
| replaceBits(mask, 32, 0, 0); |
| setRegMask(misc_reg::Pagemask, mask); |
| |
| mask = 0x0; |
| replaceBits(mask, 32, 0, 0); |
| setRegMask(misc_reg::Badvaddr, mask); |
| setRegMask(misc_reg::Lladdr, mask); |
| |
| mask = 0x08C00300; |
| replaceBits(mask, 32, 0, 0); |
| setRegMask(misc_reg::Cause, mask); |
| |
| } |
| |
| inline unsigned |
| ISA::getVPENum(ThreadID tid) const |
| { |
| TCBindReg tcBind = miscRegFile[misc_reg::TcBind][tid]; |
| return tcBind.curVPE; |
| } |
| |
| RegVal |
| ISA::readMiscRegNoEffect(RegIndex idx, ThreadID tid) const |
| { |
| unsigned reg_sel = (bankType[idx] == perThreadContext) |
| ? tid : getVPENum(tid); |
| DPRINTF(MipsPRA, "Reading CP0 Register:%u Select:%u (%s) (%lx).\n", |
| idx / 8, idx % 8, miscRegNames[idx], miscRegFile[idx][reg_sel]); |
| return miscRegFile[idx][reg_sel]; |
| } |
| |
| //@TODO: MIPS MT's register view automatically connects |
| // Status to TCStatus depending on current thread |
| //template <class TC> |
| RegVal |
| ISA::readMiscReg(RegIndex idx, ThreadID tid) |
| { |
| unsigned reg_sel = (bankType[idx] == perThreadContext) |
| ? tid : getVPENum(tid); |
| DPRINTF(MipsPRA, |
| "Reading CP0 Register:%u Select:%u (%s) with effect (%lx).\n", |
| idx / 8, idx % 8, miscRegNames[idx], miscRegFile[idx][reg_sel]); |
| |
| return miscRegFile[idx][reg_sel]; |
| } |
| |
| void |
| ISA::setMiscRegNoEffect(RegIndex idx, RegVal val, ThreadID tid) |
| { |
| unsigned reg_sel = (bankType[idx] == perThreadContext) |
| ? tid : getVPENum(tid); |
| DPRINTF(MipsPRA, |
| "[tid:%i] Setting (direct set) CP0 Register:%u " |
| "Select:%u (%s) to %#x.\n", |
| tid, idx / 8, idx % 8, miscRegNames[idx], val); |
| |
| miscRegFile[idx][reg_sel] = val; |
| } |
| |
| void |
| ISA::setRegMask(RegIndex idx, RegVal val, ThreadID tid) |
| { |
| unsigned reg_sel = (bankType[idx] == perThreadContext) |
| ? tid : getVPENum(tid); |
| DPRINTF(MipsPRA, |
| "[tid:%i] Setting CP0 Register: %u Select: %u (%s) to %#x\n", |
| tid, idx / 8, idx % 8, miscRegNames[idx], val); |
| miscRegFile_WriteMask[idx][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(RegIndex idx, RegVal val, ThreadID tid) |
| { |
| int reg_sel = (bankType[idx] == perThreadContext) |
| ? tid : getVPENum(tid); |
| |
| DPRINTF(MipsPRA, |
| "[tid:%i] Setting CP0 Register:%u " |
| "Select:%u (%s) to %#x, with effect.\n", |
| tid, idx / 8, idx % 8, miscRegNames[idx], val); |
| |
| RegVal cp0_val = filterCP0Write(idx, reg_sel, val); |
| |
| miscRegFile[idx][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) |
| */ |
| RegVal |
| ISA::filterCP0Write(RegIndex idx, int reg_sel, RegVal val) |
| { |
| RegVal retVal = val; |
| |
| // Mask off read-only regions |
| retVal &= miscRegFile_WriteMask[idx][reg_sel]; |
| RegVal curVal = miscRegFile[idx][reg_sel]; |
| // Mask off current alue with inverse mask (clear writeable bits) |
| curVal &= (~miscRegFile_WriteMask[idx][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[idx][reg_sel], |
| ~miscRegFile_WriteMask[idx][reg_sel], |
| val, miscRegFile[idx][reg_sel], retVal); |
| return retVal; |
| } |
| |
| void |
| ISA::scheduleCP0Update(BaseCPU *cpu, Cycles delay) |
| { |
| if (!cp0Updated) { |
| cp0Updated = true; |
| |
| //schedule UPDATE |
| auto cp0_event = new EventFunctionWrapper( |
| [this, cpu]{ processCP0Event(cpu, UpdateCP0); }, |
| "Coprocessor-0 event", true, Event::CPU_Tick_Pri); |
| cpu->schedule(cp0_event, cpu->clockEdge(delay)); |
| } |
| } |
| |
| void |
| ISA::updateCPU(BaseCPU *cpu) |
| { |
| /////////////////////////////////////////////////////////////////// |
| // |
| // EVALUATE CP0 STATE FOR MIPS MT |
| // |
| /////////////////////////////////////////////////////////////////// |
| MVPConf0Reg mvpConf0 = readMiscRegNoEffect(misc_reg::MvpConf0); |
| ThreadID num_threads = mvpConf0.ptc + 1; |
| |
| for (ThreadID tid = 0; tid < num_threads; tid++) { |
| TCStatusReg tcStatus = readMiscRegNoEffect(misc_reg::TcStatus, tid); |
| TCHaltReg tcHalt = readMiscRegNoEffect(misc_reg::TcHalt, 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; |
| } |
| |
| void |
| ISA::processCP0Event(BaseCPU *cpu, CP0EventType cp0EventType) |
| { |
| switch (cp0EventType) |
| { |
| case UpdateCP0: |
| updateCPU(cpu); |
| break; |
| } |
| } |
| |
| } // namespace MipsISA |
| } // namespace gem5 |