2007-06-23 01:03:42 +02:00
|
|
|
/*
|
2007-11-17 03:32:22 +01:00
|
|
|
* Copyright (c) 2007 MIPS Technologies, Inc.
|
|
|
|
* All rights reserved.
|
2007-06-23 01:03:42 +02:00
|
|
|
*
|
2007-11-17 03:32:22 +01:00
|
|
|
* 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.
|
2007-06-23 01:03:42 +02:00
|
|
|
*
|
2007-11-17 03:32:22 +01:00
|
|
|
* 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.
|
2007-11-13 22:58:16 +01:00
|
|
|
*
|
2007-11-15 20:21:01 +01:00
|
|
|
* Authors: Korey Sewell
|
2007-06-23 01:03:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __ARCH_MIPS_MT_HH__
|
|
|
|
#define __ARCH_MIPS_MT_HH__
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
*
|
|
|
|
* ISA-specific helper functions for multithreaded execution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "arch/mips/faults.hh"
|
2009-07-09 08:02:21 +02:00
|
|
|
#include "arch/mips/isa_traits.hh"
|
2007-06-23 01:03:42 +02:00
|
|
|
#include "arch/mips/mt_constants.hh"
|
2009-07-21 05:14:15 +02:00
|
|
|
#include "arch/mips/pra_constants.hh"
|
2009-07-09 08:02:21 +02:00
|
|
|
#include "arch/mips/registers.hh"
|
2007-06-23 01:03:42 +02:00
|
|
|
#include "base/bitfield.hh"
|
|
|
|
#include "base/trace.hh"
|
|
|
|
#include "base/misc.hh"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
namespace MipsISA
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
template <class TC>
|
|
|
|
inline unsigned
|
|
|
|
getVirtProcNum(TC *tc)
|
|
|
|
{
|
2009-07-21 05:14:15 +02:00
|
|
|
TCBindReg tcbind = tc->readMiscRegNoEffect(TCBind);
|
|
|
|
return tcbind.curVPE;
|
2007-06-23 01:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class TC>
|
|
|
|
inline unsigned
|
|
|
|
getTargetThread(TC *tc)
|
|
|
|
{
|
2009-07-21 05:14:15 +02:00
|
|
|
VPEControlReg vpeCtrl = tc->readMiscRegNoEffect(VPEControl);
|
|
|
|
return vpeCtrl.targTC;
|
2007-06-23 01:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
tc->setMiscReg(TCRestart, tc->readNextPC());
|
|
|
|
|
2008-11-04 17:35:42 +01:00
|
|
|
warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x", curTick, tc->threadId(), tc->getCpuPtr()->name(),
|
2007-06-23 01:03:42 +02:00
|
|
|
tc->readPC(), tc->readNextPC());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class TC>
|
|
|
|
inline void
|
|
|
|
restoreThread(TC *tc)
|
|
|
|
{
|
|
|
|
if (tc->status() != TC::Active) {
|
|
|
|
// Restore PC from TCRestart
|
|
|
|
IntReg pc = tc->readMiscRegNoEffect(TCRestart);
|
|
|
|
|
|
|
|
// TODO: SET PC WITH AN EVENT INSTEAD OF INSTANTANEOUSLY
|
|
|
|
// tc->setPCEvent(pc, pc + 4, pc + 8);
|
|
|
|
tc->setPC(pc);
|
|
|
|
tc->setNextPC(pc + 4);
|
|
|
|
tc->setNextNPC(pc + 8);
|
|
|
|
tc->activate(0);
|
|
|
|
|
2008-11-04 17:35:42 +01:00
|
|
|
warn("%i: Restoring thread %i in %s @ PC %x", curTick, tc->threadId(), tc->getCpuPtr()->name(),
|
2007-06-23 01:03:42 +02:00
|
|
|
tc->readPC());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class TC>
|
|
|
|
void
|
|
|
|
forkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt)
|
|
|
|
{
|
2009-07-21 05:14:15 +02:00
|
|
|
MVPConf0Reg mvpConf = tc->readMiscRegNoEffect(MVPConf0);
|
|
|
|
int num_threads = mvpConf.ptc + 1;
|
2007-06-23 01:03:42 +02:00
|
|
|
|
|
|
|
int success = 0;
|
2009-05-26 18:23:13 +02:00
|
|
|
for (ThreadID tid = 0; tid < num_threads && success == 0; tid++) {
|
2009-07-21 05:14:15 +02:00
|
|
|
TCBindReg tidTCBind =
|
|
|
|
tc->readRegOtherThread(TCBind + Ctrl_Base_DepTag, tid);
|
|
|
|
TCBindReg tcBind = tc->readMiscRegNoEffect(TCBind);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
if (tidTCBind.curVPE = tcBind.curVPE) {
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
TCStatusReg tidTCStatus =
|
|
|
|
tc->readRegOtherThread(TCStatus + Ctrl_Base_DepTag,tid);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
TCHaltReg tidTCHalt =
|
|
|
|
tc->readRegOtherThread(TCHalt + Ctrl_Base_DepTag,tid);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
if (tidTCStatus.da == 1 && tidTCHalt.h == 0 &&
|
|
|
|
tidTCStatus.a == 0 && success == 0) {
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
tc->setRegOtherThread(TCRestart + Ctrl_Base_DepTag, Rs, tid);
|
2007-06-23 01:03:42 +02:00
|
|
|
tc->setRegOtherThread(Rd_bits, Rt, tid);
|
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
StatusReg status = tc->readMiscReg(Status);
|
|
|
|
TCStatusReg tcStatus = tc->readMiscReg(TCStatus);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
|
|
|
// Set Run-State to Running
|
2009-07-21 05:14:15 +02:00
|
|
|
tidTCStatus.rnst = 0;
|
2007-06-23 01:03:42 +02:00
|
|
|
// Set Delay-Slot to 0
|
2009-07-21 05:14:15 +02:00
|
|
|
tidTCStatus.tds = 0;
|
2007-06-23 01:03:42 +02:00
|
|
|
// Set Dirty TC to 1
|
2009-07-21 05:14:15 +02:00
|
|
|
tidTCStatus.dt = 1;
|
2007-06-23 01:03:42 +02:00
|
|
|
// Set Activated to 1
|
2009-07-21 05:14:15 +02:00
|
|
|
tidTCStatus.a = 1;
|
2007-06-23 01:03:42 +02:00
|
|
|
// Set status to previous thread's status
|
2009-07-21 05:14:15 +02:00
|
|
|
tidTCStatus.tksu = status.ksu;
|
2007-06-23 01:03:42 +02:00
|
|
|
// Set ASID to previous thread's state
|
2009-07-21 05:14:15 +02:00
|
|
|
tidTCStatus.asid = tcStatus.asid;
|
2007-06-23 01:03:42 +02:00
|
|
|
|
|
|
|
// Write Status Register
|
2009-07-21 05:14:15 +02:00
|
|
|
tc->setRegOtherThread(TCStatus + Ctrl_Base_DepTag,
|
|
|
|
tidTCStatus, tid);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
|
|
|
// Mark As Successful Fork
|
|
|
|
success = 1;
|
|
|
|
}
|
|
|
|
} else {
|
2009-03-06 02:15:31 +01:00
|
|
|
std::cerr << "Bad VPEs" << std::endl;
|
2007-06-23 01:03:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (success == 0) {
|
2009-07-21 05:14:15 +02:00
|
|
|
VPEControlReg vpeControl = tc->readMiscRegNoEffect(VPEControl);
|
|
|
|
vpeControl.excpt = 1;
|
|
|
|
tc->setMiscReg(VPEControl, vpeControl);
|
2007-06-23 01:03:42 +02:00
|
|
|
fault = new ThreadFault();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <class TC>
|
|
|
|
int
|
|
|
|
yieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask)
|
|
|
|
{
|
|
|
|
if (src_reg == 0) {
|
2009-07-21 05:14:15 +02:00
|
|
|
MVPConf0Reg mvpConf0 = tc->readMiscRegNoEffect(MVPConf0);
|
|
|
|
ThreadID num_threads = mvpConf0.ptc + 1;
|
2007-06-23 01:03:42 +02:00
|
|
|
|
|
|
|
int ok = 0;
|
|
|
|
|
|
|
|
// Get Current VPE & TC numbers from calling thread
|
2009-07-21 05:14:15 +02:00
|
|
|
TCBindReg tcBind = tc->readMiscRegNoEffect(TCBind);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-05-26 18:23:13 +02:00
|
|
|
for (ThreadID tid = 0; tid < num_threads; tid++) {
|
2009-07-21 05:14:15 +02:00
|
|
|
TCStatusReg tidTCStatus =
|
|
|
|
tc->readRegOtherThread(TCStatus + Ctrl_Base_DepTag, tid);
|
|
|
|
TCHaltReg tidTCHalt =
|
|
|
|
tc->readRegOtherThread(TCHalt + Ctrl_Base_DepTag, tid);
|
|
|
|
TCBindReg tidTCBind =
|
|
|
|
tc->readRegOtherThread(TCBind + Ctrl_Base_DepTag, tid);
|
|
|
|
|
|
|
|
if (tidTCBind.curVPE == tcBind.curVPE &&
|
|
|
|
tidTCBind.curTC == tcBind.curTC &&
|
|
|
|
tidTCStatus.da == 1 &&
|
|
|
|
tidTCHalt.h == 0 &&
|
|
|
|
tidTCStatus.a == 1) {
|
2007-06-23 01:03:42 +02:00
|
|
|
ok = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ok == 1) {
|
2009-07-21 05:14:15 +02:00
|
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
|
|
|
|
tcStatus.a = 0;
|
|
|
|
tc->setMiscReg(TCStatus, tcStatus);
|
|
|
|
warn("%i: Deactivating Hardware Thread Context #%i",
|
|
|
|
curTick, tc->threadId());
|
2007-06-23 01:03:42 +02:00
|
|
|
}
|
|
|
|
} else if (src_reg > 0) {
|
2008-09-26 17:18:56 +02:00
|
|
|
if (src_reg && !yield_mask != 0) {
|
2009-07-21 05:14:15 +02:00
|
|
|
VPEControlReg vpeControl = tc->readMiscReg(VPEControl);
|
|
|
|
vpeControl.excpt = 2;
|
|
|
|
tc->setMiscReg(VPEControl, vpeControl);
|
2007-06-23 01:03:42 +02:00
|
|
|
fault = new ThreadFault();
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
} else if (src_reg != -2) {
|
2009-07-21 05:14:15 +02:00
|
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
|
|
|
|
VPEControlReg vpeControl = tc->readMiscRegNoEffect(VPEControl);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
if (vpeControl.ysi == 1 && tcStatus.dt == 1 ) {
|
|
|
|
vpeControl.excpt = 4;
|
2007-06-23 01:03:42 +02:00
|
|
|
fault = new 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
|
2009-07-21 05:14:15 +02:00
|
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
|
|
|
|
StatusReg status = tc->readMiscRegNoEffect(Status);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
status.cu = tcStatus.tcu;
|
|
|
|
status.mx = tcStatus.tmx;
|
|
|
|
status.ksu = tcStatus.tksu;
|
2007-06-23 01:03:42 +02:00
|
|
|
|
|
|
|
tc->setMiscRegNoEffect(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
|
2009-07-21 05:14:15 +02:00
|
|
|
TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
|
|
|
|
StatusReg status = tc->readMiscRegNoEffect(Status);
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
tcStatus.tcu = status.cu;
|
|
|
|
tcStatus.tmx = status.mx;
|
|
|
|
tcStatus.tksu = status.ksu;
|
2007-06-23 01:03:42 +02:00
|
|
|
|
2009-07-21 05:14:15 +02:00
|
|
|
tc->setMiscRegNoEffect(TCStatus, tcStatus);
|
2007-06-23 01:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace MipsISA
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|