1872 lines
62 KiB
C++
1872 lines
62 KiB
C++
// 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#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::BreakPoint_i> IopCpu_c::CreateBreakPoint(const std::string &aBreakPointType, const Configuration_c &aConfig) {
|
|
if (aBreakPointType == "LogOn") {
|
|
return std::make_shared<LogOn_c>(aConfig);
|
|
} else if (aBreakPointType == "Terminate") {
|
|
return std::make_shared<Terminate_c>(aConfig);
|
|
} else if (aBreakPointType == "LogOff") {
|
|
return std::make_shared<LogOff_c>(aConfig);
|
|
} else if (aBreakPointType == "LogLevel") {
|
|
return std::make_shared<LogLevel_c>(aConfig);
|
|
} else if (aBreakPointType == "LogLevelPush") {
|
|
return std::make_shared<LogLevelPush_c>(aConfig);
|
|
} else if (aBreakPointType == "LogLevelPop") {
|
|
return std::make_shared<LogLevelPop_c>(aConfig);
|
|
} else if (aBreakPointType == "Trace") {
|
|
return std::make_shared<TracePoint_c>(aConfig);
|
|
} else if (aBreakPointType == "Event") {
|
|
return std::make_shared<EventFirePoint_c>(aConfig);
|
|
} else {
|
|
throw InvalidParameter_x(boost::format("Unkown breakpoint type:") % aBreakPointType);
|
|
}
|
|
}
|
|
|
|
IopCpu_c::IopCpu_c(const Configuration_c &aConfig, uint8_t aCpuId, std::vector<uint8_t> &aIoMemory, std::vector<uint8_t> *aBufferMemory, class IopCluster_c &aIopCluster):
|
|
mIoMemory(aIoMemory),
|
|
mCpuId(aCpuId),
|
|
mState(
|
|
aConfig,
|
|
*this,
|
|
aConfig.get<uint64_t>("ClockFrequency", 80000000),
|
|
aConfig.get<uint64_t>("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<bool>("Exists", true);
|
|
mLogger.SetParent(aIopCluster.GetLogger());
|
|
try {
|
|
boost::optional<std::string> DefaultLogLevel = aConfig.get_optional<std::string>("DefaultLogLevel");
|
|
if (DefaultLogLevel.is_initialized()) {
|
|
mLogger.SetDisplayLogLevel(FromString_LogLevels_e(DefaultLogLevel.get()));
|
|
}
|
|
|
|
std::string IopType = aConfig.get<std::string>("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<size_t>("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<IopPeripheral_i> Peripheral;
|
|
if (PeripheralType == "ERA") {
|
|
Peripheral = std::make_shared<ChannelERA_c>(ChannelConfig.second, *this, ChannelConfig.second.get<size_t>("ChannelIdx"));
|
|
} else if (PeripheralType == "Console") {
|
|
Peripheral = std::make_shared<IopConsole_c>(ChannelConfig.second, *this, mIopCluster->GetMainframe().DoDisableAutoTerminal());
|
|
} else if (PeripheralType == "HIA") {
|
|
Peripheral = std::make_shared<ChannelHostMemory_c>(ChannelConfig.second, *this, mIopCluster->GetMainframe().GetMemory(), ChannelConfig.second.get<size_t>("ChannelIdx"), true, false);
|
|
} else if (PeripheralType == "HOA") {
|
|
Peripheral = std::make_shared<ChannelHostMemory_c>(ChannelConfig.second, *this, mIopCluster->GetMainframe().GetMemory(), ChannelConfig.second.get<size_t>("ChannelIdx"), false, true);
|
|
} else if (PeripheralType == "Expander") {
|
|
Peripheral = std::make_shared<IopChannelExp_c>(ChannelConfig.second, *this);
|
|
} else if (PeripheralType == "DD29") {
|
|
Peripheral = std::make_shared<IopDiskDD29_c>(ChannelConfig.second, *this);
|
|
} else if (PeripheralType == "Bmx") {
|
|
Peripheral = std::make_shared<IopChannelBmx_c>(ChannelConfig.second, *this);
|
|
} else if (PeripheralType == "CI") {
|
|
size_t CrayChannelIdx = ChannelConfig.second.get<size_t>("CrayChannelIdx");
|
|
size_t IopChannelIdx = ChannelConfig.second.get<size_t>("IopChannelIdx");
|
|
std::shared_ptr<IopCrayChannel_c> LocalChannel = std::make_shared<IopCrayChannel_c>(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<size_t>("CrayChannelIdx");
|
|
size_t IopChannelIdx = ChannelConfig.second.get<size_t>("IopChannelIdx");
|
|
std::shared_ptr<IopCrayChannel_c> LocalChannel = std::make_shared<IopCrayChannel_c>(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<IopConcentrator_c>(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;i<Peripheral->GetChannelCnt();++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<std::string>("Type");
|
|
IopInt_t Addr = FromString<IopInt_t>(BreakPoint.first);
|
|
std::shared_ptr<BreakPoint_i> 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<size_t>("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;RegIdx<sizeof(mState.OperandRegisters)/sizeof(mState.OperandRegisters[0]);++RegIdx) {
|
|
mLogger << setloglevel(LogLevel_Dump) << Indent(aIdent) << "OR[" << DecPrinter(RegIdx,0) << "]: "
|
|
<< HexPrinter(mState.OperandRegisters[RegIdx]) << " "
|
|
<< std::endl;
|
|
}
|
|
for(size_t i=0;i<mIoChannels.size();++i) {
|
|
if (mIoChannels[i] != nullptr) mIoChannels[i]->Dump(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;i<mIoChannels.size();++i) {
|
|
if (mIoChannels[i] != nullptr) mIoChannels[i]->MasterClear();
|
|
}
|
|
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<IopParcel_t>(mState.P);
|
|
IopParcel_t SecondParcel = 0;
|
|
SecondParcel = IoMemAccess<IopParcel_t>((mState.P+1) & 0xffff);
|
|
|
|
bool DelayISet = false;
|
|
bool BreakBurst;
|
|
IopInt_t Increment = Decode<false>(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;i<mIoChannels.size();++i) {
|
|
if (mIoChannels[i] != nullptr) mIoChannels[i]->Tick();
|
|
}*/
|
|
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;i<mIoChannels.size();++i) {
|
|
if (mIoChannels[i] != nullptr) {
|
|
if (mIoChannels[i]->GetInterrupt() != 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<IopParcel_t>(mState.P);
|
|
IopParcel_t SecondParcel = 0;
|
|
SecondParcel = IoMemAccess<IopParcel_t>((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<false>(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<true>(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 <bool aDoExecute, uint16_t aFieldF> 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 <bool aDoExecute, uint16_t aFieldF> 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 <bool aDoExecute, uint16_t aFieldF> 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<true, aFieldF>, &IopCpu_c::Decode<false, aFieldF> }
|
|
#define DECODEJUMP(aFieldF) { &IopCpu_c::DecodeJump<true, aFieldF>, &IopCpu_c::DecodeJump<false, aFieldF> }
|
|
#define DECODEIO(aFieldF) { &IopCpu_c::DecodeIo<true, aFieldF>, &IopCpu_c::DecodeIo<false, aFieldF> }
|
|
|
|
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 <bool aDoExecute> 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(); }
|