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

412 lines
14 KiB
C++

// Cray-XMP I/O Processor simulator class
#include "sim_iop.h"
#include "sim_iop_periph.h"
#if defined(PARTIAL_DEBUG) && defined(_MSC_VER)
#pragma optimize ("", off)
#endif
// SimIopPeripheral_c
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SimIopPeripheral_c::SimIopPeripheral_c(const Configuration_c &aConfig, SimIopCluster_c &aParent):
mLogger(aConfig, "PERI"),
mParent(aParent)
{
mLogger.SetParent(aParent.GetLogger());
mPrinterFileName = aConfig.get<std::string>("PrinterFileName");
mDiskDir = aConfig.get<std::string>("DiskDir");
mTapeDir = aConfig.get<std::string>("TapeDir");
mLastTapeFile = 0;
mRewindOnClose = true;
}
void SimIopPeripheral_c::GetStatus(StatusReport_c &aStatus, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const {}
std::string SimIopPeripheral_c::GetName() const {
std::stringstream Name;
Name << "EXP";
return Name.str();
}
void SimIopPeripheral_c::RegisterCommands(CommandHooks_t &aHooks) {}
void SimIopPeripheral_c::Reset() {
}
void SimIopPeripheral_c::Write(
uint32_t *aAddr,
uint32_t *aDataLen,
uint32_t *aTransferLen,
size_t aNumBuffers,
std::ostream &aFile
) {
for (size_t Idx = 0; Idx < aNumBuffers; ++Idx) {
if (aDataLen[Idx] == 0) continue;
mLogger << setloglevel(LogLevel_IoTrace) << "Writing to expander device from address: " << HexPrinter(aAddr[Idx]) << " len: " << HexPrinter(aDataLen[Idx]) << std::endl;
LogLine_c TraceLine = mLogger << setloglevel(LogLevel_IoTrace);
const size_t cLineSize = 4;
size_t AccessSize = (aDataLen[Idx] + sizeof(CInt_t) * cLineSize - 1) / (sizeof(CInt_t) * cLineSize);
size_t DataLeft = aDataLen[Idx];
for (size_t i = 0; i < AccessSize; ++i) {
CAddr_t BaseAddr = CAddr_t(aAddr[Idx] + i * cLineSize);
CInt_t Data[cLineSize];
size_t LineSize = std::min(DataLeft, cLineSize * sizeof(CInt_t));
for (size_t j = 0; j < LineSize; j += sizeof(CInt_t)) {
Data[j / sizeof(CInt_t)] = mParent.GetMainframe().MemRead<CInt_t>(CAddr_t(BaseAddr + j / sizeof(CInt_t)));
}
aFile.write((char*)(&Data), LineSize);
CRAY_ASSERT(!aFile.bad());
if (TraceLine.good()) {
TraceLine << HexPrinter(aAddr[Idx] + i * cLineSize) << " : ";
for (size_t j = 0; j < LineSize; j += sizeof(CInt_t)) {
TraceLine << HexPrinter(SwapBytes(Data[j / sizeof(CInt_t)])) << " ";
}
TraceLine << " - ";
for (size_t j = 0; j < LineSize; j += sizeof(CInt_t)) {
TraceLine << AsciiDumpPrinter(SwapBytes(Data[j / sizeof(CInt_t)])) << " ";
}
TraceLine << std::endl;
}
DataLeft -= LineSize;
}
TraceLine << std::endl;
CRAY_ASSERT(DataLeft == 0);
aTransferLen[Idx] = aDataLen[Idx];
}
}
void SimIopPeripheral_c::Read(
uint32_t *aAddr,
uint32_t *aDataLen,
uint32_t *aTransferLen,
size_t aNumBuffers,
std::istream &aFile
) {
for (size_t Idx = 0; Idx < aNumBuffers; ++Idx) {
if (aDataLen[Idx] == 0) continue;
if (aFile.eof()) {
aTransferLen[Idx] = 0;
continue;
}
mLogger << setloglevel(LogLevel_IoTrace) << "Reading from expander device to address: " << HexPrinter(aAddr[Idx]) << " len: " << HexPrinter(aDataLen[Idx]) << std::endl;
LogLine_c TraceLine = mLogger << setloglevel(LogLevel_IoTrace);
const size_t cLineSize = 4;
size_t AccessSize = (aDataLen[Idx] + sizeof(CInt_t) * cLineSize - 1) / (sizeof(CInt_t) * cLineSize);
size_t DataLeft = aDataLen[Idx];
for (size_t i = 0; i < AccessSize; ++i) {
CAddr_t BaseAddr = CAddr_t(aAddr[Idx] + i * cLineSize);
CInt_t Data[cLineSize];
size_t LineSize = std::min(DataLeft, cLineSize * sizeof(CInt_t));
aFile.read((char*)(&Data), LineSize);
size_t BytesRead = size_t(aFile.gcount());
if (BytesRead < LineSize) {
CRAY_ASSERT(aFile.eof());
} else {
CRAY_ASSERT(!aFile.bad());
}
LineSize = BytesRead;
for (size_t j = 0; j < LineSize; j += sizeof(CInt_t)) {
mParent.GetMainframe().MemWrite(CAddr_t(BaseAddr + j / sizeof(CInt_t)), Data[j / sizeof(CInt_t)]);
}
if (TraceLine.good()) {
TraceLine << HexPrinter(aAddr[Idx] + i * cLineSize) << " : ";
for (size_t j = 0; j < LineSize; j += sizeof(CInt_t)) {
TraceLine << HexPrinter(SwapBytes(Data[j / sizeof(CInt_t)])) << " ";
}
TraceLine << " - ";
for (size_t j = 0; j < LineSize; j += sizeof(CInt_t)) {
TraceLine << AsciiDumpPrinter(SwapBytes(Data[j / sizeof(CInt_t)])) << " ";
}
TraceLine << std::endl;
}
DataLeft -= LineSize;
if (aFile.eof()) break;
}
TraceLine << std::endl;
CRAY_ASSERT(DataLeft == 0 || aFile.eof());
aTransferLen[Idx] = aDataLen[Idx] - uint32_t(DataLeft);
// aDataLen[Idx] = aTransferLen[Idx];
}
}
void SimIopPeripheral_c::SendPacket(std::vector<CInt_t> &aPacket, bool aIosEStyle) {
if (!aIosEStyle) {
mParent.SendPacket(aPacket);
return;
} else {
IopEPacket_c Response = mParent.GenerateResponse();
Response.SetSize(aPacket.size()+1);
Response.Data(0) = 0x6600030000000000ULL; // Let's assume response code is the same as request, except lower-case 'f'. Could be wrong...
for (size_t Idx = 0; Idx < aPacket.size(); ++Idx) Response.Data(Idx + 1) = aPacket[Idx];
mParent.SendPacket(Response);
}
}
void SimIopPeripheral_c::HandleIosDPacket(std::vector<CInt_t> &aPacket) {
HandlePacket(aPacket, false);
}
void SimIopPeripheral_c::HandleIosEPacket(IopEPacket_c &aPacket) {
// Extract the IosD-style packet
std::vector<CInt_t> Packet(aPacket.GetLength() - 2);
for (size_t Idx = 0; Idx < Packet.size(); ++Idx) Packet[Idx] = aPacket.Data(Idx + 1);
HandlePacket(Packet, true);
}
// IOSD packet structure is in fpacket.h, IOSE packet structure is in epackfp.h
// They seem to be more or less identical, except for the filename location and size
void SimIopPeripheral_c::HandlePacket(std::vector<CInt_t> &aPacket, bool aIosEStyle) {
using namespace IosFPacket_n;
FunctionCodes_e Function = FunctionCodes_e(GetBits(aPacket[0], RequestFunctionRange));
StatusCodes_e Status = StatusCodes_e(GetBits(aPacket[0], StatusRange));
uint8_t IopNumber = uint8_t(GetBits(aPacket[0], IopNumberRange));
ChannelNumbers_e ChannelNumber = ChannelNumbers_e(GetBits(aPacket[0], ChannelNumberRange));
switch (Function) {
case FunctionCodes_e::OPN: {
switch (ChannelNumber) {
case ChannelNumbers_e::Printer:
mPrinterFile.open(mPrinterFileName, std::ios::out | std::ios::app);
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
case ChannelNumbers_e::Disk:
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
case ChannelNumbers_e::Tape: {
bool DoWrite = GetBits(aPacket[5], ReadWriteRange) != 0;
mRewindOnClose = GetBits(aPacket[5], RewindRange) != 0;
uint16_t FileNumber = uint16_t(GetBits(aPacket[5], FileNumberRange));
mLastTapeFile = FileNumber;
char UserName[9];
UserName[8] = 0;
memcpy(UserName, &aPacket[1], 8);
*(uint64_t *)(UserName) = SwapBytes(*(uint64_t *)(UserName));
boost::filesystem::path FullPath(mTapeDir);
if (!boost::filesystem::exists(FullPath)) boost::filesystem::create_directories(FullPath);
std::stringstream FileNumberStr;
FileNumberStr << DecPrinter(FileNumber) << ".dat";
FullPath /= FileNumberStr.str();
if (!boost::filesystem::exists(FullPath) && !DoWrite) {
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::ILDRV)); // :::TODO how to return errors?
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
}
mFile.open(FullPath.generic_string(), std::ios::binary | (DoWrite ? std::ios::out : std::ios::in));
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
}
case ChannelNumbers_e::File:
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
default:
CRAY_ASSERT(false);
}
} break;
case FunctionCodes_e::CLS: {
switch (ChannelNumber) {
case ChannelNumbers_e::Printer:
mPrinterFile.close();
break;
case ChannelNumbers_e::Disk:
mDiskFile.close();
break;
case ChannelNumbers_e::Tape:
if (mRewindOnClose) {
mLastTapeFile = 0;
} else {
++mLastTapeFile;
}
mTapeFile.close();
break;
case ChannelNumbers_e::File:
mFile.close();
break;
default:
CRAY_ASSERT(false);
}
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
} break;
case FunctionCodes_e::RD:
case FunctionCodes_e::RDHLD:
case FunctionCodes_e::RDRD: {
uint32_t Addr[2];
uint32_t DataLen[2];
uint32_t TransferLen[2];
Addr[0] = uint32_t(GetBits(aPacket[2], AddrReq1Range));
Addr[1] = uint32_t(GetBits(aPacket[2], AddrReq2Range));
DataLen[0] = uint32_t(GetBits(aPacket[3], DataLenReq1Range));
DataLen[1] = uint32_t(GetBits(aPacket[3], DataLenReq2Range));
TransferLen[0] = uint32_t(GetBits(aPacket[4], TransferLenReq1Range));
TransferLen[1] = uint32_t(GetBits(aPacket[4], TransferLenReq2Range));
switch (ChannelNumber) {
case ChannelNumbers_e::Printer:
CRAY_ASSERT(false);
break;
case ChannelNumbers_e::Disk:
break;
case ChannelNumbers_e::Tape:
Read(Addr, DataLen, TransferLen, 2, mTapeFile);
break;
case ChannelNumbers_e::File:
Read(Addr, DataLen, TransferLen, 2, mFile);
break;
default:
CRAY_ASSERT(false);
}
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SetBits(aPacket[4], TransferLenReq1Range, uint64_t(TransferLen[0]));
SetBits(aPacket[4], TransferLenReq2Range, uint64_t(TransferLen[1]));
SendPacket(aPacket, aIosEStyle);
} break;
case FunctionCodes_e::WR:
case FunctionCodes_e::WRHLD:
case FunctionCodes_e::WRWR: {
uint32_t Addr[2];
uint32_t DataLen[2];
uint32_t TransferLen[2];
Addr[0] = uint32_t(GetBits(aPacket[2], AddrReq1Range));
Addr[1] = uint32_t(GetBits(aPacket[2], AddrReq2Range));
DataLen[0] = uint32_t(GetBits(aPacket[3], DataLenReq1Range));
DataLen[1] = uint32_t(GetBits(aPacket[3], DataLenReq2Range));
TransferLen[0] = uint32_t(GetBits(aPacket[4], TransferLenReq1Range));
TransferLen[1] = uint32_t(GetBits(aPacket[4], TransferLenReq2Range));
switch (ChannelNumber) {
case ChannelNumbers_e::Printer:
Write(Addr, DataLen, TransferLen, 2, mPrinterFile);
break;
case ChannelNumbers_e::Disk:
break;
case ChannelNumbers_e::Tape:
Write(Addr, DataLen, TransferLen, 2, mTapeFile);
break;
case ChannelNumbers_e::File:
Write(Addr, DataLen, TransferLen, 2, mFile);
break;
default:
CRAY_ASSERT(false);
}
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SetBits(aPacket[4], TransferLenReq1Range, uint64_t(TransferLen[0]));
SetBits(aPacket[4], TransferLenReq2Range, uint64_t(TransferLen[1]));
SendPacket(aPacket, aIosEStyle);
} break;
case FunctionCodes_e::DRF32:
switch(ChannelNumber) {
case ChannelNumbers_e::File: {
boost::filesystem::path FullPath(mDiskDir);
bool DoWrite;
bool DoOverwrite;
if (!aIosEStyle) {
char DirName[17];
char FileName[17];
DirName[16] = 0;
FileName[16] = 0;
memcpy(DirName, &aPacket[1], 16);
memcpy(FileName, &aPacket[3], 16);
*(uint64_t *)(DirName + 0) = SwapBytes(*(uint64_t *)(DirName + 0));
*(uint64_t *)(DirName + 8) = SwapBytes(*(uint64_t *)(DirName + 8));
*(uint64_t *)(FileName + 0) = SwapBytes(*(uint64_t *)(FileName + 0));
*(uint64_t *)(FileName + 8) = SwapBytes(*(uint64_t *)(FileName + 8));
DoWrite = GetBits(aPacket[5], ReadWriteRange) != 0;
DoOverwrite = GetBits(aPacket[5], OverwriteRange) != 0;
FullPath /= DirName;
FullPath /= FileName;
} else {
const size_t MaxFileNameLen = 60 * 8;
char FileName[MaxFileNameLen + 1];
FileName[MaxFileNameLen] = 0;
memcpy(FileName, &aPacket[6], MaxFileNameLen);
for (size_t Idx = 0; Idx < MaxFileNameLen / 8; ++Idx) *(uint64_t *)(FileName + Idx * 8) = SwapBytes(*(uint64_t *)(FileName + Idx * 8));
DoWrite = GetBits(aPacket[5], ReadWriteRange) != 0;
DoOverwrite = GetBits(aPacket[5], OverwriteRange) != 0;
char *PathPart = strtok(FileName, "/");
while (PathPart != nullptr) {
FullPath /= PathPart;
PathPart = strtok(nullptr, "/");
}
}
if (FullPath.has_parent_path()) {
boost::filesystem::path Parent = FullPath.parent_path();
if (!boost::filesystem::exists(Parent)) boost::filesystem::create_directories(Parent);
}
if (boost::filesystem::exists(FullPath) && !DoOverwrite && DoWrite) {
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::ILDRV)); // :::TODO how to return errors?
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
}
if (!boost::filesystem::exists(FullPath) && !DoWrite) {
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::ILDRV)); // :::TODO how to return errors?
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
}
std::cout << "OPENING extender file '" << FullPath.generic_string() << "' for " << (DoWrite ? "writing" : "reading") << std::endl;
mFile.open(FullPath.generic_string(), std::ios::binary | (DoWrite ? std::ios::out : std::ios::in));
ReversePacket(aPacket);
SetBits(aPacket[0], StatusRange, uint64_t(StatusCodes_e::OK));
SetBits(aPacket[0], StatusNumberRange, uint64_t(0));
SendPacket(aPacket, aIosEStyle);
break;
}
default:
CRAY_ASSERT(false);
}
break;
default:
CRAY_ASSERT(false);
break;
}
}
namespace IosFPacket_n {
const char *LPNAME = "UPRINT";
const char *EXNAME = "UDISK";
const char *ETNAME = "UTAPE";
const char *EFNAME = "UFILE";
};
#if defined(PARTIAL_DEBUG) && defined(_MSC_VER)
#pragma optimize ("", on)
#endif