1
0
mirror of synced 2026-01-17 08:32:10 +00:00
2020-09-09 15:11:45 -07:00

146 lines
5.6 KiB
C++

#include "iop_cluster.h"
#include "cray_mainframe.h"
IopCluster_c::IopCluster_c(const Configuration_c &aConfig, CLogger_c &aLogger, size_t aIopClusterId, class Mainframe_c &aMainframe) :
mIoMasterClear(false),
mLogger(aConfig),
mMainframe(aMainframe),
mIopClusterId(aIopClusterId),
mIopTickIdx(0)
{
mLogger.SetParent(aLogger);
try {
// Create shared memories
mBufferMemory.resize(aConfig.get("BufferMemorySize", 8 * 1024 * 1024) * sizeof(uint64_t), 0);
// Set startup CPU
mStartupIopIdx = aConfig.get<size_t>("StartupIopIdx", 0);
// Load all buffer image files
for (const auto &BufferImage : aConfig.get_child_safe("BufferImageFiles")) {
size_t LoadAddress = FromString<size_t>(BufferImage.first);
std::string ImageFileName = BufferImage.second.get_value<std::string>();
LoadBufferImage(ImageFileName.c_str(), CAddr_t(LoadAddress));
}
// Create IOPs
for (const auto &Iop : aConfig.get_child_safe("Iops")) {
if (FromString<size_t>(Iop.first) != mIops.size()) throw InvalidParameter_x("IOP index must start at 0 and must be contiguous");
mIops.push_back(std::make_unique<Iop_s>(
Iop.second,
uint8_t(mIops.size()),
&mBufferMemory,
*this
));
}
// Connect IOPs together
for (size_t i = 0; i<mIops.size(); ++i) {
for (size_t j = i + 1; j<mIops.size(); ++j) {
std::unique_ptr<IopIopChannel_c> Channel1 = std::make_unique<IopIopChannel_c>(aConfig.get_child_safe("IOP2IOP"), mIops[i]->Cpu, mIops[j]->Cpu, 6 + 2 * i, 7 + 2 * j - 2);
std::unique_ptr<IopIopChannel_c> Channel2 = std::make_unique<IopIopChannel_c>(aConfig.get_child_safe("IOP2IOP"), mIops[j]->Cpu, mIops[i]->Cpu, 6 + 2 * j - 2, 7 + 2 * i);
/* mIops[i]->Cpu.Connect(6+2*j-2,Channel2->GetAI());
mIops[i]->Cpu.Connect(7+2*j-2,Channel1->GetAO());
mIops[j]->Cpu.Connect(6+2*i,Channel1->GetAI());
mIops[j]->Cpu.Connect(7+2*i,Channel2->GetAO());*/
mIops[i]->Cpu.Connect(&Channel2->GetChannel(0));
mIops[i]->Cpu.Connect(&Channel1->GetChannel(1));
mIops[j]->Cpu.Connect(&Channel1->GetChannel(0));
mIops[j]->Cpu.Connect(&Channel2->GetChannel(1));
mIopIopChannels.push_back(move(Channel1));
mIopIopChannels.push_back(move(Channel2));
}
}
// Execute buffer-memory pokes to change memory image
for (const auto &BufferMemoryPoke : aConfig.get_child_safe("BufferMemoryPokes")) {
IopInt_t Value = FromString<IopInt_t>(BufferMemoryPoke.second.data());
size_t Addr = FromString<size_t>(BufferMemoryPoke.first);
if (Addr * sizeof(IopInt_t) >= mBufferMemory.size()) throw InvalidParameter_x("Buffer poke address outside of memory");
BufferMemAccessByType<IopInt_t>(CAddr_t(Addr)) = SwapBytes(Value);
}
mBufferMemoryDumpFileName = aConfig.get_optional<std::string>("BufferMemoryDumpFile");
}
catch (...) {
mIops.clear();
mIopIopChannels.clear();
mBufferMemory.clear();
throw;
}
}
void IopCluster_c::LoadBufferImage(const char *aFileName, CAddr_t aLoadAddr) {
CRAY_ASSERT(mBufferMemory.size() % sizeof(CInt_t) == 0);
CAddr_t MemSize = CAddr_t(mBufferMemory.size() / sizeof(uint64_t));
if (aLoadAddr > MemSize) throw Mainframe_c::ImageLoadFailure_x(aFileName, "load address is beyond buffer memory size");
std::ifstream File(aFileName, std::ios_base::in | std::ios_base::binary);
if (File.fail()) throw Mainframe_c::ImageLoadFailure_x(aFileName, "can't open file");
uint64_t FileSize = boost::filesystem::file_size(aFileName); // we use 64-bit arithmetic here to avoid truncation of very large file sizes even though we can't load them
if (FileSize % sizeof(uint64_t) != 0) throw Mainframe_c::ImageLoadFailure_x(aFileName, "file size is not modulo 8");
if (FileSize / sizeof(uint64_t) + size_t(aLoadAddr) > size_t(MemSize)) throw Mainframe_c::ImageLoadFailure_x(aFileName, "file doesn't fit in buffer memory");
File.read((char*)(&mBufferMemory[(size_t(aLoadAddr) * sizeof(uint64_t))]), FileSize);
size_t BytesRead = size_t(File.gcount());
if (BytesRead != FileSize || File.fail()) throw Mainframe_c::ImageLoadFailure_x(aFileName, "can't read file");
}
void IopCluster_c::DeadStart() {
MasterClear();
if (mStartupIopIdx < mIops.size()) {
mIops[mStartupIopIdx]->Cpu.DeadStart();
}
}
void IopCluster_c::MasterClear() {
for (auto &Iop : GetIops()) Iop.MasterClear();
}
void IopCluster_c::GetPeripheralStatus(StatusReport_c &aStatus, PeripheralType_e aFilter, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const {
for (auto &Iop : mIops) {
StatusReport_c Status;
Iop->Cpu.GetPeripheralStatus(Status, aFilter, aElapsedTime, aLongFormat);
if (!Status.empty()) {
aStatus.put_child(Iop->Cpu.GetName(), Status);
}
}
}
std::string IopCluster_c::GetName() const {
std::stringstream Name;
Name << "ICL" << DecPrinter(mIopClusterId);
return Name.str();
}
std::string IopCluster_c::GetLongName() const {
std::stringstream Name;
Name << "IOP Cluster " << DecPrinter(mIopClusterId);
return Name.str();
}
void IopCluster_c::Dump(size_t aIdent) const {
for (size_t Iop = 0; Iop<mIops.size(); ++Iop) {
if (mIops[Iop] == nullptr) continue;
mLogger << setloglevel(LogLevel_Dump) << "Iop" << DecPrinter(Iop, 0) << std::endl;
mIops[Iop]->Cpu.Dump(aIdent + 1);
}
}
void IopCluster_c::Tick() {
if (mIopTickIdx < mIops.size()) {
mIops[mIopTickIdx]->Cpu.Tick();
}
++mIopTickIdx;
if (mIopTickIdx >= mIops.size()) mIopTickIdx = 0;
}
void IopCluster_c::GetCpuStatus(StatusReport_c &aStatus, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const {
size_t IopCnt = GetIopCnt();
for (size_t IopIdx = 0; IopIdx < IopCnt; ++IopIdx) {
StatusReport_c IopStatus;
GetIop(IopIdx).GetStatus(IopStatus, aElapsedTime, aLongFormat);
aStatus.put_child(GetIop(IopIdx).GetName(), IopStatus);
}
}