cc07dcf026
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.
599 lines
20 KiB
C++
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();
|
|
}
|
|
|
|
}
|