a2d246b6b8
This patch takes quite a large step in transitioning from the ad-hoc RefCountingPtr to the c++11 shared_ptr by adopting its use for all Faults. There are no changes in behaviour, and the code modifications are mostly just replacing "new" with "make_shared".
276 lines
8.8 KiB
C++
Executable file
276 lines
8.8 KiB
C++
Executable file
/*
|
|
* Copyright (c) 2007 MIPS Technologies, Inc.
|
|
* 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: Korey Sewell
|
|
*/
|
|
|
|
#ifndef __ARCH_MIPS_MT_HH__
|
|
#define __ARCH_MIPS_MT_HH__
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* ISA-specific helper functions for multithreaded execution.
|
|
*/
|
|
|
|
#include <iostream>
|
|
|
|
#include "arch/mips/faults.hh"
|
|
#include "arch/mips/isa_traits.hh"
|
|
#include "arch/mips/mt_constants.hh"
|
|
#include "arch/mips/pra_constants.hh"
|
|
#include "arch/mips/registers.hh"
|
|
#include "base/bitfield.hh"
|
|
#include "base/misc.hh"
|
|
#include "base/trace.hh"
|
|
|
|
namespace MipsISA
|
|
{
|
|
|
|
template <class TC>
|
|
inline unsigned
|
|
getVirtProcNum(TC *tc)
|
|
{
|
|
TCBindReg tcbind = tc->readMiscRegNoEffect(MISCREG_TC_BIND);
|
|
return tcbind.curVPE;
|
|
}
|
|
|
|
template <class TC>
|
|
inline unsigned
|
|
getTargetThread(TC *tc)
|
|
{
|
|
VPEControlReg vpeCtrl = tc->readMiscRegNoEffect(MISCREG_VPE_CONTROL);
|
|
return vpeCtrl.targTC;
|
|
}
|
|
|
|
template <class TC>
|
|
inline void
|
|
haltThread(TC *tc)
|
|
{
|
|
if (tc->status() == TC::Active) {
|
|
tc->halt();
|
|
|
|
// Save last known PC in TCRestart
|
|
// @TODO: Needs to check if this is a branch and if so,
|
|
// take previous instruction
|
|
PCState pc = tc->pcState();
|
|
tc->setMiscReg(MISCREG_TC_RESTART, pc.npc());
|
|
|
|
warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x",
|
|
curTick(), tc->threadId(), tc->getCpuPtr()->name(),
|
|
pc.pc(), pc.npc());
|
|
}
|
|
}
|
|
|
|
template <class TC>
|
|
inline void
|
|
restoreThread(TC *tc)
|
|
{
|
|
if (tc->status() != TC::Active) {
|
|
// Restore PC from TCRestart
|
|
Addr restartPC = tc->readMiscRegNoEffect(MISCREG_TC_RESTART);
|
|
|
|
// TODO: SET PC WITH AN EVENT INSTEAD OF INSTANTANEOUSLY
|
|
tc->pcState(restartPC);
|
|
tc->activate();
|
|
|
|
warn("%i: Restoring thread %i in %s @ PC %x",
|
|
curTick(), tc->threadId(), tc->getCpuPtr()->name(), restartPC);
|
|
}
|
|
}
|
|
|
|
template <class TC>
|
|
void
|
|
forkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt)
|
|
{
|
|
MVPConf0Reg mvpConf = tc->readMiscRegNoEffect(MISCREG_MVP_CONF0);
|
|
int num_threads = mvpConf.ptc + 1;
|
|
|
|
int success = 0;
|
|
for (ThreadID tid = 0; tid < num_threads && success == 0; tid++) {
|
|
TCBindReg tidTCBind =
|
|
tc->readRegOtherThread(MISCREG_TC_BIND + Misc_Reg_Base, tid);
|
|
TCBindReg tcBind = tc->readMiscRegNoEffect(MISCREG_TC_BIND);
|
|
|
|
if (tidTCBind.curVPE == tcBind.curVPE) {
|
|
|
|
TCStatusReg tidTCStatus =
|
|
tc->readRegOtherThread(MISCREG_TC_STATUS +
|
|
Misc_Reg_Base,tid);
|
|
|
|
TCHaltReg tidTCHalt =
|
|
tc->readRegOtherThread(MISCREG_TC_HALT + Misc_Reg_Base,tid);
|
|
|
|
if (tidTCStatus.da == 1 && tidTCHalt.h == 0 &&
|
|
tidTCStatus.a == 0 && success == 0) {
|
|
|
|
tc->setRegOtherThread(MISCREG_TC_RESTART +
|
|
Misc_Reg_Base, Rs, tid);
|
|
tc->setRegOtherThread(Rd_bits, Rt, tid);
|
|
|
|
StatusReg status = tc->readMiscReg(MISCREG_STATUS);
|
|
TCStatusReg tcStatus = tc->readMiscReg(MISCREG_TC_STATUS);
|
|
|
|
// Set Run-State to Running
|
|
tidTCStatus.rnst = 0;
|
|
// Set Delay-Slot to 0
|
|
tidTCStatus.tds = 0;
|
|
// Set Dirty TC to 1
|
|
tidTCStatus.dt = 1;
|
|
// Set Activated to 1
|
|
tidTCStatus.a = 1;
|
|
// Set status to previous thread's status
|
|
tidTCStatus.tksu = status.ksu;
|
|
// Set ASID to previous thread's state
|
|
tidTCStatus.asid = tcStatus.asid;
|
|
|
|
// Write Status Register
|
|
tc->setRegOtherThread(MISCREG_TC_STATUS + Misc_Reg_Base,
|
|
tidTCStatus, tid);
|
|
|
|
// Mark As Successful Fork
|
|
success = 1;
|
|
}
|
|
} else {
|
|
std::cerr << "Bad VPEs" << std::endl;
|
|
}
|
|
}
|
|
|
|
if (success == 0) {
|
|
VPEControlReg vpeControl =
|
|
tc->readMiscRegNoEffect(MISCREG_VPE_CONTROL);
|
|
vpeControl.excpt = 1;
|
|
tc->setMiscReg(MISCREG_VPE_CONTROL, vpeControl);
|
|
fault = std::make_shared<ThreadFault>();
|
|
}
|
|
}
|
|
|
|
|
|
template <class TC>
|
|
int
|
|
yieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask)
|
|
{
|
|
if (src_reg == 0) {
|
|
MVPConf0Reg mvpConf0 = tc->readMiscRegNoEffect(MISCREG_MVP_CONF0);
|
|
ThreadID num_threads = mvpConf0.ptc + 1;
|
|
|
|
int ok = 0;
|
|
|
|
// Get Current VPE & TC numbers from calling thread
|
|
TCBindReg tcBind = tc->readMiscRegNoEffect(MISCREG_TC_BIND);
|
|
|
|
for (ThreadID tid = 0; tid < num_threads; tid++) {
|
|
TCStatusReg tidTCStatus =
|
|
tc->readRegOtherThread(MISCREG_TC_STATUS + Misc_Reg_Base,
|
|
tid);
|
|
TCHaltReg tidTCHalt =
|
|
tc->readRegOtherThread(MISCREG_TC_HALT + Misc_Reg_Base,
|
|
tid);
|
|
TCBindReg tidTCBind =
|
|
tc->readRegOtherThread(MISCREG_TC_BIND + Misc_Reg_Base,
|
|
tid);
|
|
|
|
if (tidTCBind.curVPE == tcBind.curVPE &&
|
|
tidTCBind.curTC == tcBind.curTC &&
|
|
tidTCStatus.da == 1 &&
|
|
tidTCHalt.h == 0 &&
|
|
tidTCStatus.a == 1) {
|
|
ok = 1;
|
|
}
|
|
}
|
|
|
|
if (ok == 1) {
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
|
|
tcStatus.a = 0;
|
|
tc->setMiscReg(MISCREG_TC_STATUS, tcStatus);
|
|
warn("%i: Deactivating Hardware Thread Context #%i",
|
|
curTick(), tc->threadId());
|
|
}
|
|
} else if (src_reg > 0) {
|
|
if (src_reg && !yield_mask != 0) {
|
|
VPEControlReg vpeControl = tc->readMiscReg(MISCREG_VPE_CONTROL);
|
|
vpeControl.excpt = 2;
|
|
tc->setMiscReg(MISCREG_VPE_CONTROL, vpeControl);
|
|
fault = std::make_shared<ThreadFault>();
|
|
} else {
|
|
}
|
|
} else if (src_reg != -2) {
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
|
|
VPEControlReg vpeControl =
|
|
tc->readMiscRegNoEffect(MISCREG_VPE_CONTROL);
|
|
|
|
if (vpeControl.ysi == 1 && tcStatus.dt == 1 ) {
|
|
vpeControl.excpt = 4;
|
|
fault = std::make_shared<ThreadFault>();
|
|
} else {
|
|
}
|
|
}
|
|
|
|
return src_reg & yield_mask;
|
|
}
|
|
|
|
|
|
// TC will usually be a object derived from ThreadContext
|
|
// (src/cpu/thread_context.hh)
|
|
template <class TC>
|
|
inline void
|
|
updateStatusView(TC *tc)
|
|
{
|
|
// TCStatus' register view must be the same as
|
|
// Status register view for CU, MX, KSU bits
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
|
|
StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
|
|
|
|
status.cu = tcStatus.tcu;
|
|
status.mx = tcStatus.tmx;
|
|
status.ksu = tcStatus.tksu;
|
|
|
|
tc->setMiscRegNoEffect(MISCREG_STATUS, status);
|
|
}
|
|
|
|
// TC will usually be a object derived from ThreadContext
|
|
// (src/cpu/thread_context.hh)
|
|
template <class TC>
|
|
inline void
|
|
updateTCStatusView(TC *tc)
|
|
{
|
|
// TCStatus' register view must be the same as
|
|
// Status register view for CU, MX, KSU bits
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
|
|
StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
|
|
|
|
tcStatus.tcu = status.cu;
|
|
tcStatus.tmx = status.mx;
|
|
tcStatus.tksu = status.ksu;
|
|
|
|
tc->setMiscRegNoEffect(MISCREG_TC_STATUS, tcStatus);
|
|
}
|
|
|
|
} // namespace MipsISA
|
|
|
|
|
|
#endif
|