gem5/src/arch/mips/isa.cc
Gabe Black cc07dcf026 MIPS: Extract CPU pointer from the thread context in scheduleCP0 setMiscReg.
The MIPS ISA object expects to be constructed with a CPU pointer it uses to
look at other thread contexts and allow them to be manipulated with control
registers. Unfortunately, that differs from all the other ISA classes and
would complicate their implementation.

This change makes the event constructor use a CPU pointer pulled out of the
thread context passed to setMiscReg instead.
2009-12-31 15:30:50 -05:00

599 lines
20 KiB
C++

/*
* 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_constants.hh"
#include "arch/mips/mt.hh"
#include "arch/mips/pra_constants.hh"
#include "base/bitfield.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.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()
{
init();
}
void
ISA::init()
{
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);
}
clear(0);
}
void
ISA::clear(unsigned tid_or_vpn)
{
for(int i = 0; i < NumMiscRegs; i++) {
miscRegFile[i][tid_or_vpn] = 0;
miscRegFile_WriteMask[i][tid_or_vpn] = (long unsigned int)(-1);
}
}
void
ISA::expandForMultithreading(ThreadID num_threads, unsigned num_vpes)
{
// 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 (num_vpes > 1) {
miscRegFile[per_vpe_regs[i]].resize(num_vpes);
}
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(num_threads);
bankType[per_tc_regs[i]] = perThreadContext;
}
if (num_vpes > 1) {
for (int i=1; i < num_vpes; i++) {
clear(i);
}
}
}
//@TODO: Use MIPS STYLE CONSTANTS (e.g. TCHALT_H instead of TCH_H)
void
ISA::reset(std::string core_name, ThreadID num_threads,
unsigned num_vpes, BaseCPU *cpu)
{
DPRINTF(MipsPRA, "Resetting CP0 State with %i TCs and %i VPEs\n",
num_threads, num_vpes);
MipsISA::CoreSpecific &cp = cpu->coreParams;
// 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 = num_vpes - 1;
mvpConf0.ptc = num_threads - 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 < num_threads; 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 < num_threads; 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(), 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, int delay)
{
if (!cp0Updated) {
cp0Updated = true;
//schedule UPDATE
CP0Event *cp0_event = new CP0Event(this, cpu, UpdateCP0);
cpu->schedule(cp0_event, curTick + cpu->ticks(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(int delay)
{
cpu->reschedule(this, curTick + cpu->ticks(delay), true);
}
void
ISA::CP0Event::unscheduleEvent()
{
if (scheduled())
squash();
}
}