// 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 #include #include #include "utils.h" #include "sim_iop.h" #include "cray_mainframe.h" #if defined(PARTIAL_DEBUG) && defined(_MSC_VER) #pragma optimize ("", off) #endif bool IopEPacket_c::IsValid() const { if (mPacket[0] != mPacket[mPacket.size() - 1]) { std::cout << "mPacket[0] != mPacket[mPacket.size() - 1]" << std::endl; return false; } if (GetMagic() != cMagic) { std::cout << "GetMagic() != cMagic" << std::endl; return false; } if (GetLength() != mPacket.size() - 1) { std::cout << "GetLength() != mPacket.size() - 1" << std::endl; return false; } return true; } std::vector &IopEPacket_c::Finalize() { SetMagic(cMagic); // if (mPacket.size() != 1) { SetLength(uint16_t(mPacket.size())); SetFlags(cFlagAck); mPacket.push_back(mPacket[0]); // } else { // SetLength(0); // } return mPacket; } std::unique_ptr SimIopCluster_c::CreateIToCChannel(SimIopCluster_c *aThis, const Configuration_c &aConfig) { return std::make_unique(aConfig.get_child_safe("I2C"), aConfig.get_child_safe("I2C").get("Channel"), aThis->GetMainframe(), *aThis); } std::unique_ptr SimIopCluster_c::CreateCToIChannel(SimIopCluster_c *aThis, const Configuration_c &aConfig) { return std::make_unique(aConfig.get_child_safe("C2I"), aConfig.get_child_safe("C2I").get("Channel"), aThis->GetMainframe(), *aThis); } SimIopCluster_c::SimIopCluster_c(const Configuration_c &aConfig, size_t aIopId, class Mainframe_c &aMainframe, IToCChannelCreator_t aIToCChannelCreator, CToIChannelCreator_t aCToIChannelCreator): mMainframe(&aMainframe), mLogger(aConfig,"IOP",aIopId), mIopId(aIopId), mState(States_e::Reset), mMasterCluster(aConfig.get("MasterCluster", true)), mDontTouchExchangePacket(aConfig.get("DontTouchExchangePacket", false)), mPacketsReceived(0), mPacketsSent(0) { mLogger.SetParent(aMainframe.GetLogger()); mIToCChannel = aIToCChannelCreator(this, aConfig); mCToIChannel = aCToIChannelCreator(this, aConfig); try { std::string IopRevision = aConfig.get("IopRevision", "IOSE"); if (IopRevision == "IOSD") { mIopRevision = IopRevision_e::IOSD; } else if (IopRevision == "IOSE") { mIopRevision = IopRevision_e::IOSE; } else { throw Generic_x() << "Unknown IOP revision: " << IopRevision; } for (const auto &DiskConfig : aConfig.get_child_safe("Disks")) { std::string DiskId = DiskConfig.first; std::unique_ptr Disk = std::make_unique(DiskConfig.second, DiskId, *this); mDisks.push_back(std::move(Disk)); } for (const auto &ConsoleConfig : aConfig.get_child_safe("Consoles")) { if (ConsoleConfig.first == "Default") { mDefaultConsoleConfig = ConsoleConfig.second; } else { size_t ConsoleId = FromString(ConsoleConfig.first); if (mIopRevision == IopRevision_e::IOSE) { std::unique_ptr Console = std::make_unique( ConsoleConfig.second, ConsoleId, *this, uint8_t(mConsoles.size()), aMainframe.DoDisableAutoTerminal() ); mConsoles.push_back(std::move(Console)); } else { std::unique_ptr Console = std::make_unique( ConsoleConfig.second, ConsoleId, *this, uint8_t(mConsoles.size()), aMainframe.DoDisableAutoTerminal() ); mConsoles.push_back(std::move(Console)); } } } for (const auto &EthConfig : aConfig.get_child_safe("EthInterfaces")) { std::string Name = EthConfig.first; std::unique_ptr Eth = std::make_unique(EthConfig.second, *this, Name); mEthInterfaces.push_back(std::move(Eth)); } mMainframe->SetChannel(mIToCChannel->GetChannelId() - 8, *mIToCChannel); mMainframe->SetChannel(mCToIChannel->GetChannelId() - 8, *mCToIChannel); mKernelFileName = aConfig.get_optional("KernelFileName"); mKernelPreamble = aConfig.get("KernelPreamble", 8 * 8); mParameterFileName = aConfig.get_optional("ParameterFileName"); mRamFsFileName = aConfig.get_optional("RamFsFileName"); mBootCluster = aConfig.get("BootCluster", 0); mBootChannel = aConfig.get("BootChannel", 0); mLogicalMainframeNumber = aConfig.get("LogicalMainframeNumber", 0); mOWSProtocolLevel = aConfig.get("OWSProtocolLevel", 0); mRunLevel = aConfig.get_optional("RunLevel"); if (mRunLevel.is_initialized()) { if (mRunLevel.get().length() != 1) throw Generic_x() << "RunLevel must be a single character"; } if (aConfig.get_optional("Peripherals").is_initialized() || (mIopRevision == IopRevision_e::IOSD)) { mIopPeripheral = std::make_unique(aConfig.get_child_safe("Peripherals"), *this); } } catch (...) { throw; } } void SimIopCluster_c::GetPeripheralStatus(StatusReport_c &aStatus, PeripheralType_e aFilter, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const { switch (aFilter) { case PeripheralType_e::Disk: for (auto &Disk : mDisks) { StatusReport_c Status; Disk->GetStatus(Status, aElapsedTime, aLongFormat); if (!Status.empty()) { aStatus.put_child(Disk->GetName(), Status); } } break; case PeripheralType_e::Console: for (auto &Console : mConsoles) { StatusReport_c Status; Console->GetStatus(Status, aElapsedTime, aLongFormat); if (!Status.empty()) { aStatus.put_child(Console->GetName(), Status); } } break; case PeripheralType_e::Network: for (auto &EthInterface : mEthInterfaces) { StatusReport_c Status; EthInterface->GetStatus(Status, aElapsedTime, aLongFormat); if (!Status.empty()) { aStatus.put_child(EthInterface->GetName(), Status); } } aStatus.put(aLongFormat ? "MF Packets Received" : "MFR", mPacketsReceived); aStatus.put(aLongFormat ? "MF Packets Sent" : "MFS", mPacketsSent); aStatus.put(aLongFormat ? "MF Queue Lenngth" : "QL", mIToCChannel->GetQueueLength()); break; default: break; } } void SimIopCluster_c::RegisterCommands(CommandHooks_t &aHooks) { for (auto &Disk : mDisks) { Disk->RegisterCommands(aHooks); } for (auto &Console : mConsoles) { Console->RegisterCommands(aHooks); } for (auto &Eth : mEthInterfaces) { Eth->RegisterCommands(aHooks); } } std::string SimIopCluster_c::GetName() const { std::stringstream Name; Name << "ICL" << DecPrinter(mIopId); return Name.str(); } std::string SimIopCluster_c::GetLongName() const { std::stringstream Name; Name << "IOP Cluster " << DecPrinter(mIopId); return Name.str(); } void SimIopCluster_c::MasterClear() { for (auto &Disk : mDisks) { Disk->MasterClear(); } for (auto &Console : mConsoles) { Console->Reset(); } mState = States_e::Reset; } IopEPacket_c SimIopCluster_c::GenerateResponse(IopEPacket_c &aRequest) const { IopEPacket_c Response(aRequest); Response.SetSize(0); Response.SetAckSeq(mSeqReceived); Response.SetSeq(mSeqSent); Response.SetFlags(IopEPacket_c::cFlagAck); return Response; } IopEPacket_c SimIopCluster_c::GenerateResponse() const { IopEPacket_c Response; Response.SetSize(0); Response.SetAckSeq(mSeqReceived); Response.SetSeq(mSeqSent); Response.SetFlags(IopEPacket_c::cFlagAck); // TODO: do we set this here? return Response; } void SimIopCluster_c::SendPacket(IopEPacket_c &aPacket) { // CRAY_ASSERT(!aReplace); aPacket.SetAckSeq(mSeqReceived); aPacket.SetSeq(mSeqSent); mIToCChannel->QueuePacket(aPacket.Finalize()); ++mSeqSent; } void SimIopCluster_c::SendPacket(std::vector &aPacket) { mIToCChannel->QueuePacket(aPacket); } MachineTypes_e SimIopCluster_c::GetMachineType() const { return mMainframe->GetMachineType(); } void SimIopCluster_c::HandleIosEOPacket(IopEPacket_c &aPacket) { const BitRange_s TypeRange(56, 63); const BitRange_s RunLevelRange(48, 55); const BitRange_s RequestRange(40, 47); const BitRange_s ResponseRange(32, 39); const BitRange_s ClusterRange(24, 31); const BitRange_s IopRange(16, 23); enum class RequestCodes_e { OP_BOOT = 1, // boot the specified IOP OP_DOWN = 2, // mark the specified IOP as down OP_UP = 3, // mark the specified IOP as up OP_KILL = 4, // master clear and down the specified IOP OP_OBIT = 5, // obituary notice for the specified IOP OP_ALIVE = 6, // existence notice for the specified IOP OP_CLOCK = 7, // send current clock OP_PANIC = 8, // CPU panic message OP_DUMP = 9, // dump given IOP OP_ISTOP = 10, // inform CPU of IOP stop OP_IRESTART = 11, // inform CPU of IOP restart OP_CHGLVL = 12, // Unicos run level changed notice OP_RUNLVL = 13, // change the Unicos run level OP_SYSHALT = 14, // halt the Unicos system OP_IABORT = 15, // inform CPU of IOP abort OP_VITAL = 16, // check health of UNICOS OP_FPANIC = 17, // force a panic OP_PREPANIC = 18, // CPU started panic, may flush OP_ERRLOG = 19 // make errlog entry }; const uint8_t cLogicalPath = 7; CRAY_ASSERT(aPacket.GetLogicalPath() == cLogicalPath); RequestCodes_e Request = RequestCodes_e(GetBits(aPacket.Data(0), RequestRange)); IopEPacket_c Response = GenerateResponse(aPacket); switch (Request) { case RequestCodes_e::OP_CLOCK: { Response.SetSize(8); SetBitsInPlace(Response.Data(0), TypeRange, 'o'); // Mark packet as response SetBitsInPlace(Response.Data(0), RequestRange, uint64_t(RequestCodes_e::OP_CLOCK)); time_t NowTime = time(0); struct tm *Now = localtime(&NowTime); Response.Data(1) = CInt_t(0); Response.Data(2) = CInt_t(Now->tm_mon+1); // Month Response.Data(3) = CInt_t(Now->tm_mday); // Day Response.Data(4) = CInt_t(Now->tm_year + 1900); // Year Response.Data(5) = CInt_t(Now->tm_hour); // Hour Response.Data(6) = CInt_t(Now->tm_min); // Minute Response.Data(7) = CInt_t(Now->tm_sec); // Second SendPacket(Response); } break; case RequestCodes_e::OP_PANIC: { MakeConsoles(0); mConsoles[0]->SendString("================== KERNEL PANIC ================\r\n"); size_t CharCount = (aPacket.GetLength() - 2) * 8; for (size_t i = 0; i < (CharCount + 7) / 8; ++i) { aPacket.Data(i + 2) = SwapBytes(aPacket.Data(i + 2)); } char *Str = (char*)(&aPacket.Data(2)); mConsoles[0]->SendString(Str, std::min(size_t(CharCount), strlen(Str))); mConsoles[0]->SendString("\r\n================================================\r\n"); } break; default: CRAY_ASSERT(false); } } void SimIopCluster_c::HandleIosEPPacket(IopEPacket_c &aPacket) { // Word 0 const BitRange_s TypeRange(56, 63); const BitRange_s ClusterRange(48, 55); const BitRange_s IopRange(40, 47); const BitRange_s ChannelRange(32, 39); const BitRange_s UnitRange(24, 31); const BitRange_s RequestRange(16, 23); const BitRange_s ResponseRange(8, 15); // OPEN /////////////////////////////////// // Word 1 const BitRange_s Open_HwTypeRange(32, 63); const BitRange_s Open_PacketAddrRange(0, 31); // Word 2 const BitRange_s Open_InReqQueueRange(32, 63); const BitRange_s Open_InRspQueueRange(0, 31); // Word 3 const BitRange_s Open_OutReqQueueRange(32, 63); const BitRange_s Open_OutRspQueueRange(0, 31); // CLOSE /////////////////////////////////// // Word 1 const BitRange_s Close_PacketAddrRange(0, 31); // I/O /////////////////////////////////// // Word 1 const BitRange_s IO_AalRange(60, 63); const BitRange_s IO_FlagsRange(52, 59); const BitRange_s IO_LengthMtuRange(32, 51); const BitRange_s IO_VpiVciRange(0, 31); // Word 2 const BitRange_s IO_PacketAddrRange(32, 63); const BitRange_s IO_SeqAddrRange(0, 31); enum class Flags_e { PP_TX_VPCI = 0x01, // vpi/vci is used for transmitting data PP_RX_VPCI = 0x02, // vpi/vci is used for receiving data }; enum class Request_e { PP_OPEN = 0x01, // open function PP_CLOSE = 0x02, // close function PP_INPUT = 0x03, // Input function PP_OUTPUT = 0x04, // Output function PP_ACTIVATE = 0x05, // Activate a VCI/VPI pair on the FORE card PP_DEACTIVATE = 0x06, // Deactivate a VCI/VPI pair on the FORE card PP_FSTATS = 0x07, // Dump FORE statistics to addr PP_DSTATS = 0x08, // Dump driver statistics to addr PP_TRACE = 0x09, // Dump standard trace buffer PP_ATRACE = 0x0a, // Dump auxiliary trace buffer PP_GQUEUES = 0x0b, // Get a copy of all the IOS queue structures PP_GOC3CONF = 0x0c, // Get OC3 configuration from SUNI chip PP_SOC3CONF = 0x0d, // Set OC3 configuration on SUNI chip PP_DEBUG = 0x20, // Toggle IOS debug mode (prints traces, etc) PP_CLRTRACE = 0x21 // Clear the IOS trace and aux trace }; enum class Response_e { PPST_OK = 0x00, // ok status PPST_HDW = 0x01, // hardware error PPST_PROER = 0x02, // protocol error PPST_ILCHN = 0x03, // illegal channel PPST_ILFNC = 0x04, // illegal function PPST_RTO = 0x05, // read timeout PPST_WTO = 0x06, // write timeout PPST_ILDRV = 0x07, // illegal driver PPST_INVAL = 0x08, // invalid argument (010) PPST_FAILED = 0x09, // request failed (011) PPST_TIMER = 0x0a, // Funcion timeout (012) (0x0a) PPST_OVRFLW = 0x0b, // Queue overflow error (013) (0x0b) PPST_CANCEL = 0x0c, // I/O request cancelled (014) (0x0c) PPST_BUSY = 0x0d, // Packet request already in progress (busy) PPST_OPENOK = 0xf0 // Open completed succesfully }; Request_e Request = Request_e(GetBits(aPacket.Data(0), RequestRange)); switch (Request) { case Request_e::PP_OPEN: { IopEPacket_c Response = GenerateResponse(aPacket); Response.SetSize(4); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength()-1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } mLogger << setloglevel(LogLevel_IoActivity) << "ATM open" << std::endl; //DumpPacket(mLogger, (CAddr_t(GetBits(aPacket.Data(2), IO_PacketAddrRange))), *mMainframe, "packet"); SetBitsInPlace(Response.Data(0), TypeRange, 'p'); // Mark packet as response SetBitsInPlace(Response.Data(0), ResponseRange, uint64_t(Response_e::PPST_OPENOK)); SendPacket(Response); } break; case Request_e::PP_INPUT: { IopEPacket_c Response = GenerateResponse(aPacket); Response.SetSize(4); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength()-1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } mLogger << setloglevel(LogLevel_IoActivity) << "ATM input " << "Length: " << DecPrinter((GetBits(aPacket.Data(1), IO_LengthMtuRange))) << " " << "Vpi/Vci: " << HexPrinter((CAddr_t(GetBits(aPacket.Data(1), IO_VpiVciRange)))) << " " << "Seq: " << HexPrinter((CAddr_t(GetBits(aPacket.Data(2), IO_SeqAddrRange)))) << " " << std::endl; //DumpPacket(mLogger, (CAddr_t(GetBits(aPacket.Data(1), Open_PacketAddrRange))), *mMainframe, "packet"); SetBitsInPlace(Response.Data(0), TypeRange, 'p'); // Mark packet as response SetBitsInPlace(Response.Data(0), ResponseRange, uint64_t(Response_e::PPST_OK)); SendPacket(Response); } break; case Request_e::PP_OUTPUT: { IopEPacket_c Response = GenerateResponse(aPacket); Response.SetSize(4); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength()-1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } mLogger << setloglevel(LogLevel_IoActivity) << "ATM output " << "Length: " << DecPrinter((GetBits(aPacket.Data(1), IO_LengthMtuRange))) << " " << "Vpi/Vci: " << HexPrinter((CAddr_t(GetBits(aPacket.Data(1), IO_VpiVciRange)))) << " " << "Seq: " << HexPrinter((CAddr_t(GetBits(aPacket.Data(2), IO_SeqAddrRange)))) << " " << std::endl; //DumpPacket(mLogger, (CAddr_t(GetBits(aPacket.Data(1), Open_PacketAddrRange))), *mMainframe, "packet"); SetBitsInPlace(Response.Data(0), TypeRange, 'p'); // Mark packet as response SetBitsInPlace(Response.Data(0), ResponseRange, uint64_t(Response_e::PPST_OK)); SendPacket(Response); } break; case Request_e::PP_CLOSE: { IopEPacket_c Response = GenerateResponse(aPacket); Response.SetSize(4); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength()-1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } mLogger << setloglevel(LogLevel_IoActivity) << "ATM close" << std::endl; //DumpPacket(mLogger, (CAddr_t(GetBits(aPacket.Data(2), IO_PacketAddrRange))), *mMainframe, "packet"); SetBitsInPlace(Response.Data(0), TypeRange, 'p'); // Mark packet as response SetBitsInPlace(Response.Data(0), ResponseRange, uint64_t(Response_e::PPST_OK)); SendPacket(Response); } break; default: CRAY_ASSERT(false); break; } } void SimIopCluster_c::HandleIosEDPacket(IopEPacket_c &aPacket) { // Word -1 // EIOP number is stuffed into 'process' GetProcess // Word 0 const BitRange_s TypeRange(56, 63); const BitRange_s RequestCodeRange(40, 47); const BitRange_s ResponseCodeRange(32, 39); const BitRange_s DeviceTypeRange(25, 31); const BitRange_s UnitRange(21, 24); const BitRange_s ChannelRange(16, 20); const BitRange_s RawFunctionParameterRange(0, 15); // Word 1 const BitRange_s IndexRange(32, 63); const BitRange_s CurrentBpRange(0, 31); // Word 2 const BitRange_s CylinderRange(32, 63); const BitRange_s HeadRange(31, 31); const BitRange_s SectorRange(30, 30); const BitRange_s SectorCntRange(0, 15); // Word 3 const BitRange_s ErrorRecoveryInProgressRange(59, 59); const BitRange_s NextValidPacketRange(58, 58); const BitRange_s EnableSpiralRange(57, 57); const BitRange_s DisableZeroLatencyRange(56, 56); const BitRange_s LogicalSectorSizeRange(32, 47); const BitRange_s ChannelBufferDesciptorRange(16, 31); const BitRange_s AddressIncrementRange(0, 15); // Word 4 const BitRange_s TargetMemoryTypeRange(48, 50); const BitRange_s TargetMemoryAddrRange(0, 47); // Word 5 const BitRange_s ChanneBufferOffsetRange(32, 47); const BitRange_s StreamMasksRange(0, 15); // Response only fields // Word 6 const BitRange_s GeneralStatusRange(48, 63); const BitRange_s M1StatusRange(32, 47); const BitRange_s DriveStatusRange(16, 31); const BitRange_s ControllerStatus(0, 15); // Word 7 const BitRange_s CylinderInErrorRange(32, 63); const BitRange_s HeadInErrorRange(31, 31); const BitRange_s SectorInErrorRange(30, 30); const BitRange_s SiralOffsetRange(0, 15); // Word 8...24 const BitRange_s WriteBehindCylinderRange(48, 63); const BitRange_s WriteBehindHeadRange(32, 47); const BitRange_s WriteBehindSectorRange(16, 31); const BitRange_s WriteBehindSegmentNumberRange(9, 15); const BitRange_s WriteBehindRecoveredFlagRange(8, 8); const BitRange_s WriteBehindSectorsInErrorRange(0, 7); // 25..70 // There is more status here up to 70 enum class RequestCodes_e { // Note: there's quite a bit of repetition here in the list. From what I can tell, this is mostly about more reable names, but same meaning. DRQ_ECHO = 001, // echo DRQ_READ = 002, // read data DRQ_WRITE = 003, // write data DRQ_WRITEB = 004, // write behind DRQ_RID = 033, // read ID DRQ_RDAECC = 041, // read data and ecc - dd6x DRQ_READ_TARGET = 042, DRQ_WDAECCTP = 046, // write data, ecc, toggle parity - dd6x DRQ_WDAECC = 047, // write data and ecc - dd6x DRQ_WID = 052, // write ID DRQ_WDID = 053, // write defective ID DRQ_WZECC = 055, // write with zero ecc DRQ_WRITE_BEHIND = 004, DRQ_CONFIGURE_UP = 011, DRQ_CONFIGURE_DOWN = 012, DRQ_RETURN_STATS = 021, DRQ_READ_SECTOR = 030, DRQ_READ_SECTOR_FROM_BUFFER = 031, DRQ_READ_SECTOR_NO_HW_RA = 032, DRQ_READ_ID = 033, DRQ_READ_ABSOLUTE = 034, DRQ_READ_BUFFER = 035, DRQ_READ_ECC = 036, DRQ_READ_VECTORS = 037, DRQ_READ_TRACK_HEADER = 040, DRQ_WRITE_DATA = 050, DRQ_WRITE_THRU = 051, DRQ_WRITE_ID = 052, DRQ_WRITE_DEFECTIVE_ID = 053, DRQ_WRITE_BUFFER = 054, DRQ_WRITE_DATA_ZERO_ECC = 055, DRQ_WRITE_TRACK_HEADER = 056, DRQ_DIAGNOSTIC = 060, DRQ_RESET = 061, DRQ_CLEAR_FAULTS = 062, DRQ_RTZ = 063, DRQ_SELECT = 064, DRQ_DESELECT = 065, DRQ_DESELECT_OPP_SELECT = 066, DRQ_SEEK = 067, DRQ_SELECT_OFFSET = 070, DRQ_SELECT_STROBE = 071, DRQ_SELECT_HEAD = 072, DRQ_WRITE_STREAMS = 076, DRQ_LOAD_FORMAT = 077, DRQ_RETURN_GENERAL_STATUS = 0174, DRQ_RETURN_SELECT_STATUS = 0175, DRQ_ACCUMULATE_STATUS = 0176, DRQ_RETURN_ACCUMULATED_STATUS = 0177 }; enum class ResponseCodes_e { DRS_OK = 0000, // ok DRS_ERR_MIN = 0010, DRS_ERR = 0010, // error DRS_DERR = 0011, // data error DRS_ERR_MAX = 0077, DRS_RERR = 0301, // request error DRS_PERR = 0303, // parameter error DRS_NVPERR = 0322, // next valid packet error DRS_RECOVERED = 0001, DRS_CORRECTED = 0002, DRS_SINGLE_BIT = 0003, DRS_IO_WAIT = 0004, DRS_FIRST_FATAL_ERROR_CODE = 0010, DRS_IO_ERROR = 0010, DRS_TRANSFER_ERROR = 0011, DRS_POS_ERROR = 0012, DRS_HEAD_ERROR = 0013, DRS_SELECT_ERROR = 0014, DRS_DESELECT_ERROR = 0015, DRS_RESERVE_ERROR = 0016, DRS_RELEASE_ERROR = 0017, DRS_DOUBLE_BIT = 0020, DRS_STATUS_ERROR = 0021, DRS_TRANSFER_PARAM_ERROR = 0022, DRS_TIMEOUT = 0023, DRS_CHANNEL_ERROR = 0024, DRS_NOT_READY = 0025, DRS_LOAD_POS_ERROR = 0026, DRS_RCP_ERROR = 0027, DRS_RESET_ERROR = 0030, DRS_STROBE_ERROR = 0031, DRS_DIAGNOSTIC_ERROR = 0032, DRS_CLEAR_FAULTS_ERROR = 0033, DRS_OFFSET_ERROR = 0034, DRS_ECHO_ERROR = 0035, DRS_IO_TIMEOUT = 0040, DRS_POS_TIMEOUT = 0041, DRS_HEAD_TIMEOUT = 0042, DRS_SELECT_TIMEOUT = 0043, DRS_DESELECT_TIMEOUT = 0044, DRS_RESERVE_TIMEOUT = 0045, DRS_RELEASE_TIMEOUT = 0046, DRS_STATUS_TIMEOUT = 0047, DRS_LOADPOS_TIMEOUT = 0050, DRS_RCP_TIMEOUT = 0051, DRS_RESET_TIMEOUT = 0052, DRS_STROBE_TIMEOUT = 0053, DRS_DIAG_TIMEOUT = 0054, DRS_CLRFLTS_TIMEOUT = 0055, DRS_OFFSET_TIMEOUT = 0056, DRS_ECHO_TIMEOUT = 0057, DRS_BAD_OPTION = 0076, DRS_OTHER_FATAL_ERROR = 0077, DRS_LAST_FATAL_ERROR_CODE = 0077, DRS_NO_LOCAL_MEMORY = 0100, DRS_NO_CACHE_MEMORY = 0101, DRS_SEGMENT_MEMORY = 0102, DRS_NO_STATISTICS = 0200, DRS_INVALID_REQUEST_CODE = 0301, DRS_UNKNOWN_PACKET_TYPE = 0302, DRS_INVALID_PARAMETER = 0303, DRS_NO_DRIVER = 0320, DRS_ALREADY_CONFIGURED = 0321, DRS_NVP_SEQUENCE_ERROR = 0322, DRS_UNSUPPORTED = 0323, DRS_DEVICE_NOT_CONFIGURED = 0324, DRS_CONFIGURATION_FAILURE = 0325, DRS_UCODE_CHKSUM_FAILURE = 0326, DRS_INCOMPAT_UNICOS = 0327, DRS_NOT_EXECUTED = 0377 }; enum class MemoryTypes_e { DTM_CM = 0, // central memory DTM_SSD = 2, // SSD DTM_T3D = 4 // T3D }; uint8_t Channel = uint8_t(GetBits(aPacket.Data(0), ChannelRange)); uint8_t Unit = uint8_t(GetBits(aPacket.Data(0), UnitRange)); RequestCodes_e RequestCode = RequestCodes_e(GetBits(aPacket.Data(0), RequestCodeRange)); size_t Cylinder = size_t(GetBits(aPacket.Data(2), CylinderRange)); size_t Head = size_t(GetBits(aPacket.Data(2), HeadRange)); size_t Sector = size_t(GetBits(aPacket.Data(2), SectorRange)); size_t SectorCnt = size_t(GetBits(aPacket.Data(2), SectorCntRange)); MemoryTypes_e TargetMemoryType = MemoryTypes_e(GetBits(aPacket.Data(4), TargetMemoryTypeRange)); uint64_t TargetMemoryAddr = GetBits(aPacket.Data(4), TargetMemoryAddrRange); uint8_t IopNumber = aPacket.GetProcess(); switch (RequestCode) { case RequestCodes_e::DRQ_READ: { bool Found = false; for (auto &Disk : mDisks) { if (Disk->GetPhysicalDeviceId() == Channel && Disk->GetIopNumber() == IopNumber && Disk->GetUnit() == Unit) { Found = true; CRAY_ASSERT(Head == 0); CRAY_ASSERT(Sector == 0); CRAY_ASSERT(TargetMemoryType == MemoryTypes_e::DTM_CM); Disk->Read(Cylinder, uint32_t(SectorCnt), CAddr_t(TargetMemoryAddr)); IopEPacket_c Response = GenerateResponse(aPacket); Response.SetSize(68); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength()-1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'd'); // Mark packet as response SetBitsInPlace(Response.Data(0), RequestCodeRange, uint64_t(RequestCodes_e::DRQ_READ)); SetBitsInPlace(Response.Data(0), ResponseCodeRange, uint64_t(ResponseCodes_e::DRS_OK)); SendPacket(Response); } } if (!Found) { CRAY_ASSERT(false); } } break; case RequestCodes_e::DRQ_WRITE: case RequestCodes_e::DRQ_WRITE_BEHIND: { bool Found = false; for (auto &Disk : mDisks) { if (Disk->GetPhysicalDeviceId() == Channel) { Found = true; CRAY_ASSERT(Head == 0); CRAY_ASSERT(Sector == 0); CRAY_ASSERT(TargetMemoryType == MemoryTypes_e::DTM_CM); Disk->Write(Cylinder, uint32_t(SectorCnt), CAddr_t(TargetMemoryAddr)); IopEPacket_c Response = GenerateResponse(aPacket); Response.SetSize(68); for (size_t Idx = 0; Idx < aPacket.GetLength(); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'd'); // Mark packet as response SetBitsInPlace(Response.Data(0), RequestCodeRange, uint64_t(RequestCodes_e::DRQ_READ)); SetBitsInPlace(Response.Data(0), ResponseCodeRange, uint64_t(ResponseCodes_e::DRS_OK)); SendPacket(Response); } } if (!Found) { CRAY_ASSERT(false); } } break; case RequestCodes_e::DRQ_CONFIGURE_DOWN: case RequestCodes_e::DRQ_CONFIGURE_UP: case RequestCodes_e::DRQ_RETURN_ACCUMULATED_STATUS: case RequestCodes_e::DRQ_RETURN_GENERAL_STATUS: case RequestCodes_e::DRQ_DIAGNOSTIC: case RequestCodes_e::DRQ_RESET: case RequestCodes_e::DRQ_DESELECT: case RequestCodes_e::DRQ_ECHO: { IopEPacket_c Response = GenerateResponse(aPacket); Response.SetSize(68); for (size_t Idx = 0; Idx < aPacket.GetLength(); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'd'); // Mark packet as response SetBitsInPlace(Response.Data(0), RequestCodeRange, uint64_t(RequestCode)); SetBitsInPlace(Response.Data(0), ResponseCodeRange, uint64_t(ResponseCodes_e::DRS_OK)); SendPacket(Response); } break; default: CRAY_ASSERT(false); break; } } void SimIopCluster_c::HandleAPacket(std::vector &aPacket) { enum class FunctionCodes_e { Read = 1, Write = 2, WriteBehind = 12, SelectDrive = 040, ReleaseDrive = 041, ReleaseOpposite = 042 }; enum class StatusCodes_e { OK = 0, RecoveredDataError = 1, CorrectedDataError = 11, UnrecoveredDataError = 12, UnrecoveredHardwareError = 13, BadParameterInRequest = 16, NoBackdoorConfigured = 17 }; uint8_t Diag = uint8_t(GetBitsReverse(aPacket[1], 16, 16)); uint16_t DiagRequest = uint16_t(GetBitsReverse(aPacket[1], 17, 21)); // The second word would also contain more info for diagnostics (see apacket.h) but we don't support that for now... uint8_t StripeFactor = uint8_t(GetBitsReverse(aPacket[2], 0, 3)); uint8_t UpperCylinder = uint8_t(GetBitsReverse(aPacket[2], 31, 31)); uint8_t SequenceNumber = uint8_t(GetBitsReverse(aPacket[2], 40, 47)); uint16_t MinorDev = uint16_t(GetBitsReverse(aPacket[2], 48, 63)); uint32_t TargetMem = uint32_t(GetBitsReverse(aPacket[3], 0, 1)); uint32_t DataAddr = uint32_t(GetBitsReverse(aPacket[3], 2, 31)); FunctionCodes_e FunctionCode = FunctionCodes_e(GetBitsReverse(aPacket[3], 32, 39)); StatusCodes_e ReturnStatus = StatusCodes_e(GetBitsReverse(aPacket[3], 40, 47)); DeviceTypes_e DeviceType = DeviceTypes_e(GetBitsReverse(aPacket[3], 48, 52)); uint8_t IopNumber = uint8_t(GetBitsReverse(aPacket[3], 53, 54)); uint8_t UnitNumber = uint8_t(GetBitsReverse(aPacket[3], 55, 56)); uint8_t PhysicalChannel = uint8_t(GetBitsReverse(aPacket[3], 57, 63)); uint32_t Cylinder; uint32_t Head; uint32_t Sector; // Device address for HDDs if (GetMachineType() == MachineTypes_e::YEL || GetMachineType() == MachineTypes_e::YMP) { Cylinder = uint32_t(GetBitsReverse(aPacket[4], 2, 31)); Head = uint32_t(GetBitsReverse(aPacket[4], 0, 0)); Sector = uint32_t(GetBitsReverse(aPacket[4], 1, 1)); } else { Cylinder = uint32_t(GetBitsReverse(aPacket[4], 0, 10)) | (UpperCylinder << 11); Head = uint32_t(GetBitsReverse(aPacket[4], 11, 15)); Sector = uint32_t(GetBitsReverse(aPacket[4], 16, 22)); } // Device address for RAM disks uint16_t RamAddr = uint16_t(GetBitsReverse(aPacket[4], 0, 31)); uint32_t WordCount = uint32_t(GetBitsReverse(aPacket[4], 32, 63)); uint16_t ReadAhead = uint16_t(GetBitsReverse(aPacket[5], 32, 47)); CRAY_ASSERT(Diag == 0); std::stringstream EventStr; EventStr << "C->I PACKET A request -" << " StripeFactor: " << HexPrinter(StripeFactor) << " SeqNo: " << HexPrinter(SequenceNumber) << " MinorDev: " << HexPrinter(MinorDev) << " TargetMem: " << HexPrinter(TargetMem) << " DataAddr: " << HexPrinter(DataAddr) << " FunctionCode: " << HexPrinter(uint8_t(FunctionCode)) << " RetStatus: " << HexPrinter(uint8_t(ReturnStatus)) << " DeviceType: " << DecPrinter(uint8_t(DeviceType)) << " Iop: " << OctPrinter(IopNumber) << " Unit: " << DecPrinter(UnitNumber) << " PhysicalChannel: " << OctPrinter(PhysicalChannel) << " CHS: " << DecPrinter(Cylinder) << "-" << DecPrinter(Head) << "-" << DecPrinter(Sector) << " WordCount: " << HexPrinter(WordCount) << " ReadAhead: " << DecPrinter(ReadAhead) << std::endl; mLogger << setloglevel(LogLevel_EventFire) << EventStr.str(); GetMainframe().GetEventDispatcher().Fire(EventStr.str()); // CRAY_ASSERT(StripeFactor == 0); CRAY_ASSERT(TargetMem == 0); CRAY_ASSERT(FunctionCode == FunctionCodes_e::Read || FunctionCode == FunctionCodes_e::Write || FunctionCode == FunctionCodes_e::WriteBehind); // CRAY_ASSERT(DeviceType == DeviceTypes_e::DD29); // Look up the drive bool Found = false; for (auto &Disk : mDisks) { if (Disk->GetPhysicalDeviceId() == PhysicalChannel && Disk->GetIopNumber() == IopNumber && Disk->GetUnit() == UnitNumber) { Found = true; switch(FunctionCode) { case FunctionCodes_e::Read: Disk->Read(Cylinder, Head, Sector, WordCount * sizeof(CInt_t) / Disk->GetSectorSize(), CAddr_t(DataAddr)); break; case FunctionCodes_e::Write: case FunctionCodes_e::WriteBehind: Disk->Write(Cylinder, Head, Sector, WordCount * sizeof(CInt_t) / Disk->GetSectorSize(), CAddr_t(DataAddr)); break; default: CRAY_ASSERT(false); } break; } } if (!Found) throw Generic_x() << "Can't find drive for physical channel: " << OctPrinter(PhysicalChannel) << " iop: " << OctPrinter(IopNumber) << " and unit: " << DecPrinter(UnitNumber); // Compose a reply ReversePacket(aPacket); aPacket[3] = SetBitsReverse(aPacket[3], 40, 47, uint64_t(StatusCodes_e::OK)); mIToCChannel->QueuePacket(aPacket); } void SimIopCluster_c::HandleKPacket(std::vector &aPacket) { // Kernel crash: wait for the next packet, print it, and exit mState = States_e::KernelPanic; } void SimIopCluster_c::Tick() { for (auto &Console : mConsoles) Console->Tick(); for (auto &EthInterfaces : mEthInterfaces) EthInterfaces->Tick(); switch (mState) { case States_e::Reset: /* Boot config: * * On Model-E boot, boot info is in registers. * $ELSE owslink,0 A5 Boot cluster number owschan,0 A6 Boot cluster channel number rfsleng,0 S1 Length of root file system scfleng,0 S2 Length of spare chip configuration file sysmem,0 S4 LWA+1 of UNICOS binary csim,0 S6 CSIM flag from deadstart end,0 S7 length of binary + spare chip + par file S3 D'8 S1 S1&S3 owsplvl,0 S1 OWS protocol level S1 A7 S1 S1>D'16 S1 S1&S3 S1 S1Reset(); if (mKernelFileName.is_initialized()) { CAddr_t KernelStart = CAddr_t(0); mMainframe->LoadImageFile(mKernelFileName.get().c_str(), KernelStart, mKernelPreamble); uint64_t KernelSize = boost::filesystem::file_size(mKernelFileName.get()); CAddr_t DataEnd = KernelStart + CAddr_t((KernelSize + sizeof(CInt_t) - 1) / sizeof(CInt_t)); if (mParameterFileName.is_initialized()) { CAddr_t ParamStart = DataEnd; mMainframe->LoadImageFile(mParameterFileName.get().c_str(), ParamStart); uint64_t ParamSize = boost::filesystem::file_size(mParameterFileName.get()); CAddr_t ParamEnd = ParamStart + CAddr_t((ParamSize + sizeof(CInt_t) - 1) / sizeof(CInt_t)); if (!mDontTouchExchangePacket) { mMainframe->MemWrite(CAddr_t(0x00000c), SwapBytes(CInt_t(ParamStart))); // Start address of PARAM file patched into S4 on boot mMainframe->MemWrite(CAddr_t(0x00000f), SwapBytes(CInt_t(ParamEnd))); // End address of PARAM file patched into S7 on boot } DataEnd = ParamEnd; if (mRamFsFileName.is_initialized()) { CAddr_t RamFsStart = DataEnd; mMainframe->LoadImageFile(mRamFsFileName.get().c_str(), RamFsStart); uint64_t RamFsSize = boost::filesystem::file_size(mRamFsFileName.get()); RamFsSize = CAddr_t((RamFsSize + sizeof(CInt_t) - 1) / sizeof(CInt_t)); CAddr_t RamFsEnd = CAddr_t(RamFsStart + RamFsSize); if (!mDontTouchExchangePacket) { mMainframe->MemWrite(CAddr_t(0x000009), SwapBytes(CInt_t(RamFsSize))); // End address of RAM FS file patched into S1 on boot } DataEnd = RamFsEnd; } } if (!mDontTouchExchangePacket) { mMainframe->MemWriteNoWatchpointByType(CAddr_t(0x000005) * 2 + 1, SwapBytes(CAddr_t(mBootCluster))); // Boot cluster in A5 mMainframe->MemWriteNoWatchpointByType(CAddr_t(0x000006) * 2 + 1, SwapBytes(CAddr_t(mBootChannel))); // Boot channel in A6 } uint8_t RunLevel = 0; if (mRunLevel.is_initialized()) { RunLevel = mRunLevel.get()[0]; } if (!mDontTouchExchangePacket) { CAddr_t A7 = (RunLevel << 16) | (mOWSProtocolLevel << 8) | (mLogicalMainframeNumber); // RunLevel needs to be specified as a 'char' not as an 'int' mMainframe->MemWriteNoWatchpointByType(CAddr_t(0x000007) * 2 + 1, SwapBytes(A7)); // RunLevel and stuff in A7 } } mMainframe->CpuMasterClear(true); mMainframe->CpuMasterClear(false); } if (GetIopRevision() == IopRevision_e::IOSD) { time_t NowTime = time(0); struct tm *Now = localtime(&NowTime); std::vector Packet(6); Packet[0] = CInt_t(Now->tm_mon + 1); // Month Packet[1] = CInt_t(Now->tm_mday); // Day Packet[2] = 1999; // CInt_t(Now->tm_year + 1900); // Year Packet[3] = CInt_t(Now->tm_hour); // Hour Packet[4] = CInt_t(Now->tm_min); // Minute Packet[5] = CInt_t(Now->tm_sec); // Second (upper 32 bits is TZ offset) // TZ offset indeed is in the upper 32 bits, but // 1. UNICOS doesn't actually read it // 2. Windows doesn't seem to have a tm_gmtoff field //Packet[5] = (CInt_t(Now->tm_gmtoff) << 32) | (CInt_t(Now->tm_sec)); // Second (upper 32 bits is TZ offset) mIToCChannel->QueuePacket(Packet); if (mMasterCluster) { mState = States_e::WaitTimeSent; } else { mState = States_e::WaitTimeSent; } } else { mState = States_e::RunningJ90; } break; case States_e::WaitTimeSent: if (mIToCChannel->ReadyToSend()) { mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "sending in States_e::WaitTimeSent" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; std::vector Packet(6); Packet[0] = 0x4331004900000000; // - C1.I.... Packet[1] = 0x0000000000000000; // - ........ Packet[2] = 0x0000000000000000; // - ........ Packet[3] = 0x0000000000000000; // - ........ Packet[4] = 0x0000000000000000; // - ........ Packet[5] = 0x0000000000000000; // - ........ mIToCChannel->QueuePacket(Packet); mState = States_e::WaitISent; } break; case States_e::WaitISent: if (mCToIChannel->HasPacket()) { mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "receiving in States_e::WaitISent" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "###################################################################################" << std::endl; std::vector Packet = mCToIChannel->GetPacket(); CRAY_ASSERT(Packet.size() == 6); CRAY_ASSERT(Packet[0] == 0x0049433100000000); // - .IC1.... CRAY_ASSERT(Packet[1] == 0x0000000000000000); // - ........ CRAY_ASSERT(Packet[2] == 0x0000000000000000); // - ........ CRAY_ASSERT(Packet[3] == 0x0000000000000000); // - ........ CRAY_ASSERT(Packet[4] == 0x0000000000000000); // - ........ CRAY_ASSERT(Packet[5] == 0x0000000000000000); // - ........ Packet[0] = 0x4331004AFFFFFFFF; // - C1.J.... Packet[1] = 0xFFFFFFFFFFFFFFFF; // - ........ Packet[2] = 0xFFFFFFFFFFFFFFFF; // - ........ Packet[3] = 0xFFFFFFFFFFFFFFFF; // - ........ Packet[4] = 0xFFFFFFFFFFFFFFFF; // - ........ Packet[5] = 0xFFFFFFFFFFFFFFFF; // - ........ mIToCChannel->QueuePacket(Packet); mState = States_e::WaitJSent; } break; case States_e::WaitJSent: if (mCToIChannel->HasPacket()) { std::vector Packet = mCToIChannel->GetPacket(); CRAY_ASSERT(Packet.size() == 6); CRAY_ASSERT(Packet[0] == 0x004A4331FFFFFFFF); // - .JC1.... CRAY_ASSERT(Packet[1] == 0xFFFFFFFFFFFFFFFF); // - ........ CRAY_ASSERT(Packet[2] == 0xFFFFFFFFFFFFFFFF); // - ........ CRAY_ASSERT(Packet[3] == 0xFFFFFFFFFFFFFFFF); // - ........ CRAY_ASSERT(Packet[4] == 0xFFFFFFFFFFFFFFFF); // - ........ CRAY_ASSERT(Packet[5] == 0xFFFFFFFFFFFFFFFF); // - ........ // Send an error-report (C) packet. Packet[0] = 0x4331004300000004; // - C1.C.... Packet[1] = 0x0000000000000000; // - ........ Packet[2] = 0x0000000000000000; // - ........ Packet[3] = 0x0000000000000000; // - ........ Packet[4] = 0x0000000000000000; // - ........ Packet[5] = 0x0000000000000000; // - ........ mIToCChannel->QueuePacket(Packet); mState = States_e::RunningYEL; } break; case States_e::RunningYEL: if (mCToIChannel->HasPacket()) { // TODO: do incoming packet processing std::vector Packet = mCToIChannel->GetPacket(); CRAY_ASSERT(Packet.size() == 6); char PacketType = char(GetBitsReverse(Packet[0], 8, 15)); switch (PacketType) { case 'T': // terminal packet HandleTPacket(Packet); break; case 'A': HandleAPacket(Packet); break; case 'K': HandleKPacket(Packet); break; case 'M': { // Ethernet packet bool Found = false; for (auto &EthInterface : mEthInterfaces) { if (EthInterface->HandleIosDPacket(Packet)) { Found = true; break; } } if (!Found && !mEthInterfaces.empty()) mEthInterfaces.front()->SendErrorResponse(Packet, SimIopEth_n::Status_e::MPST_ILCHN); break; } case 'F': { // IOP local peripheral packet mIopPeripheral->HandleIosDPacket(Packet); break; } default: CRAY_ASSERT(false); break; } } break; case States_e::RunningJ90: if (mCToIChannel->HasPacket()) { // We have to break the buffer up to multiple messages... std::vector RawPacket = mCToIChannel->GetPacket(); std::vector::const_iterator PacketBegin = RawPacket.begin(); std::vector::const_iterator PacketEnd = std::find(PacketBegin + 1, RawPacket.cend(), *PacketBegin); while (PacketEnd != RawPacket.cend()) { IopEPacket_c Packet(PacketBegin,PacketEnd+1); CRAY_ASSERT(Packet.IsValid()); mSeqReceived = Packet.GetSeq(); mPacketsReceived++; if (Packet.GetFlags() & IopEPacket_c::cFlagIni) mSeqSent = 1; if (Packet.GetLength() > 1) { char PacketType = char(GetBits(Packet.Data(0), 56, 63)); switch (PacketType) { case 'O': // OWS packet HandleIosEOPacket(Packet); break; case 'Z': // Terminal packet HandleIosEZPacket(Packet); break; case 'D': // Disk packet HandleIosEDPacket(Packet); break; case 'P': // ATM packet HandleIosEPPacket(Packet); break; case 'M': { // Ethernet packet bool Found = false; for (auto &EthInterface : mEthInterfaces) { if (EthInterface->HandleIosEPacket(Packet)) { Found = true; break; } } if (!Found && !mEthInterfaces.empty()) mEthInterfaces.front()->SendErrorResponse(Packet, SimIopEth_n::Status_e::MPST_ILCHN); break; } case 'F': { // Expander packet (????) It seems that it is an IOS-D-style F packet embedded in an IOS-E packet. However the IOS-E style 'f' packet is FTDI. For now, going with an F packet if (mIopPeripheral == nullptr) throw Generic_x() << "Can't handle shell driver (F) packet without Peripheral section in IopCluster configuration"; mIopPeripheral->HandleIosEPacket(Packet); break; } default: CRAY_ASSERT(false); break; } } PacketBegin = PacketEnd + 1; if (PacketBegin == RawPacket.cend()) break; PacketEnd = std::find(PacketBegin + 1, RawPacket.cend(), *PacketBegin); } } break; case States_e::KernelPanic: if (mCToIChannel->HasPacket()) { if (mConsoles.size() > 0) { SimIopConsole_c &Console = *mConsoles[0]; std::vector Packet = mCToIChannel->GetPacket(); size_t ByteCnt = Packet.size() * sizeof(CInt_t); // Simply dump all incoming data to the first console... Console.SendString("\r\n"); bool NewLinePrinted = false; for (size_t i = 0; i < ByteCnt; ++i) { char Char = ((char*)(&Packet[0]))[(i / 8 * 8) + (7 - (i % 8))]; switch (Char) { case 0: if (!NewLinePrinted) { Console.SendString("\r\n"); NewLinePrinted = true; } break; case 0x0a: case 0x0d: Console.SendString("\r\n"); break; default: Console.SendChar(Char); NewLinePrinted = false; break; } } } } break; default: CRAY_ASSERT(false); break; } } // SimIopCluster_c::ChannelIToC_c ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SimIopCluster_c::ChannelIToC_c::ChannelIToC_c(const Configuration_c &aConfig, size_t aChannelId, Mainframe_c &aMainframe, SimIopCluster_c &aParent): Channel_i(aChannelId, aMainframe), mLogger(aConfig, "I->C_", aChannelId), mParent(aParent), mPacketValid(false) { mLogger.SetParent(aParent.GetLogger()); } void SimIopCluster_c::ChannelIToC_c::ChannelTick() { if (!mPacketValid) { if (mPacketQueue.empty()) return; SendPacket(mPacketQueue.front()); mPacketQueue.pop(); return; } if (IsActive()) { while (IsActive()) { CInt_t Data = mPacket[mPacketIdx++]; SetData(Data, mPacketIdx == mPacket.size()); if (mPacketIdx == mPacket.size()) { mPacketValid = false; return; } } // mLogger << setloglevel(LogLevel_Error) << "Packet is too large for buffer of Start:" << HexPrinter(mStart) << " Limit: " << HexPrinter(mLimit) << " Size: " << DecPrinter(mLimit - mStart) << std::endl; mLogger << setloglevel(LogLevel_Error) << "Packet is too large for buffer" << std::endl; mLogger << setloglevel(LogLevel_Error) << "Packet size:" << mPacket.size() << " words" << std::endl; for (size_t Idx = 0; Idx < mPacket.size(); ++Idx) { mLogger << setloglevel(LogLevel_Error) << HexPrinter(Idx, 4) << " : " << HexPrinter(mPacket[Idx]) << " - " << AsciiDumpPrinter(mPacket[Idx]) << std::endl; } CRAY_ASSERT(false); //Disconnect(); } } bool SimIopCluster_c::ChannelIToC_c::ReadyToSend() const { return !mPacketValid; } void SimIopCluster_c::ChannelIToC_c::SendPacket(const std::vector &aPacket, bool aReplace) { CRAY_ASSERT(!mPacketValid || aReplace); mPacket = aPacket; mPacketIdx = 0; mPacketValid = true; mLogger << setloglevel(LogLevel_IoTrace) << "Priming packet to mainframe of " << mPacket.size() << " words" << std::endl; } void SimIopCluster_c::ChannelIToC_c::QueuePacket(const std::vector &aPacket) { ++mParent.mPacketsSent; if (!mPacketValid) { SendPacket(aPacket); } else { mPacketQueue.push(aPacket); } } // SimIopCluster_c::ChannelCToI_c ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SimIopCluster_c::ChannelCToI_c::ChannelCToI_c(const Configuration_c &aConfig, size_t aChannelId, Mainframe_c &aMainframe, SimIopCluster_c &aParent) : Channel_i(aChannelId, aMainframe), mLogger(aConfig, "C->I_", aChannelId), mParent(aParent), mPacketValid(false), mPacketIdx(0) { mLogger.SetParent(aParent.GetLogger()); } void SimIopCluster_c::ChannelCToI_c::ChannelTick() { while (IsActive() && !mPacketValid) { CInt_t Data = GetData(); mPacket.emplace_back(Data); if (!IsActive()) { // Channel just got done with transmission due to this word --> mark the packet valid mPacketValid = true; } } } bool SimIopCluster_c::ChannelCToI_c::HasPacket() { return mPacketValid; } std::vector SimIopCluster_c::ChannelCToI_c::GetPacket() { CRAY_ASSERT(mPacketValid); mPacketValid = false; std::vector RetVal(std::move(mPacket)); mPacket.clear(); return RetVal; } // Console handling ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SimIopCluster_c::MakeConsoles(size_t aMaxConsoleId) { while (mConsoles.size() <= aMaxConsoleId) { if (mIopRevision == IopRevision_e::IOSE) { std::unique_ptr Console = std::make_unique( mDefaultConsoleConfig, mConsoles.size(), *this, uint8_t(mConsoles.size()), mMainframe->DoDisableAutoTerminal() ); mConsoles.push_back(std::move(Console)); } else { std::unique_ptr Console = std::make_unique( mDefaultConsoleConfig, mConsoles.size(), *this, uint8_t(mConsoles.size()), mMainframe->DoDisableAutoTerminal() ); mConsoles.push_back(std::move(Console)); } } } void SimIopCluster_c::HandleIosEZPacket(IopEPacket_c &aPacket) { using namespace IosEZPacket_n; uint8_t Dev = uint8_t(GetBits(aPacket.Data(0), DevRange)); MakeConsoles(Dev); SimIopConsole_c &Console = *mConsoles[Dev]; Console.HandlePacket(aPacket.GetRawData()); } void SimIopCluster_c::HandleTPacket(std::vector &aPacket) { using namespace IosTPacket_n; uint8_t IopNumber = uint8_t(GetBits(aPacket[0], IopNumberRange)); uint8_t TTyNumber = uint8_t(GetBits(aPacket[0], TTyNumberRange)); CRAY_ASSERT(IopNumber == mIopId); MakeConsoles(TTyNumber); SimIopConsole_c &Console = *mConsoles[TTyNumber]; Console.HandlePacket(aPacket); } #if defined(PARTIAL_DEBUG) && defined(_MSC_VER) #pragma optimize ("", on) #endif