1
0
mirror of synced 2026-01-27 12:01:45 +00:00
Files
andrastantos.cray-sim/simulator/sim_lib/cray_mainframe.h

506 lines
20 KiB
C++

#ifndef __CRAY_MAINFRAME_H__
#define __CRAY_MAINFRAME_H__
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <mutex>
#include "utils.h"
#include "cray_types.h"
#include <stdint.h>
#include <string.h>
#include <vector>
#include <map>
#include <limits.h>
#include <fstream>
#include <streambuf>
#include <sstream>
#include "sim_iop.h"
#include "iop_iop2iop.h"
#include "cray_channels.h"
#include "debug_events.h"
#include "config_file.h"
#include "sys_task_req.h"
#include "unicos_proc_list.h"
#include "iop_cluster_if.h"
// Cray Mainframe: this variant doesn't uses host-implemented IOPs instead of simulated ones
// !!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!
// !!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!
//
// To be true to the documentation, octal numbers are extensively used in this file.
// Watch out for the leading 0-s!
//
// !!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!
// !!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!
class SimIopCluster_c;
class Lock_c {
public:
Lock_c(std::atomic_flag &aFlag): mFlag(aFlag) {
while (mFlag.test_and_set());
}
~Lock_c() { mFlag.clear(); }
protected:
std::atomic_flag &mFlag;
};
class Terminate_x : public Generic_x {
public:
Terminate_x() { mErrorStrm << "*** TERMINATE ***"; }
};
class InterCpuCluster_c {
public:
InterCpuCluster_c() :
TestAndSetBlockedCnt(0),
ClusterCpuCnt(0)
{
ClusterMutex.clear();
}
void Dump(CLogger_c &aLogger, size_t aIdent=0) const {
for(size_t Idx=0;Idx<sizeof(SB)/sizeof(SB[0]);++Idx) {
aLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "SB" << DecPrinter(Idx,0) << ": " << HexPrinter(SB[Idx],6) << std::endl;
}
for(size_t Idx=0;Idx<sizeof(ST)/sizeof(ST[0]);++Idx) {
aLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "ST" << DecPrinter(Idx,0) << ": " << HexPrinter(ST[Idx],6) << std::endl;
}
// aLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "SM: " << HexPrinter(SM,8) << " (";
aLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "SM: (";
for(size_t Idx=0;Idx<32;++Idx) {
// aLogger << setloglevel(LogLevel_Dump) << (((SM & (0x80000000 >> Idx)) == 0) ? '0' : '1');
aLogger << setloglevel(LogLevel_Dump) << (SM[Idx] ? '0' : '1');
}
aLogger << setloglevel(LogLevel_Dump) << ')' << std::endl;
}
CAddr_t SB[8];
CInt_t ST[8];
std::array<std::atomic_bool, 32> SM;
size_t TestAndSetBlockedCnt;
size_t ClusterCpuCnt;
//std::mutex ClusterMutex;
std::atomic_flag ClusterMutex;
};
class Cpu_c;
class Mainframe_c;
class Mainframe_c: public TimeStampGenerator_i {
public:
class BreakPoint_i {
public:
BreakPoint_i() {}
virtual ~BreakPoint_i() {}
virtual void Fire(Cpu_c &aCpu) = 0;
virtual bool Test(const Cpu_c &aCpu, const Mainframe_c &aMainframe) = 0;
};
class BreakPointBase_c: public BreakPoint_i {
public:
explicit BreakPointBase_c(const Configuration_c &aConfig) {
/***
try {
for(const auto &DataCondition: aConfig.get_child_safe("DataConditions")) {
IopAddr_t Addr = FromString<IopAddr_t>(DataCondition.first);
IopInt_t Value = DataCondition.second.get_value<IopInt_t>();
mDataConditions.push_back(DataCondition_s(Addr,Value));
}
}
catch(exception &Ex) {
mDataConditions.clear();
throw Ex;
}
****/
mTriggerCnt = aConfig.get<size_t>("TriggerCnt", 0);
boost::optional<std::string> AbsoluteAddr = aConfig.get_optional<std::string>("AbsoluteAddr");
if (AbsoluteAddr.is_initialized()) {
mAbsoluteAddr = FromString(AbsoluteAddr.get(), StringFormat_e::ProgramAddr);
}
mPassCnt = 0;
};
virtual bool Test(const Cpu_c &aCpu, const Mainframe_c &aMainframe) override;
protected:
/***
struct DataCondition_s {
IopAddr_t Addr;
IopInt_t Value;
DataCondition_s(IopAddr_t aAddr, IopInt_t aValue): Addr(aAddr), Value(aValue) {}
};
vector<DataCondition_s> mDataConditions;
****/
size_t mPassCnt;
size_t mTriggerCnt;
boost::optional<CProgramAddr_t> mAbsoluteAddr;
};
class EventFirePoint_c: public BreakPointBase_c {
public:
EventFirePoint_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig), mEvent(aConfig.get<DebugEvent_t>("Event")) {}
virtual void Fire(Cpu_c &aCpu) override;
protected:
DebugEvent_t mEvent;
};
class TracePoint_c : public BreakPointBase_c {
public:
TracePoint_c(const Configuration_c &aConfig) : BreakPointBase_c(aConfig), mTrace(aConfig.get<std::string>("Message")) {}
virtual void Fire(Cpu_c &aCpu) override;
protected:
std::string mTrace;
};
class DumpPoint_c : public BreakPointBase_c {
public:
DumpPoint_c(const Configuration_c &aConfig) : BreakPointBase_c(aConfig) {}
virtual void Fire(Cpu_c &aCpu) override;
protected:
std::string mTrace;
};
class CpuDumpPoint_c: public BreakPointBase_c {
public:
CpuDumpPoint_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig) {}
virtual void Fire(Cpu_c &aCpu) override;
};
class TerminatePoint_c: public BreakPointBase_c {
public:
TerminatePoint_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig), mMessage(aConfig.get<std::string>("Message")) {}
virtual void Fire(Cpu_c &aCpu) override;
protected:
std::string mMessage;
};
class LogOn_c: public BreakPointBase_c {
public:
LogOn_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig) {}
virtual void Fire(Cpu_c &aCpu) override;
};
class LogOff_c: public BreakPointBase_c {
public:
LogOff_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig) {}
virtual void Fire(Cpu_c &aCpu) override;
};
class LogLevel_c: public BreakPointBase_c {
public:
LogLevel_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig) {
std::string Level = aConfig.get<std::string>("Level");
mLogLevel = FromString_LogLevels_e(Level);
}
virtual void Fire(Cpu_c &aCpu) override;
protected:
LogLevels_e mLogLevel;
};
class LogLevelPush_c: public BreakPointBase_c {
public:
LogLevelPush_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig) {
std::string Level = aConfig.get<std::string>("Level");
mLogLevel = FromString_LogLevels_e(Level);
}
virtual void Fire(Cpu_c &aCpu) override;
protected:
LogLevels_e mLogLevel;
};
class LogLevelPop_c: public BreakPointBase_c {
public:
LogLevelPop_c(const Configuration_c &aConfig): BreakPointBase_c(aConfig) {}
virtual void Fire(Cpu_c &aCpu) override;
};
class Dump_c : public BreakPointBase_c {
public:
Dump_c(const Configuration_c &aConfig) : BreakPointBase_c(aConfig) {}
virtual void Fire(Cpu_c &aCpu) override;
};
class History_c : public BreakPointBase_c {
public:
History_c(const Configuration_c &aConfig) : BreakPointBase_c(aConfig) {}
virtual void Fire(Cpu_c &aCpu) override;
};
typedef std::map<CProgramAddr_t, std::vector<std::shared_ptr<BreakPoint_i>>> BreakPoints_t;
class ImageLoadFailure_x: public std::exception {
public:
ImageLoadFailure_x(const char *aFileName, const char *aReason) {
std::stringstream Strm;
Strm << "Image file: " << aFileName << " cannot be loaded due to: " << aReason;
mErrorStr = Strm.str();
}
ImageLoadFailure_x(const char *aFileName) {
std::stringstream Strm;
Strm << "Image file: " << aFileName << " cannot be loaded";
mErrorStr = Strm.str();
}
virtual const char *what() const throw() override { return mErrorStr.c_str(); }
protected:
std::string mErrorStr;
};
typedef std::unique_ptr<Cpu_c> (*CpuCreator_t)(Mainframe_c *aThis, const std::string aName, const std::string aType, const Configuration_c &aCpuConfig, const Configuration_c &aDefaultCpuConfig, BreakPoints_t &aBreakPoints, size_t aCpuId);
typedef std::unique_ptr<IopClusterBase_i>(*IopClusterCreator_t)(Mainframe_c *aThis, std::string aType, const Configuration_c &aConfig, size_t aIopId);
explicit Mainframe_c(const Configuration_c &aConfig, CLogger_c &aLogger, bool aMultiThreaded, bool aDisableAutoTerminal, CpuCreator_t aCpuCreator = CreateCpu, IopClusterCreator_t aIopClusterCreator = CreateIopCluster);
explicit Mainframe_c(size_t aMemSize, MachineTypes_e aMachineType);
virtual ~Mainframe_c() override;
size_t GetChannelCnt() const { return mChannels.size(); }
typedef Channel_i *ChannelPtr_t;
ChannelPtr_t &GetChannel(size_t aIdx) {
CRAY_ASSERT(aIdx < mChannels.size());
return mChannels[aIdx];
}
const ChannelPtr_t &GetChannel(size_t aIdx) const {
CRAY_ASSERT(aIdx < mChannels.size());
return mChannels[aIdx];
}
void SetChannel(size_t aIdx, Channel_i &aChannel) {
CRAY_ASSERT(aIdx < mChannels.size());
if (mChannels[aIdx] != nullptr) {
CRAY_ASSERT(mOwnedChannels[aIdx] != nullptr);
mLogger << setloglevel(LogLevel_Warning) << "WARNING: replacing channel at channel number: " << DecPrinter(aIdx + 8) << std::endl;
mOwnedChannels[aIdx] = nullptr; // Remove the possibly default channel
}
mChannels[aIdx] = &aChannel;
RebuildTickedChannels();
}
typedef IteratorWrapper_t<Mainframe_c, ChannelPtr_t, &Mainframe_c::GetChannelCnt, &Mainframe_c::GetChannel> ChannelIteratorWrapper_c;
const ChannelIteratorWrapper_c GetChannels() { return ChannelIteratorWrapper_c(*this); }
typedef ConstIteratorWrapper_t<Mainframe_c, ChannelPtr_t, &Mainframe_c::GetChannelCnt, &Mainframe_c::GetChannel> ConstChannelIteratorWrapper_c;
const ConstChannelIteratorWrapper_c GetChannels() const { return ConstChannelIteratorWrapper_c(*this); }
size_t GetCpuCnt() const { return mCpus.size(); }
Cpu_c &GetCpu(size_t aIdx) {
CRAY_ASSERT(aIdx < mCpus.size());
return *mCpus[aIdx];
}
const Cpu_c &GetCpu(size_t aIdx) const {
CRAY_ASSERT(aIdx < mCpus.size());
return *mCpus[aIdx];
}
typedef IteratorWrapper_t<Mainframe_c, Cpu_c, &Mainframe_c::GetCpuCnt, &Mainframe_c::GetCpu> CpuIteratorWrapper_c;
const CpuIteratorWrapper_c GetCpus() { return CpuIteratorWrapper_c(*this); }
typedef ConstIteratorWrapper_t<Mainframe_c, Cpu_c, &Mainframe_c::GetCpuCnt, &Mainframe_c::GetCpu> ConstCpuIteratorWrapper_c;
const ConstCpuIteratorWrapper_c GetCpus() const { return ConstCpuIteratorWrapper_c(*this); }
size_t GetIopClusterCnt() const { return mIopClusters.size(); }
IopClusterBase_i &GetIopCluster(size_t aIdx) {
CRAY_ASSERT(aIdx < mIopClusters.size());
return *mIopClusters[aIdx];
}
const IopClusterBase_i &GetIopCluster(size_t aIdx) const {
CRAY_ASSERT(aIdx < mIopClusters.size());
return *mIopClusters[aIdx];
}
typedef IteratorWrapper_t<Mainframe_c, IopClusterBase_i, &Mainframe_c::GetIopClusterCnt, &Mainframe_c::GetIopCluster> IopIteratorWrapper_c;
const IopIteratorWrapper_c GetIopClusters() { return IopIteratorWrapper_c(*this); }
typedef ConstIteratorWrapper_t<Mainframe_c, IopClusterBase_i, &Mainframe_c::GetIopClusterCnt, &Mainframe_c::GetIopCluster> ConstIopIteratorWrapper_c;
const ConstIopIteratorWrapper_c GetIopClusters() const { return ConstIopIteratorWrapper_c(*this); }
size_t GetClusterCnt() const { return mClusters.size(); }
InterCpuCluster_c &GetCluster(size_t aIdx) {
CRAY_ASSERT(aIdx < mClusters.size());
return *mClusters[aIdx];
}
const InterCpuCluster_c &GetCluster(size_t aIdx) const {
CRAY_ASSERT(aIdx < mClusters.size());
return *mClusters[aIdx];
}
typedef IteratorWrapper_t<Mainframe_c, InterCpuCluster_c, &Mainframe_c::GetClusterCnt, &Mainframe_c::GetCluster> ClusterIteratorWrapper_c;
const ClusterIteratorWrapper_c GetClusters() { return ClusterIteratorWrapper_c(*this); }
typedef ConstIteratorWrapper_t<Mainframe_c, InterCpuCluster_c, &Mainframe_c::GetClusterCnt, &Mainframe_c::GetCluster> ConstClusterIteratorWrapper_c;
ConstClusterIteratorWrapper_c GetClusters() const { return ConstClusterIteratorWrapper_c(*this); }
std::vector<uint8_t> &GetMemory() { return mMemory; }
const std::vector<uint8_t> &GetMemory() const { return mMemory; }
size_t GetMemorySize() { return mMemory.size(); }
size_t GetMemorySizeInWords() const { return mMemSizeInWords; }
size_t GetMemorySizeInParcels() const { return mMemSizeInParcels; }
size_t mMemSizeInWords;
size_t mMemSizeInParcels;
void SetLastCpuIssuedCI(size_t aCpuId) { mLastCpuIssuedCI = aCpuId; }
void IoMasterClear(bool aMasterClear);
void CpuMasterClear(bool aMasterClear);
void DeadStart();
void ChannelTick();
virtual CInt_t GetRealTimeClock() const;
void SetRealTimeClock(CInt_t aValue) {
if (mUseHostRealTimeClock) {
mRealTimeStart = mRealTimeTimer.elapsed().wall;
mLastRealTimeReading = 0;
}
mRealTimeClock = aValue;
}
void UpdateRealTimeClock() { if (!mUseHostRealTimeClock) mRealTimeClock += mRealTimeClockIncrement; }
void Dump(size_t aIdent=0) const;
void DumpMemories() const;
void DumpHistory();
CLogger_c &GetLogger() const { return mLogger; }
virtual uint64_t GetTimeStamp() const override { return mEnableTimeStamp ? mTickCnt : 0ULL; }
virtual uint64_t GetResolution() const override { return 105000000ULL; } // TODO: make this configurable
const DebugEventDispatcher_c &GetEventDispatcher() const { return mEventDispatcher; }
DebugEventDispatcher_c &GetEventDispatcher() { return mEventDispatcher; }
void HandleDebugEvent(const DebugEvent_t &aEvent) {
//std::cout << "EVENT POINTS LENGTH: " << mEventPoints.size() << std::endl;
mEventPoints.Fire(aEvent);
}
bool IsMultiThreaded() const { return mMultiThreaded; }
OsTypes_e GetOsType() const { return mOsType; }
void LoadImageFile(const char *aFileName, CAddr_t aLoadAddr, size_t aPreamble = 0, size_t aImageSize = std::numeric_limits<size_t>::max());
MachineTypes_e GetMachineType() const { return mMachineType; }
void HandleDeadLock(uint16_t aCluster);
void RouteChannelInterrupt(); // Route the channel interrupt to the appropriate CPU
bool DoDisableAutoTerminal() const { return mDisableAutoTerminal; }
CInt_t SimToHost(CInt_t aValue);
CInt_t HostToSim();
void RegisterCommands(CommandHooks_t &aHooks);
protected:
MachineTypes_e mMachineType;
bool mMultiThreaded;
bool mDisableAutoTerminal;
mutable CInt_t mLastRealTimeReading;
CInt_t mDeltaClockIncrement;
class MainFrameEventDispatcher_c: public DebugEventDispatcher_c {
public:
MainFrameEventDispatcher_c(Mainframe_c &aParent): mParent(aParent) {}
virtual void Fire(const DebugEvent_t &aEvent) const override {
mParent.GetLogger() << setloglevel(LogLevel_EventFire) << aEvent << std::endl;
DebugEventDispatcher_c::Fire(aEvent);
}
protected:
Mainframe_c &mParent;
} mEventDispatcher;
struct MemoryPoke_s {
CAddr_t Addr;
CInt_t Value;
bool IsParcelPoke;
};
std::vector<MemoryPoke_s> mMemoryPokes;
bool mMemoryPokesProcessed;
std::vector<std::unique_ptr<Cpu_c>> mCpus;
std::vector<std::unique_ptr<IopClusterBase_i>> mIopClusters;
std::vector<std::unique_ptr<IopIopChannel_c>> mIopIopChannels;
size_t mLastCpuIssuedCI; // Index to the last CPU that issued a clear interrupt
std::vector<std::unique_ptr<InterCpuCluster_c>> mClusters;
std::vector<Channel_i*> mChannels;
std::vector<Channel_i*> mTickedChannels;
std::vector<std::unique_ptr<Channel_i>> mOwnedChannels;
std::vector<uint8_t> mMemory;
uint8_t *mFastMemory;
uint8_t mStartupCpuIdx;
void RebuildTickedChannels();
boost::timer::cpu_timer mRealTimeTimer;
boost::timer::nanosecond_type mRealTimeStart;
double mSystemClockPeriod;
CInt_t mRealTimeClock;
CInt_t mRealTimeClockIncrement;
CInt_t mRealTimeClockChunkLimit;
bool mUseHostRealTimeClock;
struct WatchPoint_c {
WatchPoint_c() {}
explicit WatchPoint_c(const std::string &aMessage): mHitCnt(0), mMessage(aMessage) {}
size_t mHitCnt;
std::string mMessage;
};
std::map<CAddr_t, WatchPoint_c> mWatchPoints;
static std::shared_ptr<BreakPoint_i> CreateBreakPoint(const std::string &aBreakPointType, const Configuration_c &aConfig);
class EventPoints_c: public EventPoints_t<BreakPoint_i> {
public:
explicit EventPoints_c(Mainframe_c &aParent): mParent(aParent) {}
protected:
virtual void FireBreakPoint(BreakPoint_i *aBreakPoint) override { if (aBreakPoint->Test(mParent.GetCpu(0), mParent)) aBreakPoint->Fire(mParent.GetCpu(0)); } // TODO: which CPU to pass on to Fire???
virtual std::shared_ptr<BreakPoint_i> CreateBreakPoint(const std::string &aBreakPointType, const Configuration_c &aConfig) override { return Mainframe_c::CreateBreakPoint(aBreakPointType, aConfig); }
Mainframe_c &mParent;
};
EventPoints_c mEventPoints;
bool mIoMasterClear;
bool mCpuMasterClear;
uint64_t mTickCnt;
bool mEnableTimeStamp;
OsTypes_e mOsType;
void CheckWatchPointsInternal(CAddr_t aAddr, bool aWrite, CInt_t aData);
void CheckWatchPoints(CAddr_t aAddr, CInt_t aData) {
#ifndef CRAY_TURBO
if (mProcListParser != nullptr) mProcListParser->TestMemAccess(aAddr, aData);
#endif
if (mWatchPoints.empty()) return;
CheckWatchPointsInternal(aAddr, true, aData);
}
void CheckWatchPoints(CAddr_t aAddr) {
if (mWatchPoints.empty()) return;
CheckWatchPointsInternal(aAddr, false, 0);
}
std::string ReportHist() const;
std::string ReportBBHist() const;
public:
struct ReadOutOfBoundsError_x : public Generic_x { ReadOutOfBoundsError_x() : Generic_x("Data read out of bounds") {} };
template <typename aType> aType MemReadNoWatchpoint(const CAddr_t aAddr) const { size_t Addr = size_t(aAddr) * 8; if (Addr >= mMemory.size()) throw ReadOutOfBoundsError_x(); return *(aType *)(&mMemory[Addr]); } // Default addresses are by QWORDs
template <typename aType> aType MemReadNoWatchpointByType(const CAddr_t aAddr) const { size_t Addr = size_t(aAddr) * sizeof(aType); if (Addr >= mMemory.size()) throw ReadOutOfBoundsError_x(); return *(aType *)(&mMemory[Addr]); }
template <typename aType> aType MemReadNoWatchpointByByte(const CAddr_t aAddr) const { size_t Addr = size_t(aAddr); if (Addr >= mMemory.size()) throw ReadOutOfBoundsError_x(); return *(aType *)(&mMemory[Addr]); }
// template <typename aType> void MemWriteNoWatchpoint(const CAddr_t aAddr, aType aVal) { CheckWatchPoints(aAddr, aVal); *(aType *)(&mMemory[aAddr * 8]) = aVal; } // Default addresses are by QWORDs
template <typename aType> void MemWriteNoWatchpointByType(const CAddr_t aAddr, aType aVal) { *(aType *)(&mMemory[aAddr * sizeof(aType)]) = aVal; }
// template <typename aType> void MemWriteNoWatchpointByByte(const CAddr_t aAddr, aType aVal) { *(aType *)(&mMemory[size_t(aAddr)]) = aVal; }
// template <typename aType> aType *MemAccess(const CAddr_t aAddr) { CheckWatchPoints(aAddr); return (aType *)(&mMemory[aAddr * 8]); } // Default addresses are by QWORDs
template <typename aType> aType *MemAccessByType(const CAddr_t aAddr) { CheckWatchPoints(aAddr * sizeof(aType) / 8); return (aType *)(&mMemory[aAddr * sizeof(aType)]); }
// template <typename aType> aType *MemAccessByByte(const CAddr_t aAddr) { CheckWatchPoints(aAddr / 8); return (aType *)(&mMemory[size_t(aAddr)]); }
template <typename aType> aType MemRead(const CAddr_t aAddr) { CheckWatchPoints(aAddr); return *(aType *)(&mMemory[aAddr * 8]); } // Default addresses are by QWORDs
template <typename aType> aType MemReadByType(const CAddr_t aAddr) { CheckWatchPoints(aAddr * sizeof(aType) / 8); return *(aType *)(&mMemory[aAddr * sizeof(aType)]); }
template <typename aType> aType MemReadByByte(const CAddr_t aAddr) { CheckWatchPoints(aAddr / 8); return *(aType *)(&mMemory[size_t(aAddr)]); }
// template <typename aType> void MemWrite(const CAddr_t aAddr, aType aVal) { CheckWatchPoints(aAddr); *(aType *)(&mMemory[aAddr * 8]) = aVal; } // Default addresses are by QWORDs
// template <typename aType> void MemWriteByType(const CAddr_t aAddr, aType aVal) { CheckWatchPoints(aAddr * sizeof(aType) / 8); *(aType *)(&mMemory[aAddr * sizeof(aType)]) = aVal; }
void MemWrite(const CAddr_t aAddr, uint8_t aVal) { CheckWatchPoints(aAddr / 8); mMemory[size_t(aAddr)] = aVal; }
void MemWrite(const CAddr_t aAddr, CInt_t aVal) { CheckWatchPoints(aAddr, aVal); *(CInt_t *)(&mMemory[aAddr * 8]) = aVal; } // Default addresses are by QWORDs
protected:
boost::optional<std::string> mMainMemoryDumpFileName;
mutable CLogger_c mLogger;
std::unique_ptr<UnicosProcList_c> mProcListParser;
// A function that needs to be implemented to create various CPU types inside the final applcation.
// If not, then the application will not link.
static std::unique_ptr<Cpu_c> CreateCpu(Mainframe_c *aThis, const std::string aName, const std::string aType, const Configuration_c &aCpuConfig, const Configuration_c &aDefaultCpuConfig, BreakPoints_t &aBreakPoints, size_t aCpuId);
static std::unique_ptr<IopClusterBase_i> CreateIopCluster(Mainframe_c *aThis, std::string aType, const Configuration_c &aConfig, size_t aIopId);
};
#endif // __CRAY_MAINFRAME_H__