// Cray-XMP I/O Processor simulator class // !!!!!!!!!!!! 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 !!!!!!!!!!!!!! #include #include #include #include "utils.h" #include "cray_iop.h" #include "cray_mainframe.h" #include "iop_bmx.h" #include "iop_concentrator.h" #include "iop_console.h" #include "iop_disk.h" #include "iop_expander.h" #include "iop_host_memory.h" #include "iop_iop2cray.h" #include "iop_iop2iop.h" #include "iop_era.h" #include "iop_cluster.h" enum IopChannelTypes_e { IopChannelType_IOR, IopChannelType_PFR, IopChannelType_PXS, IopChannelType_LME, IopChannelType_RTC, IopChannelType_MOS, IopChannelType_AI, IopChannelType_AO, IopChannelType_ERA, IopChannelType_EXB, IopChannelType_CI, IopChannelType_CO, IopChannelType_TI, IopChannelType_TO, IopChannelType_HI, IopChannelType_HO, IopChannelType_DK, IopChannelType_BM, IopChannelType_Unkown }; IopChannelTypes_e GetChannelType(IopTypes_e aCpuType, uint16_t aChannel) { switch (aCpuType) { case IopType_MIOP: switch(aChannel) { case 000: return IopChannelType_IOR; case 001: return IopChannelType_PFR; case 002: return IopChannelType_PXS; case 003: return IopChannelType_LME; case 004: return IopChannelType_RTC; case 005: return IopChannelType_MOS; case 006: return IopChannelType_AI; case 007: return IopChannelType_AO; case 010: return IopChannelType_AI; case 011: return IopChannelType_AO; case 012: return IopChannelType_AI; case 013: return IopChannelType_AO; case 016: return IopChannelType_ERA; case 017: return IopChannelType_EXB; case 020: return IopChannelType_CI; case 021: return IopChannelType_CO; case 024: return IopChannelType_CI; case 025: return IopChannelType_CO; case 030: return IopChannelType_CI; case 031: return IopChannelType_CO; case 034: return IopChannelType_CI; case 035: return IopChannelType_CO; case 040: return IopChannelType_TI; case 041: return IopChannelType_TO; case 042: return IopChannelType_TI; case 043: return IopChannelType_TO; case 044: return IopChannelType_TI; case 045: return IopChannelType_TO; case 046: return IopChannelType_TI; case 047: return IopChannelType_TO; default: return IopChannelType_Unkown; } break; case IopType_BIOP: switch(aChannel) { case 000: return IopChannelType_IOR; case 001: return IopChannelType_PFR; case 002: return IopChannelType_PXS; case 003: return IopChannelType_LME; case 004: return IopChannelType_RTC; case 005: return IopChannelType_MOS; case 006: return IopChannelType_AI; case 007: return IopChannelType_AO; case 010: return IopChannelType_AI; case 011: return IopChannelType_AO; case 012: return IopChannelType_AI; case 013: return IopChannelType_AO; case 014: return IopChannelType_HI; case 015: return IopChannelType_HO; case 020: return IopChannelType_DK; case 021: return IopChannelType_DK; case 022: return IopChannelType_DK; case 023: return IopChannelType_DK; case 024: return IopChannelType_DK; case 025: return IopChannelType_DK; case 026: return IopChannelType_DK; case 027: return IopChannelType_DK; default: return IopChannelType_Unkown; } break; case IopType_DIOP: switch(aChannel) { case 000: return IopChannelType_IOR; case 001: return IopChannelType_PFR; case 002: return IopChannelType_PXS; case 003: return IopChannelType_LME; case 004: return IopChannelType_RTC; case 005: return IopChannelType_MOS; case 006: return IopChannelType_AI; case 007: return IopChannelType_AO; case 010: return IopChannelType_AI; case 011: return IopChannelType_AO; case 012: return IopChannelType_AI; case 013: return IopChannelType_AO; case 020: return IopChannelType_DK; case 021: return IopChannelType_DK; case 022: return IopChannelType_DK; case 023: return IopChannelType_DK; case 024: return IopChannelType_DK; case 025: return IopChannelType_DK; case 026: return IopChannelType_DK; case 027: return IopChannelType_DK; case 030: return IopChannelType_DK; case 031: return IopChannelType_DK; case 032: return IopChannelType_DK; case 033: return IopChannelType_DK; case 034: return IopChannelType_DK; case 035: return IopChannelType_DK; case 036: return IopChannelType_DK; case 037: return IopChannelType_DK; default: return IopChannelType_Unkown; } break; case IopType_XIOP: switch(aChannel) { case 000: return IopChannelType_IOR; case 001: return IopChannelType_PFR; case 002: return IopChannelType_PXS; case 003: return IopChannelType_LME; case 004: return IopChannelType_RTC; case 005: return IopChannelType_MOS; case 006: return IopChannelType_AI; case 007: return IopChannelType_AO; case 010: return IopChannelType_AI; case 011: return IopChannelType_AO; case 012: return IopChannelType_AI; case 013: return IopChannelType_AO; case 020: return IopChannelType_BM; case 021: return IopChannelType_BM; case 022: return IopChannelType_BM; case 023: return IopChannelType_BM; case 024: return IopChannelType_BM; case 025: return IopChannelType_BM; case 026: return IopChannelType_BM; case 027: return IopChannelType_BM; case 030: return IopChannelType_BM; case 031: return IopChannelType_BM; case 032: return IopChannelType_BM; case 033: return IopChannelType_BM; case 034: return IopChannelType_BM; case 035: return IopChannelType_BM; case 036: return IopChannelType_BM; case 037: return IopChannelType_BM; default: return IopChannelType_Unkown; } break; default: return IopChannelType_Unkown; } } class ChannelPrinter: public FieldFormatter_i { public: explicit ChannelPrinter(IopTypes_e aCpuType, uint16_t aChannel): Channel(aChannel), CpuType(aCpuType) {} virtual void Print(std::ostream &aStream) const { std::stringstream Str; IopChannelTypes_e ChannelType = GetChannelType(CpuType, Channel); switch (ChannelType) { case IopChannelType_IOR: Str << OctPrinter(Channel,3) << " (IOR)"; break; case IopChannelType_PFR: Str << OctPrinter(Channel,3) << " (PFR)"; break; case IopChannelType_PXS: Str << OctPrinter(Channel,3) << " (PXS)"; break; case IopChannelType_LME: Str << OctPrinter(Channel,3) << " (LME)"; break; case IopChannelType_RTC: Str << OctPrinter(Channel,3) << " (RTC)"; break; case IopChannelType_MOS: Str << OctPrinter(Channel,3) << " (MOS)"; break; case IopChannelType_AI: switch (CpuType) { case IopType_MIOP: switch (Channel) { case 006: Str << OctPrinter(Channel,3) << " (AIA_BIOP)"; break; case 010: Str << OctPrinter(Channel,3) << " (AIB_DIOP)"; break; case 012: Str << OctPrinter(Channel,3) << " (AIC_XIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; case IopType_BIOP: switch (Channel) { case 006: Str << OctPrinter(Channel,3) << " (AIA_MIOP)"; break; case 010: Str << OctPrinter(Channel,3) << " (AIB_DIOP)"; break; case 012: Str << OctPrinter(Channel,3) << " (AIC_XIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; case IopType_DIOP: switch (Channel) { case 006: Str << OctPrinter(Channel,3) << " (AIA_MIOP)"; break; case 010: Str << OctPrinter(Channel,3) << " (AIB_BIOP)"; break; case 012: Str << OctPrinter(Channel,3) << " (AIC_XIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; case IopType_XIOP: switch (Channel) { case 006: Str << OctPrinter(Channel,3) << " (AIA_MIOP)"; break; case 010: Str << OctPrinter(Channel,3) << " (AIB_BIOP)"; break; case 012: Str << OctPrinter(Channel,3) << " (AIC_DIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; default: Str << OctPrinter(Channel,3); break; } break; case IopChannelType_AO: switch (CpuType) { case IopType_MIOP: switch (Channel) { case 007: Str << OctPrinter(Channel,3) << " (AOA_BIOP)"; break; case 011: Str << OctPrinter(Channel,3) << " (AOB_DIOP)"; break; case 013: Str << OctPrinter(Channel,3) << " (AOC_XIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; case IopType_BIOP: switch (Channel) { case 007: Str << OctPrinter(Channel,3) << " (AOA_MIOP)"; break; case 011: Str << OctPrinter(Channel,3) << " (AOB_DIOP)"; break; case 013: Str << OctPrinter(Channel,3) << " (AOC_XIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; case IopType_DIOP: switch (Channel) { case 007: Str << OctPrinter(Channel,3) << " (AOA_MIOP)"; break; case 011: Str << OctPrinter(Channel,3) << " (AOB_BIOP)"; break; case 013: Str << OctPrinter(Channel,3) << " (AOC_XIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; case IopType_XIOP: switch (Channel) { case 007: Str << OctPrinter(Channel,3) << " (AOA_MIOP)"; break; case 011: Str << OctPrinter(Channel,3) << " (AOB_BIOP)"; break; case 013: Str << OctPrinter(Channel,3) << " (AOC_DIOP)"; break; default: Str << OctPrinter(Channel,3); break; } break; default: Str << OctPrinter(Channel,3); break; } break; case IopChannelType_ERA: Str << OctPrinter(Channel,3) << " (ERA)"; break; case IopChannelType_EXB: Str << OctPrinter(Channel,3) << " (EXB)"; break; case IopChannelType_CI: Str << OctPrinter(Channel,3) << " (CI)"; break; case IopChannelType_CO: Str << OctPrinter(Channel,3) << " (CO)"; break; case IopChannelType_TI: Str << OctPrinter(Channel,3) << " (TI)"; break; case IopChannelType_TO: Str << OctPrinter(Channel,3) << " (TO)"; break; case IopChannelType_HI: Str << OctPrinter(Channel,3) << " (HI)"; break; case IopChannelType_HO: Str << OctPrinter(Channel,3) << " (HO)"; break; case IopChannelType_DK: Str << OctPrinter(Channel,3) << " (DK)"; break; case IopChannelType_BM: Str << OctPrinter(Channel,3) << " (BM)"; break; case IopChannelType_Unkown: Str << OctPrinter(Channel,3); break; default: CRAY_ASSERT(false); } aStream << Str.str(); } uint16_t Channel; IopTypes_e CpuType; }; #ifdef DEFAULT_FUNCTIONS #error DEFAULT_FUNCTIONS is already defined #endif #define DEFAULT_FUNCTIONS \ case 006: Str << "Clear the channel interrupt enable flag"; break; \ case 007: Str << "Set the channel interrupt enable flag"; break; class IoFunctionNotePrinter: public FieldFormatter_i { public: IoFunctionNotePrinter(IopTypes_e aCpuType, uint16_t aChannel, uint16_t aFunction): CpuType(aCpuType), Channel(aChannel), Function(aFunction) {} virtual void Print(std::ostream &aStream) const { std::stringstream Str; IopChannelTypes_e ChannelType = GetChannelType(CpuType, Channel); switch(ChannelType) { case IopChannelType_IOR: switch(Function) { case 010: Str << "Read interrupt channel number (highest priority channel with active interrupt request)"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_PFR: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear program fetch request flag"; break; case 010: Str << "Read origin of the fetch request (the OR register number that was 0 during a jump)"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_PXS: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the exit stack boundary flag"; break; case 010: Str << "Read the E (stack pointer) register"; break; case 011: Str << "Read the value pointed to by the E (stack pointer) register"; break; case 014: Str << "Write the E (stack pointer) register"; break; case 015: Str << "Write the value pointed to by the E (stack pointer) register"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_LME: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the I/O memory parity error flag"; break; case 010: Str << "Read the memory error position info"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_RTC: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel done flag (next interrupt in 1ms)"; break; case 010: Str << "Read the top 16 bits of the 17-bit RTC"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_MOS: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel busy and done flags"; break; case 001: Str << "Write the I/O memory address (in QWORDS)"; break; case 002: Str << "Write the 15 high-order bits on the Buffer memory address (in QWORDS)"; break; case 003: Str << "Write the 9 low-order bits of the buffer memory address (in QWORDS)"; break; case 004: Str << "Set transfer length and start Buffer --> I/O memory transfer (in QWORDS, 0 is 128kBytes)"; break; case 005: Str << "Set transfer length and start I/O --> Buffer memory transfer (in QWORDS, 0 is 128kBytes)"; break; case 014: Str << "Set control register (bit 0: disable error correction, bit 1: disable write checks, bit 2: disable refersh)"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_AI: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel done flag"; break; case 010: Str << "Read A of remote IOP"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_AO: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel busy and done flags"; break; case 001: Str << "Set control register (bit 0: Master clear, bit 1: Deadstart, bit 2: Dead dump)"; break; case 014: Str << "Send A to remote IOP"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_ERA: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Idle channel"; break; case 010: Str << "Read error status"; break; case 011: Str << "Read 1st error parameter"; break; case 012: Str << "Read 2nd error parameter"; break; case 013: Str << "Read 3rd error parameter"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_EXB: switch(Function) { case 000: Str << "Idle the channel"; break; case 001: Str << "Request data input from A register (DIA)"; break; case 002: Str << "Request data input from B register (DIB)"; break; case 003: Str << "Request data input from C register (DIC)"; break; case 004: Str << "Request read busy/done flag, interrupt number"; break; case 005: Str << "Load device address"; break; case 006: Str << "Send interface mask (MSKO)"; break; case 007: Str << "Set interrupt mode"; break; case 010: Str << "Read data bus status"; break; case 011: Str << "Read status 1"; break; case 013: Str << "Read status 2"; break; case 014: Str << "Data output to A register (DOA)"; break; case 015: Str << "Data output to B register (DOB)"; break; case 016: Str << "Data output to C register (DOC)"; break; case 017: Str << "Send control"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_CI: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear channel"; break; case 001: Str << "Enter I/O memory address, start input"; break; case 002: Str << "Enter parcel count"; break; case 003: Str << "Clear channel parity error flags"; break; case 004: Str << "Clear ready waiting flag"; break; case 010: Str << "Read I/O memory address"; break; case 011: Str << "Read status (ready waiting, parity errors)"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_CO: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear channel"; break; case 001: Str << "Enter I/O memory address, start output"; break; case 002: Str << "Enter parcel count"; break; case 003: Str << "Clear error flag"; break; case 004: Str << "Set/clear external control signals"; break; case 010: Str << "Read I/O memory address"; break; case 011: Str << "Read status (4-bit channel data, error)"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_TI: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel done flag"; break; case 010: Str << "Read data"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_TO: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel busy and done flag"; break; case 014: Str << "Send data to display"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_HI: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel busy and done flag"; break; case 001: Str << "Set I/O memory address"; break; case 002: Str << "Set upper Central Memory address"; break; case 003: Str << "Set lower Central Memory address"; break; case 004: Str << "Set Block length, start I/O memory <-- Central Memory transfer"; break; case 014: Str << "Enter diagnostic mode"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_HO: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear the channel busy and done flag"; break; case 001: Str << "Set I/O memory address"; break; case 002: Str << "Set upper Central Memory address"; break; case 003: Str << "Set lower Central Memory address"; break; case 005: Str << "Set Block length, start I/O memory --> Central Memory transfer"; break; case 014: Str << "Enter diagnostic mode"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_DK: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear channel control"; break; case 001: Str << "Select mode or request status"; break; case 002: Str << "Read data into I/O memory"; break; case 003: Str << "Write data from I/O memory"; break; case 004: Str << "Select new head group"; break; case 005: Str << "Select new cylinder"; break; case 010: Str << "Read I/O Memory current address"; break; case 011: Str << "Read status response"; break; case 014: Str << "Set I/O Memory start address"; break; case 015: Str << "Status response register diagnostic"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_BM: switch(Function) { DEFAULT_FUNCTIONS case 000: Str << "Clear channel control"; break; case 001: Str << "Send reset functions"; break; case 002: Str << "Channel command"; break; case 003: Str << "Read request-in address"; break; case 004: Str << "Asynchronous I/O"; break; case 005: Str << "Delay counter diagnostics"; break; case 010: Str << "Read I/O Memory address"; break; case 011: Str << "Read byte count"; break; case 012: Str << "Read status"; break; case 013: Str << "Read input tags"; break; case 014: Str << "Set I/O Memory address"; break; case 015: Str << "Set byte count"; break; case 016: Str << "Set device address"; break; case 017: Str << "Set output tags"; break; default: Str << "**** Undefined function ****"; break; } break; case IopChannelType_Unkown: Str << "**** Undefined function ****"; break; default: CRAY_ASSERT(false); } aStream << Str.str(); } uint16_t Channel; uint16_t Function; IopTypes_e CpuType; }; #undef DEFAULT_FUNCTIONS std::shared_ptr IopCpu_c::CreateBreakPoint(const std::string &aBreakPointType, const Configuration_c &aConfig) { if (aBreakPointType == "LogOn") { return std::make_shared(aConfig); } else if (aBreakPointType == "Terminate") { return std::make_shared(aConfig); } else if (aBreakPointType == "LogOff") { return std::make_shared(aConfig); } else if (aBreakPointType == "LogLevel") { return std::make_shared(aConfig); } else if (aBreakPointType == "LogLevelPush") { return std::make_shared(aConfig); } else if (aBreakPointType == "LogLevelPop") { return std::make_shared(aConfig); } else if (aBreakPointType == "Trace") { return std::make_shared(aConfig); } else if (aBreakPointType == "Event") { return std::make_shared(aConfig); } else { throw InvalidParameter_x(boost::format("Unkown breakpoint type:") % aBreakPointType); } } IopCpu_c::IopCpu_c(const Configuration_c &aConfig, uint8_t aCpuId, std::vector &aIoMemory, std::vector *aBufferMemory, class IopCluster_c &aIopCluster): mIoMemory(aIoMemory), mCpuId(aCpuId), mState( aConfig, *this, aConfig.get("ClockFrequency", 80000000), aConfig.get("TimerLimit", 79999) ), mBufferMemory(aBufferMemory), mIopCluster(&aIopCluster), mLogger(aConfig,"IOP",aCpuId), mEventPoints(*this), mInstCnt(0), mLastInstCnt(0), RefOrB(*this), RefA(*this), RefC(*this), RefC_A(*this), RefB(*this) { mExists = aConfig.get("Exists", true); mLogger.SetParent(aIopCluster.GetLogger()); try { boost::optional DefaultLogLevel = aConfig.get_optional("DefaultLogLevel"); if (DefaultLogLevel.is_initialized()) { mLogger.SetDisplayLogLevel(FromString_LogLevels_e(DefaultLogLevel.get())); } std::string IopType = aConfig.get("Type"); if (IopType == "MIOP") mType = IopType_MIOP; else if (IopType == "BIOP") mType = IopType_BIOP; else if (IopType == "DIOP") mType = IopType_DIOP; else if (IopType == "XIOP") mType = IopType_XIOP; else throw boost::property_tree::ptree_bad_data("Type",IopType); mIoChannels.resize(aConfig.get("ChannelCount", 42),nullptr); mIoChannels[mState.ChannelIOR.GetChannelIdx()] = &mState.ChannelIOR; mIoChannels[mState.ChannelPFR.GetChannelIdx()] = &mState.ChannelPFR; mIoChannels[mState.ChannelPXS.GetChannelIdx()] = &mState.ChannelPXS; mIoChannels[mState.ChannelLME.GetChannelIdx()] = &mState.ChannelLME; mIoChannels[mState.ChannelRTC.GetChannelIdx()] = &mState.ChannelRTC; mIoChannels[mState.ChannelMOS.GetChannelIdx()] = &mState.ChannelMOS; // Load all channels for(const auto &ChannelConfig: aConfig.get_child_safe("Channels")) { std::string PeripheralType = ChannelConfig.first; // Create the appropriate peripheral std::shared_ptr Peripheral; if (PeripheralType == "ERA") { Peripheral = std::make_shared(ChannelConfig.second, *this, ChannelConfig.second.get("ChannelIdx")); } else if (PeripheralType == "Console") { Peripheral = std::make_shared(ChannelConfig.second, *this, mIopCluster->GetMainframe().DoDisableAutoTerminal()); } else if (PeripheralType == "HIA") { Peripheral = std::make_shared(ChannelConfig.second, *this, mIopCluster->GetMainframe().GetMemory(), ChannelConfig.second.get("ChannelIdx"), true, false); } else if (PeripheralType == "HOA") { Peripheral = std::make_shared(ChannelConfig.second, *this, mIopCluster->GetMainframe().GetMemory(), ChannelConfig.second.get("ChannelIdx"), false, true); } else if (PeripheralType == "Expander") { Peripheral = std::make_shared(ChannelConfig.second, *this); } else if (PeripheralType == "DD29") { Peripheral = std::make_shared(ChannelConfig.second, *this); } else if (PeripheralType == "Bmx") { Peripheral = std::make_shared(ChannelConfig.second, *this); } else if (PeripheralType == "CI") { size_t CrayChannelIdx = ChannelConfig.second.get("CrayChannelIdx"); size_t IopChannelIdx = ChannelConfig.second.get("IopChannelIdx"); std::shared_ptr LocalChannel = std::make_shared(ChannelConfig.second, *this, mIopCluster->GetMainframe(), IopChannelIdx, CrayChannelIdx, true, false); mIopCluster->GetMainframe().SetChannel(CrayChannelIdx-8,*LocalChannel); Peripheral = LocalChannel; } else if (PeripheralType == "CO") { size_t CrayChannelIdx = ChannelConfig.second.get("CrayChannelIdx"); size_t IopChannelIdx = ChannelConfig.second.get("IopChannelIdx"); std::shared_ptr LocalChannel = std::make_shared(ChannelConfig.second, *this, mIopCluster->GetMainframe(), IopChannelIdx, CrayChannelIdx ,false, true); mIopCluster->GetMainframe().SetChannel(CrayChannelIdx-8,*LocalChannel); Peripheral = LocalChannel; } else if (PeripheralType == "CONC") { Peripheral = std::make_shared(ChannelConfig.second, *this); } else { throw InvalidParameter_x(boost::format("Unkown channel type : %1$s") % PeripheralType); } // Connect the peripheral to the channels for(size_t i=0;iGetChannelCnt();++i) { const IopChannel_i &Channel = Peripheral->GetChannel(i); const IopChannel_i *OldChannel; OldChannel = Connect(&Channel); if (OldChannel != nullptr) { throw InvalidParameter_x(boost::format("Duplicate channel specification for channel %1$03o") % Channel.GetChannelIdx()); } } mPeripherals.push_back(Peripheral); } // Populate the channels that need a tick call for (auto &IoChannel : mIoChannels) { if (IoChannel != nullptr && IoChannel->NeedsTick()) { mIoTickChannels.emplace_back(IoChannel); } } // Load all break-points for(const auto &BreakPoint: aConfig.get_child_safe("BreakPoints")) { std::string BreakPointType = BreakPoint.second.get("Type"); IopInt_t Addr = FromString(BreakPoint.first); std::shared_ptr BreakPointObj(CreateBreakPoint(BreakPointType,BreakPoint.second)); CRAY_ASSERT(BreakPointObj != nullptr); mBreakPoints[Addr].push_back(BreakPointObj); } // Load all event-points mEventPoints.LoadEventPoints(aConfig.get_child_safe("EventPoints")); mInstructionBurstSize = aConfig.get("InstructionBurstSize", 1)-1; // Register ourselves for receving events mIopCluster->GetMainframe().GetEventDispatcher().AddHandler(*this); } catch (...) { mPeripherals.clear(); mBreakPoints.clear(); throw; } } void IopCpu_c::GetStatus(StatusReport_c &aStatus, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const { if (!mState.InReset) { aStatus.put("State", "ON "); } else { aStatus.put("State", "off"); } double InstCntDelta = double(mInstCnt) - double(mLastInstCnt); mLastInstCnt = uint64_t(mInstCnt); double AvgInstCnt = InstCntDelta / aElapsedTime * 1000.0; // Get instructions per microsecond or virtual MHz... std::stringstream SpeedStr; SpeedStr << DoublePrinter(AvgInstCnt, 5, 3); aStatus.put("MIPS", SpeedStr.str()); } void IopCpu_c::GetPeripheralStatus(StatusReport_c &aStatus, PeripheralType_e aFilter, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const { for (auto &Peripheral : mPeripherals) { if (Peripheral->GetType() == aFilter) { StatusReport_c Status; Peripheral->GetStatus(Status, aFilter, aLongFormat); if (!Status.empty()) { aStatus.put_child(Peripheral->GetName(), Status); } } if (Peripheral->GetType() == PeripheralType_e::Expander || Peripheral->GetType() == PeripheralType_e::Bmx) { StatusReport_c Status; Peripheral->GetStatus(Status, aFilter, aLongFormat); if (!Status.empty()) { aStatus.put_child(Peripheral->GetName(), Status); } } } } void IopCpu_c::RegisterCommands(CommandHooks_t &aHooks) { for (auto &Peripheral : mPeripherals) { Peripheral->RegisterCommands(aHooks); } } std::string IopCpu_c::GetName() const { std::stringstream Name; Name << "IOP" << DecPrinter(mCpuId); return Name.str(); } void IopCpu_c::Dump(size_t aIdent) const { mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "InReset: " << (mState.InReset ? "yes" : "no") << std::endl; if (mState.InReset) return; mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "A: " << HexPrinter(mState.A) << std::endl; mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "C: " << DecPrinter(mState.Carry,1) << std::endl; mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "B: " << HexPrinter(mState.B) << std::endl; mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "P: " << HexPrinter(mState.P) << std::endl; mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "I: " << DecPrinter(mState.I,1) << std::endl; mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "ISet is waiting: " << (mState.ISetIsWaiting ? "yes" : "no") << std::endl; for(size_t RegIdx=0;RegIdxDump(aIdent+1); } } void IopCpu_c::mShiftRight(IopInt_t aAmount) { uint32_t Data = RefC_A; if (aAmount > 16) Data = 0; else Data >>= aAmount; RefC_A = Data; } void IopCpu_c::mRotateRight(IopInt_t aAmount) { uint64_t Data = (uint64_t(RefC_A) << 17 * 2) | (uint64_t(RefC_A) << 17) | (RefC_A); aAmount &= 0x1f; Data >>= aAmount; RefC_A = uint32_t(Data); } void IopCpu_c::mShiftLeft(IopInt_t aAmount) { uint32_t Data = RefC_A; if (aAmount > 17) Data = 0; else Data <<= aAmount; RefC_A = Data; } void IopCpu_c::mRotateLeft(IopInt_t aAmount) { uint64_t Data = (uint64_t(RefC_A) << 17 * 2) | (uint64_t(RefC_A) << 17) | (RefC_A); aAmount &= 0x1f; Data <<= aAmount; Data >>= 17; RefC_A = uint32_t(Data); } void IopCpu_c::Increment(IopInt_t aAmount) { uint32_t Data = RefC_A; Data += aAmount; RefC_A = Data; } void IopCpu_c::Decrement(IopInt_t aAmount) { uint32_t Data = RefC_A; Data += (uint32_t)((uint16_t)~aAmount)+1; // Data += ~(uint32_t)aAmount; // Data += 1; RefC_A = Data; } void IopCpu_c::MasterClear() { mState.P = 0; mState.ChannelPXS.SetE(mState.ChannelPXS.GetE() + 1); mState.I = 1; mState.ISetIsWaiting = false; for(size_t i=0;iMasterClear(); } mInstCnt = 0; } IopInt_t IopCpu_c::Disassemble(IopInt_t aP, std::ostream &aDisassembly, std::ostream &aExplanation, std::ostream &InstFields) { IopInt_t OldP = mState.P; mState.P = aP; IopParcel_t FirstParcel = IoMemAccess(mState.P); IopParcel_t SecondParcel = 0; SecondParcel = IoMemAccess((mState.P+1) & 0xffff); bool DelayISet = false; bool BreakBurst; IopInt_t Increment = Decode(FirstParcel,SecondParcel,false,aDisassembly,aExplanation,DelayISet,BreakBurst); if (Increment == 1) { InstFields << HexPrinter(FirstParcel,4) << "-" << " " << " f:" << OctPrinter(FirstParcel >> 9,4) << " d:" << DecPrinter(FirstParcel & 0x1ff,4); } else { InstFields << HexPrinter(FirstParcel,4) << "-" << HexPrinter(SecondParcel,4) << " f:" << OctPrinter(FirstParcel >> 9,4) << " d:" << DecPrinter(FirstParcel & 0x1ff,4); } mState.P = OldP; return Increment; } void IopCpu_c::Tick() { // Advance all I/O channels /* for(size_t i=0;iTick(); }*/ for (auto &IoChannel : mIoTickChannels) { IoChannel->Tick(); } if (MultiThreadedSupport) { // See if any of the channels wants to stall the IOP for (size_t i = 0; i < mIoChannels.size(); ++i) { if (mIoChannels[i] != nullptr && mIoChannels[i]->StallIop()) return; } } // Check for interrupts if (mState.I != 0) { bool HaveInterrupt = false; for(size_t i=0;iGetInterrupt() != 0) { mLogger << setloglevel(LogLevel_Event) << "================================ INT" << OctPrinter(i,3) << " ================================" << std::endl; //cout << "================================ INT" << OctPrinter(i,3) << " to " << "IOP" << DecPrinter(mCpuId) << " ================================" << std::endl; HaveInterrupt = true; break; } } } if (HaveInterrupt) { if (mState.InReset) { mLogger << setloglevel(LogLevel_Event) << "================================ IOP is starting ================================" << std::endl; // cout << "================================ IOP" << DecPrinter(mCpuId) << " is starting ================================" << std::endl; mInstCnt = 0; } mState.InReset = false; mState.I = 0; mState.ChannelPXS.Push(mState.P); mState.P = mState.ChannelPXS.GetAt(0); } } if (!mState.InReset) { for(size_t i=0;i<=mInstructionBurstSize;++i) { mInstCnt++; if (SingleStep()) break; } } } static NullStrm_c NullStrm; // Return true to break the burst bool IopCpu_c::SingleStep() { IopParcel_t FirstParcel = IoMemAccess(mState.P); IopParcel_t SecondParcel = 0; SecondParcel = IoMemAccess((mState.P+1) & 0xffff); bool DelayISet = false; if (mBreakPoints.size() > 0) { auto BreakPointIt = mBreakPoints.find(mState.P); if (BreakPointIt != mBreakPoints.end()) { for (auto &BreakPoint : BreakPointIt->second) { if (BreakPoint->Test(GetDma())) BreakPoint->Fire(*this); } } } bool BreakBurst; LogLine_c LogLine = mLogger << setloglevel(LogLevel_InstructionTrace); if (LogLine.good()) { std::stringstream Disassembly; std::stringstream Explanation; Decode(FirstParcel,SecondParcel,true,Disassembly,Explanation,DelayISet,BreakBurst); LogLine << "exec " << HexPrinter(mState.P) << " " << std::left << std::setw(30) << Disassembly.str() << std::setw(0); if (Explanation.str().length() > 0) { LogLine << " | " << Explanation.str() << std::endl; } else { LogLine << std::endl; } } IopInt_t Increment = Decode(FirstParcel,SecondParcel,true,NullStrm,NullStrm,DelayISet,BreakBurst); // Implement delayed-enable of interrupts if (!DelayISet && mState.ISetIsWaiting) { mState.I = 1; mState.ISetIsWaiting = false; } mState.P += Increment; return BreakBurst; } template IopInt_t IopCpu_c::DecodeJump( IopParcel_t aFirstParcel, IopParcel_t aSecondParcel, bool aInSimulation, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aDelayISet, bool &aBreakBurst ) { aDelayISet = false; aBreakBurst = false; uint16_t f = aFieldF; uint16_t d = (aFirstParcel & 0x01ff) >> 0; uint16_t k = aSecondParcel; RefOr_s RefOr(d, *this); // special-case branch and call instructions as they have a condition field in them as well CRAY_ASSERT( ((f & 0770) == 0070) || ((f & 0740) == 0100) ); uint16_t InstCode = 0xffff; const char *ConditionStr = ""; bool Condition = true; switch (f & 0770) { case 0070: // Unconditional group InstCode = f & 00007; ConditionStr = ""; Condition = true; break; case 0100: case 0110: case 0120: case 0130: switch (f & 3) { case 0: // C = 0 group InstCode = (f >> 2) & 00007; ConditionStr = ", C = 0"; Condition = RefC == 0; break; case 1: // C = 1 group InstCode = (f >> 2) & 00007; ConditionStr = ", C = 1"; Condition = RefC != 0; break; case 2: // A = 0 group InstCode = (f >> 2) & 00007; ConditionStr = ", A = 0"; Condition = RefA == 0; break; case 3: // A # 0 group InstCode = (f >> 2) & 00007; ConditionStr = ", A # 0"; Condition = RefA != 0; break; default: CRAY_ASSERT(false); } break; default: CRAY_ASSERT(false); } switch (InstCode) { case 0000: // P = P + d if (!aDoExecute) { aDisassembly << "P = P + " << DecPrinter(d) << " (" << HexPrinter(GetProgramCounter() + d, 4) << ")" << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { mLogger << setloglevel(LogLevel_Event) << "================================ JUMP =========================" << std::endl; mState.P = mState.P + d; return 0; // P is already modified, don't modify it any further } } return 1; case 0001: // P = P - d if (!aDoExecute) { aDisassembly << "P = P - " << DecPrinter(d) << " (" << HexPrinter(GetProgramCounter() - d, 4) << ")" << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { mLogger << setloglevel(LogLevel_Event) << "================================ JUMP =========================" << std::endl; mState.P = mState.P - d; return 0; // P is already modified, don't modify it any further } } return 1; case 0002: // R = P + d if (!aDoExecute) { aDisassembly << "R = P + " << DecPrinter(d) << " (" << HexPrinter(GetProgramCounter() + d, 4) << ")" << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { mLogger << setloglevel(LogLevel_Event) << "================================ CALL =========================" << std::endl; IopInt_t Target = mState.P + d; mState.P = mState.P + 1; // mLogger.Indent(); mState.ChannelPXS.Push(mState.P); mState.P = Target; aBreakBurst = true; return 0; // P is already modified, don't modify it any further } } return 1; case 0003: // R = P - d if (!aDoExecute) { aDisassembly << "R = P - " << DecPrinter(d) << " (" << HexPrinter(GetProgramCounter() - d, 4) << ")" << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { mLogger << setloglevel(LogLevel_Event) << "================================ CALL =========================" << std::endl; IopInt_t Target = mState.P - d; mState.P = mState.P + 1; // mLogger.Indent(); mState.ChannelPXS.Push(mState.P); mState.P = Target; aBreakBurst = true; return 0; // P is already modified, don't modify it any further } } return 1; case 0004: // P = dd if (!aDoExecute) { aDisassembly << "P = " << RefOr << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { if (RefOr == 0) { mLogger << setloglevel(LogLevel_Event) << "================================ PFR REQ =========================" << std::endl; mState.ChannelPFR.SetRequestIdx(d); } mLogger << setloglevel(LogLevel_Event) << "================================ JUMP =========================" << std::endl; mState.P = RefOr; return 0; // P is already modified, don't modify it any further } } return 1; case 0005: // P = dd + k if (!aDoExecute) { aDisassembly << "P = " << RefOr << "+" << DecPrinter(k) << " (" << HexPrinter(k) << ")" << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { if (RefOr == 0) { mLogger << setloglevel(LogLevel_Event) << "================================ PFR REQ =========================" << std::endl; mState.ChannelPFR.SetRequestIdx(d); } mLogger << setloglevel(LogLevel_Event) << "================================ JUMP =========================" << std::endl; mState.P = RefOr + k; return 0; // P is already modified, don't modify it any further } } return 2; case 0006: // R = dd if (!aDoExecute) { aDisassembly << "R = " << RefOr << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { // TODO: do we save to the stack before raising the interrupt??? if (RefOr == 0) { mLogger << setloglevel(LogLevel_Event) << "================================ PFR REQ =========================" << std::endl; mState.ChannelPFR.SetRequestIdx(d); } mLogger << setloglevel(LogLevel_Event) << "================================ CALL =========================" << std::endl; mState.P = mState.P + 1; // mLogger.Indent(); mState.ChannelPXS.Push(mState.P); mState.P = RefOr; aBreakBurst = true; return 0; // P is already modified, don't modify it any further } } return 1; case 0007: // R = dd + k if (!aDoExecute) { aDisassembly << "R = " << RefOr << "+" << DecPrinter(k) << " (" << HexPrinter(k) << ")" << ConditionStr; } if (aDoExecute) { aDelayISet = true; if (Condition) { // TODO: do we save to the stack before raising the interrupt??? if (RefOr == 0) { mLogger << setloglevel(LogLevel_Event) << "================================ PFR REQ =========================" << std::endl; mState.ChannelPFR.SetRequestIdx(d); } mLogger << setloglevel(LogLevel_Event) << "================================ CALL =========================" << std::endl; mState.P = mState.P + 2; // mLogger.Indent(); mState.ChannelPXS.Push(mState.P); mState.P = RefOr + k; aBreakBurst = true; return 0; // P is already modified, don't modify it any further } } return 2; default: CRAY_ASSERT(false); } // switch throw Generic_x("Unreachable code"); } template IopInt_t IopCpu_c::DecodeIo( IopParcel_t aFirstParcel, IopParcel_t /*aSecondParcel*/, bool aInSimulation, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aDelayISet, bool &aBreakBurst ) { aDelayISet = false; aBreakBurst = false; uint16_t f = aFieldF; uint16_t d = (aFirstParcel & 0x01ff) >> 0; RefOr_s RefOr(d, *this); // Special-case I/O insrtuctions as they also have special fields in 'f' CRAY_ASSERT( ((f & 0xfff0) == 0140) || ((f & 0xfff0) == 0160) ); uint16_t Function = f & 0xf; IopIoFunction_t Channel; switch (f & 0xfff0) { case 0140: // channel defined in d if (!aDoExecute) { aDisassembly << "io " << ChannelPrinter(mType, d) << ", fn" << OctPrinter(Function, 2); aExplanation << IoFunctionNotePrinter(mType, d, Function); } if (aDoExecute) { Channel = d; if (mIoChannels[Channel] == nullptr) { CRAY_ASSERT(Function == 0 || Function == 6); mLogger << setloglevel(LogLevel_Warning) << SideEffectIndent << "WARNING: channel io to non-existent channel" << std::endl; } else { // stringstream Event; // Event << "IOP" << DecPrinter(GetCpuId()) << " I/O channel" << OctPrinter(Channel) << " fn" << OctPrinter(Function,2); // mMainframe->GetEventDispatcher().Fire(Event.str()); IopInt_t ReadValue = mIoChannels[Channel]->DoIo(Function, RefA); if ((f & 0x000c) == 0x0008) RefC_A = ReadValue; aDelayISet = true; } aBreakBurst = true; } return 1; case 0160: // channel defined in B if (!aDoExecute) { aDisassembly << "IOB "; if (aInSimulation) aDisassembly << ChannelPrinter(mType, RefB) << " "; aDisassembly << ", fn" << OctPrinter(Function, 2); if (aInSimulation) aExplanation << IoFunctionNotePrinter(mType, RefB, Function); if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { Channel = RefB; if (mIoChannels[Channel] == nullptr) { LogLine_c LogLine = mLogger << setloglevel((Function != 0 && Function != 6) ? LogLevel_Error : LogLevel_Warning); if (Function != 0 && Function != 6) { LogLine << "ERROR: "; } else { LogLine << SideEffectIndent << "WARNING: "; } LogLine << "channel io to non-existent channel (" << OctPrinter(Channel) << ") function: " << OctPrinter(Function) << " at address " << HexPrinter(mState.P) << std::endl; // CRAY_ASSERT(Function == 0 || Function == 6); } else { // stringstream Event; // Event << "IOP" << DecPrinter(GetCpuId()) << " I/O channel" << OctPrinter(Channel) << " fn" << OctPrinter(Function,2); // mMainframe->GetEventDispatcher().Fire(Event.str()); IopInt_t ReadValue = mIoChannels[Channel]->DoIo(Function, RefA); if ((f & 0x000c) == 0x0008) RefC_A = ReadValue; aDelayISet = true; } aBreakBurst = true; } return 1; default: CRAY_ASSERT(false); } // switch throw Generic_x("Unreachable code"); } template IopInt_t IopCpu_c::Decode( IopParcel_t aFirstParcel, IopParcel_t aSecondParcel, bool aInSimulation, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aDelayISet, bool &aBreakBurst ) { aDelayISet = false; aBreakBurst = false; uint16_t f = aFieldF; uint16_t d = (aFirstParcel & 0x01ff) >> 0; uint16_t k = aSecondParcel; RefOr_s RefOr(d, *this); // special-case branch and call instructions as they have a condition field in them as well CRAY_ASSERT( ((f & 0770) != 0070) && ((f & 0740) != 0100) ); CRAY_ASSERT( ((f & 0xfff0) != 0140) && ((f & 0xfff0) != 0160) ); switch(f) { case 0000: // PASS if (!aDoExecute) { aDisassembly << "PASS"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } return 1; case 0001: // EXIT if (!aDoExecute) { aDisassembly << "EXIT"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { mLogger << setloglevel(LogLevel_Event) << "================================ RET ==========================" << std::endl; // mLogger.UnIndent(); mState.P = mState.ChannelPXS.Pop(); aDelayISet = true; aBreakBurst = true; return 0; } return 1; case 0002: // I = 0 if (!aDoExecute) { aDisassembly << "I = 0"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { mState.I = 0; mState.ISetIsWaiting = false; } return 1; case 0003: // I = 1 if (!aDoExecute) { aDisassembly << "I = 1"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { mState.ISetIsWaiting = true; aDelayISet = true; aBreakBurst = true; } return 1; case 0004: // A = A > d if (!aDoExecute) { aDisassembly << "A = A > " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { mShiftRight(d); } return 1; case 0005: // A = A < d if (!aDoExecute) { aDisassembly << "A = A < " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { mShiftLeft(d); } return 1; case 0006: // A = A >> d if (!aDoExecute) { aDisassembly << "A = A >> " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { mRotateRight(d); } return 1; case 0007: // A = A << d if (!aDoExecute) { aDisassembly << "A = A << " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { mRotateLeft(d); } return 1; case 0010: // A = d if (!aDoExecute) { aDisassembly << "A = " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { RefC_A = d; } return 1; case 0011: // A = A & d if (!aDoExecute) { aDisassembly << "A = A & " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { RefC_A = RefA & d; } return 1; case 0012: // A = A + d if (!aDoExecute) { aDisassembly << "A = A + " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { Increment(d); } return 1; case 0013: // A = A - d if (!aDoExecute) { aDisassembly << "A = A - " << DecPrinter(d) << " (" << HexPrinter(d) << ")"; } if (aDoExecute) { Decrement(d); } return 1; case 0014: // A = k if (!aDoExecute) { aDisassembly << "A = " << DecPrinter(k) << " (" << HexPrinter(k) << ")"; } if (aDoExecute) { RefC_A = k; } return 2; case 0015: // A = A & k if (!aDoExecute) { aDisassembly << "A = A & " << DecPrinter(k) << " (" << HexPrinter(k) << ")"; } if (aDoExecute) { RefC_A = RefA & k; } return 2; case 0016: // A = A + k if (!aDoExecute) { aDisassembly << "A = A + " << DecPrinter(k) << " (" << HexPrinter(k) << ")"; } if (aDoExecute) { Increment(k); } return 2; case 0017: // A = A - k if (!aDoExecute) { aDisassembly << "A = A - " << DecPrinter(k) << " (" << HexPrinter(k) << ")"; } if (aDoExecute) { Decrement(k); } return 2; case 0020: // A = dd if (!aDoExecute) { aDisassembly << "A = " << RefOr; } if (aDoExecute) { RefC_A = RefOr; } return 1; case 0021: // A = A & dd if (!aDoExecute) { aDisassembly << "A = A & " << RefOr; } if (aDoExecute) { RefC_A = RefA & RefOr; } return 1; case 0022: // A = A + dd if (!aDoExecute) { aDisassembly << "A = A + " << RefOr; } if (aDoExecute) { Increment(RefOr); } return 1; case 0023: // A = A - dd if (!aDoExecute) { aDisassembly << "A = A - " << RefOr; } if (aDoExecute) { Decrement(RefOr); } return 1; case 0024: // dd = A if (!aDoExecute) { aDisassembly << RefOr << " = A"; } if (aDoExecute) { RefOr = RefA; } return 1; case 0025: // dd = A + dd if (!aDoExecute) { aDisassembly << RefOr << " = A + " << RefOr; } if (aDoExecute) { Increment(RefOr); RefOr = RefA; } return 1; case 0026: // dd = dd + 1 if (!aDoExecute) { aDisassembly << RefOr << " = " << RefOr << " + 1"; } if (aDoExecute) { RefA = 1; RefC = 0; Increment(RefOr); RefOr = RefA; } return 1; case 0027: // dd = dd - 1 if (!aDoExecute) { aDisassembly << RefOr << " = " << RefOr << " - 1"; } if (aDoExecute) { RefA = -1; RefC = 0; Increment(RefOr); RefOr = RefA; } return 1; case 0030: // A = (dd) if (!aDoExecute) { aDisassembly << "A = (" << RefOr << ")"; } if (aDoExecute) { RefC_A = ReadMem(RefOr); } return 1; case 0031: // A = A & (dd) if (!aDoExecute) { aDisassembly << "A = A & (" << RefOr << ")"; } if (aDoExecute) { RefC_A = RefA & ReadMem(RefOr); } return 1; case 0032: // A = A + (dd) if (!aDoExecute) { aDisassembly << "A = A + (" << RefOr << ")"; } if (aDoExecute) { Increment(ReadMem(RefOr)); } return 1; case 0033: // A = A - (dd) if (!aDoExecute) { aDisassembly << "A = A - (" << RefOr << ")"; } if (aDoExecute) { Decrement(ReadMem(RefOr)); } return 1; case 0034: // (dd) = A if (!aDoExecute) { aDisassembly << "(" << RefOr << ") = A"; } if (aDoExecute) { WriteMem(RefOr, RefA); } return 1; case 0035: // (dd) = A + (dd) if (!aDoExecute) { aDisassembly << "(" << RefOr << ") = A + (" << RefOr << ")"; } if (aDoExecute) { Increment(ReadMem(RefOr)); WriteMem(RefOr, RefA); } return 1; case 0036: // (dd) = (dd) + 1 if (!aDoExecute) { aDisassembly << "(" << RefOr << ") = (" << RefOr << ") + 1"; } if (aDoExecute) { RefA = 1; RefC = 0; Increment(ReadMem(RefOr)); WriteMem(RefOr, RefA); } return 1; case 0037: // (dd) = (dd) - 1 if (!aDoExecute) { aDisassembly << "(" << RefOr << ") = (" << RefOr << ") - 1"; } if (aDoExecute) { RefA = -1; RefC = 0; Increment(ReadMem(RefOr)); WriteMem(RefOr, RefA); } return 1; case 0040: // C = 1, iod = DN if (!aDoExecute) { aDisassembly << RefC << " = 1, io " << ChannelPrinter(mType, d) << " = DN"; } if (aDoExecute) { CRAY_ASSERT(mIoChannels[d] != nullptr); RefC = mIoChannels[d]->GetDone(); aDelayISet = true; aBreakBurst = true; } return 1; case 0041: // C = 1, iod = BZ if (!aDoExecute) { aDisassembly << RefC << " = 1, io " << ChannelPrinter(mType, d) << " = BZ"; } if (aDoExecute) { CRAY_ASSERT(mIoChannels[d] != nullptr); RefC = mIoChannels[d]->GetBusy(); aDelayISet = true; aBreakBurst = true; } return 1; case 0042: // C = 1, IOB = DN if (!aDoExecute) { aDisassembly << RefC << " = 1, IOB "; if (aInSimulation) aDisassembly << ChannelPrinter(mType, RefB) << " "; aDisassembly << "= DN"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { CRAY_ASSERT(mIoChannels[d] != nullptr); if (mIoChannels[RefB] == nullptr) { // Non-existent channels are always 'done' mLogger << setloglevel(LogLevel_Warning) << SideEffectIndent << "WARNING: channel io to non-existent channel" << std::endl; RefC = 0; } else { RefC = mIoChannels[RefB]->GetDone(); } aDelayISet = true; aBreakBurst = true; } return 1; case 0043: // C = 1, IOB = BZ if (!aDoExecute) { aDisassembly << RefC << " = 1, IOB "; if (aInSimulation) aDisassembly << ChannelPrinter(mType, RefB) << " "; aDisassembly << "= BZ"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { CRAY_ASSERT(mIoChannels[d] != nullptr); if (mIoChannels[RefB] == nullptr) { // Non-existent channels are never 'busy' mLogger << setloglevel(LogLevel_Warning) << SideEffectIndent << "WARNING: channel io to non-existent channel" << std::endl; RefC = 0; } else { RefC = mIoChannels[RefB]->GetBusy(); } aDelayISet = true; aBreakBurst = true; } return 1; case 0044: // A = A > B if (!aDoExecute) { aDisassembly << "A = A > B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { mShiftRight(RefB); } return 1; case 0045: // A = A < B if (!aDoExecute) { aDisassembly << "A = A < B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { mShiftLeft(RefB); } return 1; case 0046: // A = A >> B if (!aDoExecute) { aDisassembly << "A = A >> B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { mRotateRight(RefB); } return 1; case 0047: // A = A << B if (!aDoExecute) { aDisassembly << "A = A << B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { mRotateLeft(RefB); } return 1; case 0050: // A = B if (!aDoExecute) { aDisassembly << "A = B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefC_A = RefB; } return 1; case 0051: // A = A & B if (!aDoExecute) { aDisassembly << "A = A & B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefC_A = RefA & RefB; } return 1; case 0052: // A = A + B if (!aDoExecute) { aDisassembly << "A = A + B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { Increment(RefB); } return 1; case 0053: // A = A - B if (!aDoExecute) { aDisassembly << "A = A - B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { Decrement(RefB); } return 1; case 0054: // B = A if (!aDoExecute) { aDisassembly << "B = A"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefB = RefA; } return 1; case 0055: // B = A + B if (!aDoExecute) { aDisassembly << "B = A + B"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { Increment(RefB); RefB = RefA; } return 1; case 0056: // B = B + 1 if (!aDoExecute) { aDisassembly << "B = B + 1"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefA = 1; RefC = 0; Increment(RefB); RefB = RefA; } return 1; case 0057: // B = B - 1 if (!aDoExecute) { aDisassembly << "B = B - 1"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefA = -1; RefC = 0; Increment(RefB); RefB = RefA; } return 1; case 0060: // A = (B) if (!aDoExecute) { aDisassembly << "A = " << RefOrB; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefC_A = RefOrB; } return 1; case 0061: // A = A & (B) if (!aDoExecute) { aDisassembly << "A = A & " << RefOrB; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefC_A = RefA & RefOrB; } return 1; case 0062: // A = A + (B) if (!aDoExecute) { aDisassembly << "A = A + " << RefOrB; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { Increment(RefOrB); } return 1; case 0063: // A = A - (B) if (!aDoExecute) { aDisassembly << "A = A - " << RefOrB; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { Decrement(RefOrB); } return 1; case 0064: // (B) = A if (!aDoExecute) { aDisassembly << RefOrB << " = A"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefOrB = RefA; } return 1; case 0065: // (B) = A + (B) if (!aDoExecute) { aDisassembly << RefOrB << " = A + " << RefOrB; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { Increment(RefOrB); RefOrB = RefA; } return 1; case 0066: // (B) = (B) + 1 if (!aDoExecute) { aDisassembly << RefOrB << " = " << RefOrB << " + 1"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefA = 1; RefC = 0; Increment(RefOrB); RefOrB = RefA; } return 1; case 0067: // (B) = (B) - 1 if (!aDoExecute) { aDisassembly << RefOrB << " = " << RefOrB << " - 1"; if (d != 0) { aExplanation << "**** non-standard encoding with D:" << HexPrinter(d) << " ****"; } } if (aDoExecute) { RefA = -1; RefC = 0; Increment(RefOrB); RefOrB = RefA; } return 1; default: CRAY_ASSERT(false); } throw Generic_x("Unreachable code"); } #define DECODE(aFieldF) { &IopCpu_c::Decode, &IopCpu_c::Decode } #define DECODEJUMP(aFieldF) { &IopCpu_c::DecodeJump, &IopCpu_c::DecodeJump } #define DECODEIO(aFieldF) { &IopCpu_c::DecodeIo, &IopCpu_c::DecodeIo } const IopCpu_c::InstImplementation_s IopCpu_c::mInstImplementations[] = { DECODE(0000), DECODE(0001), DECODE(0002), DECODE(0003), DECODE(0004), DECODE(0005), DECODE(0006), DECODE(0007), DECODE(0010), DECODE(0011), DECODE(0012), DECODE(0013), DECODE(0014), DECODE(0015), DECODE(0016), DECODE(0017), DECODE(0020), DECODE(0021), DECODE(0022), DECODE(0023), DECODE(0024), DECODE(0025), DECODE(0026), DECODE(0027), DECODE(0030), DECODE(0031), DECODE(0032), DECODE(0033), DECODE(0034), DECODE(0035), DECODE(0036), DECODE(0037), DECODE(0040), DECODE(0041), DECODE(0042), DECODE(0043), DECODE(0044), DECODE(0045), DECODE(0046), DECODE(0047), DECODE(0050), DECODE(0051), DECODE(0052), DECODE(0053), DECODE(0054), DECODE(0055), DECODE(0056), DECODE(0057), DECODE(0060), DECODE(0061), DECODE(0062), DECODE(0063), DECODE(0064), DECODE(0065), DECODE(0066), DECODE(0067), DECODEJUMP(0070), DECODEJUMP(0071), DECODEJUMP(0072), DECODEJUMP(0073), DECODEJUMP(0074), DECODEJUMP(0075), DECODEJUMP(0076), DECODEJUMP(0077), DECODEJUMP(0100), DECODEJUMP(0101), DECODEJUMP(0102), DECODEJUMP(0103), DECODEJUMP(0104), DECODEJUMP(0105), DECODEJUMP(0106), DECODEJUMP(0107), DECODEJUMP(0110), DECODEJUMP(0111), DECODEJUMP(0112), DECODEJUMP(0113), DECODEJUMP(0114), DECODEJUMP(0115), DECODEJUMP(0116), DECODEJUMP(0117), DECODEJUMP(0120), DECODEJUMP(0121), DECODEJUMP(0122), DECODEJUMP(0123), DECODEJUMP(0124), DECODEJUMP(0125), DECODEJUMP(0126), DECODEJUMP(0127), DECODEJUMP(0130), DECODEJUMP(0131), DECODEJUMP(0132), DECODEJUMP(0133), DECODEJUMP(0134), DECODEJUMP(0135), DECODEJUMP(0136), DECODEJUMP(0137), DECODEIO(0140), DECODEIO(0141), DECODEIO(0142), DECODEIO(0143), DECODEIO(0144), DECODEIO(0145), DECODEIO(0146), DECODEIO(0147), DECODEIO(0150), DECODEIO(0151), DECODEIO(0152), DECODEIO(0153), DECODEIO(0154), DECODEIO(0155), DECODEIO(0156), DECODEIO(0157), DECODEIO(0160), DECODEIO(0161), DECODEIO(0162), DECODEIO(0163), DECODEIO(0164), DECODEIO(0165), DECODEIO(0166), DECODEIO(0167), DECODEIO(0170), DECODEIO(0171), DECODEIO(0172), DECODEIO(0173), DECODEIO(0174), DECODEIO(0175), DECODEIO(0176), DECODEIO(0177) }; #undef DECODE template IopInt_t IopCpu_c::Decode( IopParcel_t aFirstParcel, IopParcel_t aSecondParcel, bool aInSimulation, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aDelayISet, bool &aBreakBurst ) { uint16_t f = (aFirstParcel & 0xfe00) >> 9; CRAY_ASSERT(f < 128); InstImplementation_s InstImpl = mInstImplementations[f]; if (aDoExecute) { return (this->*InstImpl.Exec)(aFirstParcel, aSecondParcel, aInSimulation, aDisassembly, aExplanation, aDelayISet, aBreakBurst); } else { return (this->*InstImpl.Disasm)(aFirstParcel, aSecondParcel, aInSimulation, aDisassembly, aExplanation, aDelayISet, aBreakBurst); } } void IopCpu_c::EventFirePoint_c::Fire(IopCpu_c &aIop) { std::string IopType; switch (aIop.GetType()) { case IopType_MIOP: IopType = "MIOP"; case IopType_BIOP: IopType = "BIOP"; case IopType_DIOP: IopType = "DIOP"; case IopType_XIOP: IopType = "XIOP"; default: CRAY_ASSERT(false); } std::stringstream IopName; IopName << "IOP" << DecPrinter(aIop.GetCpuId()); DebugEvent_t FiredEvent = Replace(mEvent, "{iop}", IopName.str()); FiredEvent = Replace(FiredEvent, "{type}", IopType); aIop.GetMainframe().GetEventDispatcher().Fire(FiredEvent); } class Mainframe_c &IopCpu_c::GetMainframe() { return mIopCluster->GetMainframe(); }