113 lines
4.0 KiB
C++
113 lines
4.0 KiB
C++
#include "iop_iop2iop.h"
|
|
#include "cray_mainframe.h"
|
|
#include <algorithm>
|
|
#include <time.h>
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// IopIopChannel_c
|
|
/////////////////////////////////////////////////////////
|
|
|
|
|
|
IopIopChannel_c::IopIopChannel_c(const Configuration_c &aConfig, IopCpu_c &aSrcIop, IopCpu_c &aDstIop, size_t aAIChannelIdx, size_t aAOChannelIdx) :
|
|
mAI(aConfig, *this, aAIChannelIdx),
|
|
mAO(aConfig, *this, aAOChannelIdx),
|
|
mSrcIop(aSrcIop),
|
|
mDstIop(aDstIop),
|
|
mData(0),
|
|
mThrottle(0),
|
|
mDataValid(false)
|
|
{
|
|
// mMultiThreaded = aSrcIop.GetMainframe().IsMultiThreaded();
|
|
}
|
|
|
|
IopInt_t IopIopChannel_c::ChannelAO_c::DoIo(IopIoFunction_t aFunction, IopInt_t aData) {
|
|
// Guard_t Guard(mParent.mLock);
|
|
switch (aFunction) {
|
|
case 000: {
|
|
mParent.mDataValid = false;
|
|
mDone = false;
|
|
} return 0;
|
|
case 001:
|
|
// Here we handle the dead-starting of the other IOP...
|
|
CRAY_ASSERT((aData & (1 << 2)) == 0); // Dead dump is not supported at the moment
|
|
CRAY_ASSERT((aData & 3) != 1); // Master-clear without deadstart isn't supported at the moment either
|
|
if ((aData & 3) == 0 && (mCtrlReg & 3) == 3 ) {
|
|
// This is the falling edge of master clear and dead-start, so let's dead-start the other IOP
|
|
// cout << "Getting IOP" << DecPrinter(mParent.mDstIop.GetCpuId()) << " out of reset by IOP" << DecPrinter(mParent.mSrcIop.GetCpuId()) << std::endl;
|
|
mLogger << setloglevel(LogLevel_IoActivity) << "Getting IOP" << DecPrinter(mParent.mDstIop.GetCpuId()) << " out of reset by IOP" << DecPrinter(mParent.mSrcIop.GetCpuId()) << std::endl;
|
|
mParent.mDstIop.DeadStart();
|
|
mResetStalling = true;
|
|
}
|
|
mCtrlReg = aData;
|
|
return 0;
|
|
case 006:
|
|
mInterruptEnabled = false;
|
|
return 0;
|
|
case 007:
|
|
mInterruptEnabled = true;
|
|
return 0;
|
|
case 014: {
|
|
if (mParent.mDataValid) {
|
|
mLogger << setloglevel(LogLevel_Error) << "ERROR: AO read called with channel data already valid" << std::endl;
|
|
}
|
|
mLogger << setloglevel(LogLevel_Communication) << "at " << CurrentTime() << " AO sending data " << HexPrinter(aData,4) << std::endl;
|
|
mParent.mData = aData;
|
|
mParent.mDataValid = true;
|
|
mDone = false;
|
|
} return 0;
|
|
default:
|
|
mLogger << setloglevel(LogLevel_Error) << "ERROR: Invalid function code for channel" << std::endl;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool IopIopChannel_c::ChannelAO_c::StallIop() {
|
|
// If we've resetted the target IOP, stall the source IOP until the target started executing instructions.
|
|
// This is needed because - in a multi-threaded environment - the target might take a long time to start and
|
|
// there's a fix delay in the source to change back the boot image in MOS memory (see iop_boot.asm around 0x493D).
|
|
if (mResetStalling) {
|
|
if (mParent.mDstIop.IsInReset()) return true;
|
|
// cout << "Releasing stall on IOP" << DecPrinter(mParent.mSrcIop.GetCpuId()) << std::endl;
|
|
mResetStalling = false;
|
|
}
|
|
// If there's valid data in the register, throttle source IOP execution - this is to avoid HALT 015 (communication buffer exhaustion during boot)
|
|
if (mParent.mDataValid) {
|
|
if (mThrottleCnt == 0) {
|
|
mThrottleCnt = mParent.mThrottle;
|
|
} else {
|
|
--mThrottleCnt;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
IopInt_t IopIopChannel_c::ChannelAI_c::DoIo(IopIoFunction_t aFunction, IopInt_t aData) {
|
|
// Guard_t Guard(mParent.mLock);
|
|
switch (aFunction) {
|
|
case 000: {
|
|
mParent.mDataValid = false;
|
|
} return 0;
|
|
case 006:
|
|
mInterruptEnabled = false;
|
|
return 0;
|
|
case 007:
|
|
mInterruptEnabled = true;
|
|
return 0;
|
|
case 010: {
|
|
if (!mParent.mDataValid) {
|
|
mLogger << setloglevel(LogLevel_Error) << "ERROR: AI read called with channel data invalid" << std::endl;
|
|
}
|
|
mLogger << setloglevel(LogLevel_Communication) << "at " << CurrentTime() << " AI receiving data " << HexPrinter(uint16_t(mParent.mData),4) << " with data valid: " << mParent.mDataValid << std::endl;
|
|
uint16_t Data = mParent.mData;
|
|
mParent.mDataValid = false;
|
|
mParent.mAO.SetDone(true);
|
|
return Data;
|
|
}
|
|
default:
|
|
mLogger << setloglevel(LogLevel_Error) << "ERROR: Invalid function code for channel" << std::endl;
|
|
return 0;
|
|
}
|
|
}
|
|
|