#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("StartupIopIdx", 0); // Load all buffer image files for (const auto &BufferImage : aConfig.get_child_safe("BufferImageFiles")) { size_t LoadAddress = FromString(BufferImage.first); std::string ImageFileName = BufferImage.second.get_value(); LoadBufferImage(ImageFileName.c_str(), CAddr_t(LoadAddress)); } // Create IOPs for (const auto &Iop : aConfig.get_child_safe("Iops")) { if (FromString(Iop.first) != mIops.size()) throw InvalidParameter_x("IOP index must start at 0 and must be contiguous"); mIops.push_back(std::make_unique( Iop.second, uint8_t(mIops.size()), &mBufferMemory, *this )); } // Connect IOPs together for (size_t i = 0; i Channel1 = std::make_unique(aConfig.get_child_safe("IOP2IOP"), mIops[i]->Cpu, mIops[j]->Cpu, 6 + 2 * i, 7 + 2 * j - 2); std::unique_ptr Channel2 = std::make_unique(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(BufferMemoryPoke.second.data()); size_t Addr = FromString(BufferMemoryPoke.first); if (Addr * sizeof(IopInt_t) >= mBufferMemory.size()) throw InvalidParameter_x("Buffer poke address outside of memory"); BufferMemAccessByType(CAddr_t(Addr)) = SwapBytes(Value); } mBufferMemoryDumpFileName = aConfig.get_optional("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; IopCpu.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); } }