1062 lines
53 KiB
C++
1062 lines
53 KiB
C++
#pragma once
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <mutex>
|
|
#include "utils.h"
|
|
#include "cray_types.h"
|
|
#include "cray_cpu.h"
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <limits.h>
|
|
#include "cray_mainframe.h"
|
|
#include "exchange_packet.h"
|
|
#include "config_file.h"
|
|
#include <boost/circular_buffer.hpp>
|
|
|
|
// Cray-1S CPU 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 !!!!!!!!!!!!!!
|
|
|
|
// NOTE: The #define COLLECT_PERF controls whether performance collection for certain operations (such as jump prediction accuracy, caches, life-time) is collected
|
|
// It is defauled undefined, but can ben defined to enable such statistics
|
|
//#define COLLECT_PERF
|
|
|
|
#ifdef CRAY_UNIMPLEMENTED
|
|
#error CRAY_UNIMPLEMENTED is already defined
|
|
#endif
|
|
|
|
#define CRAY_UNKNOWN throw UnknownInstError_x(__FILE__,__LINE__);
|
|
|
|
#define CRAY_UNIMPLEMENTED \
|
|
do { \
|
|
if (!aDoExecute) { \
|
|
aDisassembly << "*** UNK ***"; \
|
|
} \
|
|
if (aDoExecute) { \
|
|
throw InstUnimplementedError_x(__FILE__,__LINE__); \
|
|
} \
|
|
return 1; \
|
|
} while (false);
|
|
|
|
|
|
inline size_t FirstParcel(uint64_t aInst) { return size_t((aInst >> 32) & 0xffff); }
|
|
inline size_t SecondParcel(uint64_t aInst) { return size_t((aInst >> 16) & 0xffff); }
|
|
inline size_t ThirdParcel(uint64_t aInst) { return size_t((aInst >> 0) & 0xffff); }
|
|
|
|
inline size_t FieldG(uint64_t aInst) { return (FirstParcel(aInst) & 0170000) >> 12; }
|
|
inline size_t FieldH(uint64_t aInst) { return (FirstParcel(aInst) & 0007000) >> 9; }
|
|
inline size_t FieldGH(uint64_t aInst) { return (FirstParcel(aInst) & 0177000) >> 9; }
|
|
inline size_t FieldI(uint64_t aInst) { return (FirstParcel(aInst) & 0000700) >> 6; }
|
|
inline size_t FieldJ(uint64_t aInst) { return (FirstParcel(aInst) & 0000070) >> 3; }
|
|
inline size_t FieldK(uint64_t aInst) { return (FirstParcel(aInst) & 0000007) >> 0; }
|
|
inline size_t FieldJK(uint64_t aInst) { return (FirstParcel(aInst) & 0000077) >> 0; }
|
|
inline size_t FieldIJK(uint64_t aInst) { return (FirstParcel(aInst) & 0000777) >> 0; }
|
|
inline size_t FieldM(uint64_t aInst) { return SecondParcel(aInst); }
|
|
inline size_t FieldJKM(uint64_t aInst) { return size_t((aInst & 0x003fffff0000) >> 16); }
|
|
inline size_t FieldIJKM(uint64_t aInst) { return size_t((aInst & 0x01ffffff0000) >> 16); }
|
|
inline size_t FieldMN(uint64_t aInst) { return SecondParcel(aInst) | (ThirdParcel(aInst) << 16); }
|
|
|
|
#define EXTRACT_FIELDS(aaInst) \
|
|
size_t g = FieldG(aaInst); \
|
|
size_t h = FieldH(aaInst); \
|
|
size_t gh = FieldGH(aaInst); \
|
|
size_t i = FieldI(aaInst); \
|
|
size_t j = FieldJ(aaInst); \
|
|
size_t k = FieldK(aaInst); \
|
|
size_t jk = FieldJK(aaInst); \
|
|
size_t ijk = FieldIJK(aaInst); \
|
|
size_t m = FieldM(aaInst); \
|
|
size_t jkm = FieldJKM(aaInst); \
|
|
size_t ijkm = FieldIJKM(aaInst); \
|
|
size_t mn = FieldMN(aaInst);
|
|
|
|
class SoftCpu_c: public Cpu_c {
|
|
public:
|
|
explicit SoftCpu_c(const Configuration_c &aConfig, const Configuration_c &aDefaultConfig, Mainframe_c &aMainframe, Mainframe_c::BreakPoints_t &aBreakpoints, size_t aCpuId);
|
|
explicit SoftCpu_c(Mainframe_c &aMainframe);
|
|
virtual ~SoftCpu_c() override {}
|
|
|
|
virtual void MasterClear() override; // Enters the CPU into it's reset state, stops executing
|
|
virtual void DeadStart() override; // Removes the CPU from it's reset state, starts executing
|
|
|
|
virtual void SetDeadLockInterrupt() override {
|
|
mNotDeadLockInterrupt.clear();
|
|
// mState.Flags.SetDeadlock();
|
|
}
|
|
virtual void SetIoInterrupt() override {
|
|
mNotIoInterrupt.clear();
|
|
// mState.Flags.SetIoInterrupt();
|
|
}
|
|
virtual void Tick() override;
|
|
virtual bool IsTsBlocked() const override { return mState.TestAndSetBlocked; }
|
|
virtual bool IsSelectedForExternalInterrupts() const override { return mState.Mode.IsSelectedForExternalInterrupts(); }
|
|
virtual uint8_t GetCluster() const override { return mState.Cluster; }
|
|
|
|
virtual CProgramAddr_t GetAbsoluteProgramCounter() const override { return mState.InstBaseAddr * 4 + mState.ProgramAddress; }
|
|
|
|
virtual void GetStatus(StatusReport_c &aStatus, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const override;
|
|
virtual std::string GetName() const override;
|
|
virtual void Dump(size_t aIdent = 0) const override;
|
|
virtual uint8_t GetExchangePacketAddress() const override { return mState.ExchangePacketAddress; }
|
|
|
|
size_t Decode(
|
|
CProgramAddr_t aInstAddr,
|
|
std::ostream &aDisassembly,
|
|
std::ostream &aExplanation,
|
|
std::ostream &aInstCodes,
|
|
std::ostream &aHexInstCodes
|
|
); // Returns the increment to the ProgramAddress. Might throw all sorts of memory access exceptions, or even InstFetchOutOfBoundsError_x if aIsSecondParcelValid == false
|
|
|
|
void SetInstBaseAddr(const CAddr_t &aAddr) { mState.InstBaseAddr = aAddr; }
|
|
void SetDataBaseAddr(const CAddr_t &aAddr) { mState.DataBaseAddr = aAddr; }
|
|
|
|
virtual void DumpHistory() override;
|
|
virtual void ClearHistory() override { mHistory.clear(); }
|
|
|
|
#ifdef COLLECT_PERF
|
|
static const size_t mHistSize = 35;
|
|
std::array<uint64_t, mHistSize> GetLoadUseHist() const { return mLoadUseHist; }
|
|
std::array<uint64_t, mHistSize> GetBBHist() const { return mBBHist; }
|
|
virtual uint64_t GetJumpsTaken() const override { return mJumpsTaken; }
|
|
virtual uint64_t GetJumpsNotTaken() const override { return mJumpsNotTaken; }
|
|
#endif
|
|
virtual void SetInterProcessorInterrupt() override {
|
|
// TODO: this needs proper testing: originally these interrupts didn't get flagged, unless the target processor was in user mode and monitor-mode interrupts were disabled
|
|
// i.e. inter-processor interrupts were eaten if the target was not in monitor mode, instead of getting buffered until the interrupt could be served on the target.
|
|
// if (!IsMonitorMode() && !IsInterruptMonitorMode()) {
|
|
mNotInterProcessorInterrupt.clear();
|
|
// mState.Flags.SetInterProcessorInterrupt();
|
|
// }
|
|
}
|
|
|
|
virtual void Exchange() override;
|
|
CProgramAddr_t GetProgramCounter() const { return mState.ProgramAddress; }
|
|
bool IsMonitorMode() { return mState.Mode.IsMonitorMode(); }
|
|
CInt_t GetSReg(size_t aRegIdx) const { return mState.S[aRegIdx]; }
|
|
CInt_t GetTReg(size_t aRegIdx) const { return mState.T[aRegIdx]; }
|
|
CAddr_t GetAReg(size_t aRegIdx) const { return mState.A[aRegIdx]; }
|
|
void SetAReg(size_t aRegIdx, CAddr_t aValue) {
|
|
mLogger << setloglevel(LogLevel_InstructionTrace) << "Overriding register A" << DecPrinter(aRegIdx) << " with value " << HexPrinter(aValue) << std::endl;
|
|
mState.A[aRegIdx] = aValue;
|
|
}
|
|
CAddr_t GetBReg(size_t aRegIdx) const { return mState.B[aRegIdx]; }
|
|
CInt_t GetVReg(size_t aRegIdx, size_t aElementIdx) const { return mState.V[aRegIdx][aElementIdx]; }
|
|
protected:
|
|
virtual void SetProgrammableClockInterrupt() override;
|
|
|
|
std::atomic_flag mNotInterProcessorInterrupt;
|
|
std::atomic_flag mNotDeadLockInterrupt;
|
|
std::atomic_flag mNotMcuInterrupt;
|
|
std::atomic_flag mNotIoInterrupt;
|
|
void InitNotIntFlags() {
|
|
mNotInterProcessorInterrupt.test_and_set();
|
|
mNotDeadLockInterrupt.test_and_set();
|
|
mNotMcuInterrupt.test_and_set();
|
|
mNotIoInterrupt.test_and_set();
|
|
}
|
|
void MirrorExternalInterrupts() {
|
|
if (!mNotInterProcessorInterrupt.test_and_set()) mState.Flags.SetInterProcessorInterrupt();
|
|
if (!mNotDeadLockInterrupt.test_and_set()) mState.Flags.SetDeadlock();
|
|
if (!mNotMcuInterrupt.test_and_set()) mState.Flags.SetMcuInterrupt();
|
|
if (!mNotIoInterrupt.test_and_set()) mState.Flags.SetIoInterrupt();
|
|
}
|
|
void SetMcuInterrupt() {
|
|
mNotMcuInterrupt.clear();
|
|
// mState.Flags.SetMcuInterrupt();
|
|
}
|
|
bool IsInterruptMonitorMode() { return mState.Mode.IsInterruptMonitorMode(); }
|
|
Mode_c GetMode() const { return mState.Mode; }
|
|
CInt_t GetSR(size_t aSrIdx);
|
|
void SetSR(size_t aSrIdx, CInt_t aValue);
|
|
CAddr_t GetAddrMask() const { return mState.AddrMask; }
|
|
bool IsXMode() const { return mState.XMode; }
|
|
bool IsXmp() const { return ::IsXmp(GetMainframe().GetMachineType()); }
|
|
bool IsJ90OrSV1() const {
|
|
return (GetMainframe().GetMachineType() == MachineTypes_e::J90) || (GetMainframe().GetMachineType() == MachineTypes_e::SV1);
|
|
}
|
|
bool IsSV1() const { return (GetMainframe().GetMachineType() == MachineTypes_e::SV1); }
|
|
void TestBreakPoints();
|
|
|
|
Mainframe_c::BreakPoints_t mBreakPoints;
|
|
|
|
int32_t SignExtend(const CAddr_t &aA) {
|
|
if (IsXMode()) return ::SignExtend(CXmpAddr_t(aA));
|
|
return ::SignExtend(aA);
|
|
}
|
|
|
|
uint64_t mInstCnt;
|
|
mutable uint64_t mLastInstCnt;
|
|
uint64_t mInstCntBase;
|
|
AtomicBool mInReset;
|
|
std::atomic_flag mMasterClearLock;
|
|
|
|
struct MemoryPoke_s {
|
|
CAddr_t Addr;
|
|
CInt_t Value;
|
|
bool IsParcelPoke;
|
|
};
|
|
std::vector<MemoryPoke_s> mMemoryPokes;
|
|
uint32_t mTimerIncrement;
|
|
void SetCluster(uint8_t aCluster) {
|
|
if (mState.Cluster != aCluster) {
|
|
if (mState.Cluster != 0) {
|
|
// std::unique_lock<std::mutex> Lock(mMainframe.GetCluster(mState.Cluster - 1).ClusterMutex);
|
|
Lock_c Lock(mMainframe.GetCluster(mState.Cluster - 1).ClusterMutex);
|
|
--mMainframe.GetCluster(mState.Cluster - 1).ClusterCpuCnt;
|
|
}
|
|
if (aCluster != 0) {
|
|
// std::unique_lock<std::mutex> Lock(mMainframe.GetCluster(aCluster - 1).ClusterMutex);
|
|
Lock_c Lock(mMainframe.GetCluster(aCluster - 1).ClusterMutex);
|
|
++mMainframe.GetCluster(aCluster - 1).ClusterCpuCnt;
|
|
}
|
|
}
|
|
mState.Cluster = aCluster;
|
|
}
|
|
uint16_t InterruptMaskFromState() const {
|
|
// First see which interrupts are enabled. This depends on various mode bits
|
|
if (mState.Mode.IsMonitorMode()) {
|
|
// In monitor mode
|
|
if (mState.Mode.IsInterruptMonitorMode()) {
|
|
return
|
|
//Flags_c::InterProcessorInterrupt |
|
|
Flags_c::Deadlock |
|
|
//Flags_c::ProgrammableClockInterrupt |
|
|
Flags_c::McuInterrupt |
|
|
Flags_c::FloatingPointError |
|
|
Flags_c::OperandRangeError |
|
|
Flags_c::ProgramRangeError |
|
|
Flags_c::MemoryError |
|
|
//Flags_c::IoInterrupt |
|
|
Flags_c::ErrorExit |
|
|
Flags_c::NormalExit;
|
|
}
|
|
else {
|
|
return
|
|
(mInReset ? Flags_c::InterProcessorInterrupt : 0) |
|
|
//Flags_c::Deadlock |
|
|
//Flags_c::ProgrammableClockInterrupt |
|
|
Flags_c::McuInterrupt |
|
|
//Flags_c::FloatingPointError |
|
|
//Flags_c::OperandRangeError |
|
|
//Flags_c::ProgramRangeError |
|
|
Flags_c::MemoryError |
|
|
//Flags_c::IoInterrupt |
|
|
Flags_c::ErrorExit |
|
|
Flags_c::NormalExit;
|
|
}
|
|
}
|
|
else {
|
|
// Not in monitor mode
|
|
return
|
|
Flags_c::InterProcessorInterrupt |
|
|
Flags_c::Deadlock |
|
|
Flags_c::ProgrammableClockInterrupt |
|
|
Flags_c::McuInterrupt |
|
|
(mState.Mode.IsFloatingPointErrorMode() ? Flags_c::FloatingPointError : 0) |
|
|
(mState.Mode.IsOperandRangeErrorMode() ? Flags_c::OperandRangeError : 0) |
|
|
Flags_c::ProgramRangeError |
|
|
((mState.Mode.IsCorrectableMemoryErrorMode() | mState.Mode.IsUncorrectableMemoryErrorMode()) ? Flags_c::MemoryError : 0) | //TODO: This is not precise here, but since we don't simulate memory errors, it'll do
|
|
Flags_c::IoInterrupt |
|
|
Flags_c::ErrorExit |
|
|
Flags_c::NormalExit;
|
|
}
|
|
}
|
|
void CalcInterruptMask() {
|
|
mState.InterruptMask.Data = InterruptMaskFromState();
|
|
}
|
|
enum class Reg_e {
|
|
P = 0,
|
|
VL,
|
|
VM,
|
|
XP,
|
|
Exchange,
|
|
Special = 0x0000,
|
|
ABase = 0x1000,
|
|
SBase = 0x2000,
|
|
BBase = 0x3000,
|
|
TBase = 0x4000,
|
|
SBBase = 0x5000,
|
|
STBase = 0x6000,
|
|
VBase = 0x7000,
|
|
BaseMask = 0xff000,
|
|
RegMask = 0xfff
|
|
};
|
|
static std::string RegName(Reg_e aReg) {
|
|
switch (Reg_e(int(aReg) & int(Reg_e::BaseMask))) {
|
|
case Reg_e::Special:
|
|
switch (Reg_e(int(aReg) & int(Reg_e::RegMask))) {
|
|
case Reg_e::P: return "P";
|
|
case Reg_e::VL: return "VL";
|
|
case Reg_e::VM: return "VM";
|
|
case Reg_e::XP: return "XP";
|
|
case Reg_e::Exchange: return "Exchange";
|
|
default: CRAY_ASSERT(false);
|
|
}
|
|
case Reg_e::ABase: {
|
|
std::stringstream Strm;
|
|
int RegIdx = int(aReg) & int(Reg_e::RegMask);
|
|
CRAY_ASSERT(RegIdx < 8);
|
|
Strm << "A" << DecPrinter(RegIdx);
|
|
return Strm.str();
|
|
}
|
|
case Reg_e::SBase: {
|
|
std::stringstream Strm;
|
|
int RegIdx = int(aReg) & int(Reg_e::RegMask);
|
|
CRAY_ASSERT(RegIdx < 8);
|
|
Strm << "S" << DecPrinter(RegIdx);
|
|
return Strm.str();
|
|
}
|
|
case Reg_e::BBase: {
|
|
std::stringstream Strm;
|
|
int RegIdx = int(aReg) & int(Reg_e::RegMask);
|
|
CRAY_ASSERT(RegIdx < 64);
|
|
Strm << "B" << DecPrinter(RegIdx);
|
|
return Strm.str();
|
|
}
|
|
case Reg_e::TBase: {
|
|
std::stringstream Strm;
|
|
int RegIdx = int(aReg) & int(Reg_e::RegMask);
|
|
CRAY_ASSERT(RegIdx < 64);
|
|
Strm << "T" << DecPrinter(RegIdx);
|
|
return Strm.str();
|
|
}
|
|
case Reg_e::SBBase: {
|
|
std::stringstream Strm;
|
|
int RegIdx = int(aReg) & int(Reg_e::RegMask);
|
|
CRAY_ASSERT(RegIdx < 64);
|
|
Strm << "SB" << DecPrinter(RegIdx);
|
|
return Strm.str();
|
|
}
|
|
case Reg_e::STBase: {
|
|
std::stringstream Strm;
|
|
int RegIdx = int(aReg) & int(Reg_e::RegMask);
|
|
CRAY_ASSERT(RegIdx < 64);
|
|
Strm << "ST" << DecPrinter(RegIdx);
|
|
return Strm.str();
|
|
}
|
|
case Reg_e::VBase: {
|
|
std::stringstream Strm;
|
|
int RegIdx = int(aReg) & int(Reg_e::RegMask);
|
|
int VReg = RegIdx / 64;
|
|
RegIdx %= 64;
|
|
Strm << "V" << DecPrinter(VReg) << "[" << DecPrinter(RegIdx) << "]";
|
|
return Strm.str();
|
|
}
|
|
default: CRAY_ASSERT(false);
|
|
}
|
|
throw Generic_x("Invalid register type");
|
|
}
|
|
size_t RegSize(Reg_e aReg) {
|
|
switch (Reg_e(int(aReg) & int(Reg_e::BaseMask))) {
|
|
case Reg_e::Special:
|
|
switch (Reg_e(int(aReg) & int(Reg_e::RegMask))) {
|
|
case Reg_e::P: return IsXMode() ? 24 : 32;
|
|
case Reg_e::VL: return 5;
|
|
case Reg_e::VM: return 64;
|
|
case Reg_e::XP: return 9;
|
|
default: CRAY_ASSERT(false);
|
|
}
|
|
case Reg_e::ABase: return IsXMode() ? 24 : 32;
|
|
case Reg_e::SBase: return 64;
|
|
case Reg_e::BBase: return IsXMode() ? 24 : 32;
|
|
case Reg_e::TBase: return 64;
|
|
case Reg_e::SBBase: return IsXMode() ? 24 : 32;
|
|
case Reg_e::STBase: return 64;
|
|
case Reg_e::VBase: return 64;
|
|
default: CRAY_ASSERT(false);
|
|
}
|
|
throw Generic_x("Invalid register type");
|
|
}
|
|
|
|
struct StateChange_s {
|
|
StateChange_s(Reg_e aReg, CInt_t aVal) : Reg(aReg), Val(aVal) {};
|
|
StateChange_s(Reg_e aReg, CAddr_t aVal) : Reg(aReg), Val(aVal) {};
|
|
StateChange_s(Reg_e aReg, CAddr_t aVal1, CAddr_t aVal2) : Reg(aReg), Val(aVal1), Val2(aVal2) {};
|
|
StateChange_s(size_t aReg, CInt_t aVal) : Reg(Reg_e(aReg)), Val(aVal) {};
|
|
StateChange_s(size_t aReg, CAddr_t aVal) : Reg(Reg_e(aReg)), Val(aVal) {};
|
|
Reg_e Reg;
|
|
CAddr_t Val2;
|
|
CInt_t Val;
|
|
};
|
|
|
|
#ifndef CRAY_TURBO
|
|
void PushHistory(const StateChange_s &aElem) { mHistory.push_back(aElem); }
|
|
#else
|
|
void PushHistory(const StateChange_s &aElem) {}
|
|
#endif
|
|
boost::circular_buffer<StateChange_s> mHistory;
|
|
|
|
struct CpuState_s {
|
|
CpuState_s() {
|
|
for(size_t i=0;i<sizeof(A)/sizeof(A[0]);++i) { A[i] = 0; ALastChange[i] = 0; }
|
|
for(size_t i=0;i<sizeof(B)/sizeof(B[0]);++i) { B[i] = 0; BLastChange[i] = 0; }
|
|
for(size_t i=0;i<sizeof(S)/sizeof(S[0]);++i) { S[i] = 0; SLastChange[i] = 0; }
|
|
for(size_t i=0;i<sizeof(T)/sizeof(T[0]);++i) { T[i] = 0; TLastChange[i] = 0; }
|
|
for (size_t i = 0; i < sizeof(V) / sizeof(V[0]); ++i) { for (size_t j = 0; j < 64; ++j) { V[i][j] = 0; } VLastChange[i] = 0; }
|
|
VL = 0;
|
|
VM = 0;
|
|
ExchangePacketAddress = 0;
|
|
ProgramAddress = 0;
|
|
InstBaseAddr = 0;
|
|
InstLimitAddr = 0;
|
|
DataBaseAddr = 0;
|
|
DataLimitAddr = 0;
|
|
//Mode;
|
|
//Flags;
|
|
PeriodicInterruptLimit = 0;
|
|
PeriodicInterruptCountDown = 0;
|
|
PeriodicInterruptEnabled = false;
|
|
Cluster = 0;
|
|
TestAndSetBlocked = false;
|
|
VectorNotUsed = true;
|
|
EnableSecondVectorLogical = false;
|
|
XmpProgramState = false;
|
|
XmpEnhancedAddressingMode = false;
|
|
AddrMask = std::numeric_limits<CAddr_t>::max();
|
|
XMode = false;
|
|
}
|
|
|
|
// ISA-visible registers
|
|
CAddr_t A[8]; // 8 primary address registers
|
|
uint64_t ALastChange[8];
|
|
CAddr_t B[64]; // 64 address (branch) registers
|
|
uint64_t BLastChange[64];
|
|
|
|
CInt_t S[8]; // 8 primary scalar registers
|
|
uint64_t SLastChange[8];
|
|
CInt_t T[64]; // 64 backup scalar registers
|
|
uint64_t TLastChange[64];
|
|
|
|
CVec_t V[8]; // 8 64-entry vector registers
|
|
uint64_t VLastChange[8];
|
|
uint8_t VL; // vector length register (TODO: this is a 7-bit register) - value of 0100 is the same as 0000, i.e. 0 specifies maximum length as well
|
|
CInt_t VM; // 64-bit vector-mask register
|
|
|
|
// Internal state registers - these might have ISA access to them, but are not used extensively. Using human-readable names here
|
|
uint8_t ExchangePacketAddress; // exchange packet pointer
|
|
CProgramAddr_t ProgramAddress; // instruction pointer
|
|
|
|
CAddr_t InstBaseAddr; // instruction base-address register (TODO: this is an 18-bit register. The lower 4 bits are 0)
|
|
CAddr_t InstLimitAddr; // instruction limit address register (TODO: this is an 18-bit register. The lower 4 bits are 0)
|
|
|
|
CAddr_t DataBaseAddr; // data base-address register (TODO: this is an 18-bit register. The lower 4 bits are 0)
|
|
CAddr_t DataLimitAddr; // data limit address register (TODO: this is an 18-bit register. The lower 4 bits are 0)
|
|
|
|
Mode_c Mode; // mode register
|
|
Flags_c Flags; // interrupt flags register
|
|
Flags_c InterruptMask; // cached interrupt mask
|
|
|
|
uint32_t PeriodicInterruptLimit; // periodic interrupt limit register
|
|
uint32_t PeriodicInterruptCountDown; // periodic interrupt countdown register
|
|
bool PeriodicInterruptEnabled; // enables/disables periodic interrupts
|
|
uint8_t Cluster; // current cluster (actual limits depend on X-MP model 1x, 2x or 4x)
|
|
bool TestAndSetBlocked; // set if the CPU is blocked on a test-and-set operation
|
|
bool VectorNotUsed; // set once a vector instructions is executed. Cleared on reset and potentially though an EP exchange
|
|
bool EnableSecondVectorLogical;
|
|
bool XmpProgramState; // TODO: does it get preserved?
|
|
CVec_t BitMatrix;
|
|
//bool InReset;
|
|
CAddr_t AddrMask;
|
|
bool XMode;
|
|
bool XmpEnhancedAddressingMode;
|
|
} mState;
|
|
|
|
std::vector<CpuState_s> mCallStack;
|
|
|
|
#ifdef COLLECT_PERF
|
|
std::array<uint64_t, mHistSize> mLoadUseHist;
|
|
std::array<uint64_t, mHistSize> mBBHist;
|
|
uint64_t mLastJump;
|
|
uint64_t mJumpsTaken;
|
|
uint64_t mJumpsNotTaken;
|
|
#endif
|
|
|
|
void UpdateJumpStats(bool aTaken) {
|
|
#ifdef COLLECT_PERF
|
|
CRAY_ASSERT(mLastJump <= mCycleCount);
|
|
uint64_t BBLen = mCycleCount - mLastJump;
|
|
CRAY_ASSERT(mBBHist.size() > 0);
|
|
BBLen = std::min(BBLen, uint64_t(mBBHist.size() - 1));
|
|
mBBHist[BBLen]++;
|
|
if (aTaken) {
|
|
++mJumpsTaken;
|
|
} else {
|
|
++mJumpsNotTaken;
|
|
}
|
|
mLastJump = mCycleCount + 1; // Start counting from the following cycle
|
|
#endif
|
|
}
|
|
|
|
void UpdateLoadUseStats(uint64_t aLastChange) {
|
|
#ifdef COLLECT_PERF
|
|
CRAY_ASSERT(aLastChange <= mCycleCount);
|
|
aLastChange = mCycleCount - aLastChange;
|
|
CRAY_ASSERT(mLoadUseHist.size() > 0);
|
|
aLastChange = std::min(aLastChange, uint64_t(mLoadUseHist.size()-1));
|
|
mLoadUseHist[aLastChange]++;
|
|
#endif
|
|
}
|
|
|
|
#define RefA0 RefAx_s(0, *this, false, CAddr_t(0))
|
|
#define RefAh RefAx_s(h, *this, true, CAddr_t(0))
|
|
#define RefAi RefAx_s(i, *this, false, CAddr_t(0))
|
|
#define RefAj RefAx_s(j, *this, true, CAddr_t(0))
|
|
#define RefAk RefAx_s(k, *this, true, CAddr_t(1))
|
|
#define RefA0Target RefAx_s(0, *this, false, CAddr_t(0))
|
|
#define RefAhTarget RefAx_s(h, *this, false, CAddr_t(0))
|
|
#define RefAiTarget RefAx_s(i, *this, false, CAddr_t(0))
|
|
#define RefAjTarget RefAx_s(j, *this, false, CAddr_t(0))
|
|
#define RefAkTarget RefAx_s(k, *this, false, CAddr_t(0))
|
|
struct RefAx_s: public FieldFormatter_i {
|
|
RefAx_s(size_t aRegIdx, SoftCpu_c &aParent, bool aHasSpecialValue, CAddr_t aSpecialValue):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent),
|
|
mHasSpecialValue(aHasSpecialValue),
|
|
mSpecialValue(aSpecialValue)
|
|
{}
|
|
RefAx_s &operator=(CAddr_t aValue) {
|
|
aValue &= mParent.GetAddrMask();
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << " (" << DecPrinter(aValue,0) << ")" << std::endl;
|
|
mParent.PushHistory(StateChange_s(int(Reg_e::ABase) + mRegIdx, aValue));
|
|
mParent.mState.A[mRegIdx] = aValue;
|
|
mParent.UpdateLoadUseStats(mParent.mState.ALastChange[mRegIdx]);
|
|
mParent.mState.ALastChange[mRegIdx] = mParent.mCycleCount;
|
|
return *this;
|
|
}
|
|
operator CAddr_t() const { if (mRegIdx == 0 && mHasSpecialValue) return CAddr_t(mSpecialValue); else return mParent.GetAddrMask() & mParent.mState.A[mRegIdx]; }
|
|
virtual void Print(std::ostream &aStream) const { if (mRegIdx == 0 && mHasSpecialValue) aStream << DecPrinter(mSpecialValue,0); else aStream << "A" << DecPrinter(mRegIdx,0); }
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
bool mHasSpecialValue;
|
|
CAddr_t mSpecialValue;
|
|
};
|
|
|
|
#define RefS0 RefSx_s(0, *this, false, 0)
|
|
#define RefSi RefSx_s(i, *this, false, 0)
|
|
#define RefSj RefSx_s(j, *this, true, 0)
|
|
#define RefSk RefSx_s(k, *this, true, 0x8000000000000000ULL)
|
|
#define RefSiTarget RefSx_s(i, *this, false, 0)
|
|
struct RefSx_s: public FieldFormatter_i {
|
|
RefSx_s(size_t aRegIdx, SoftCpu_c &aParent, bool aHasSpecialValue, CInt_t aSpecialValue):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent),
|
|
mHasSpecialValue(aHasSpecialValue),
|
|
mSpecialValue(aSpecialValue)
|
|
{}
|
|
RefSx_s &operator=(CInt_t aValue) {
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << " (" << DecPrinter(aValue, 0) << ")" << std::endl;
|
|
mParent.PushHistory(StateChange_s(int(Reg_e::SBase) + mRegIdx, aValue));
|
|
mParent.mState.S[mRegIdx] = aValue;
|
|
mParent.UpdateLoadUseStats(mParent.mState.SLastChange[mRegIdx]);
|
|
mParent.mState.SLastChange[mRegIdx] = mParent.mCycleCount;
|
|
return *this;
|
|
}
|
|
CInt_t Value() const { if (mRegIdx == 0 && mHasSpecialValue) return mSpecialValue; else return mParent.mState.S[mRegIdx]; }
|
|
operator CInt_t() const { return Value(); }
|
|
// operator CFloat_t() const { return CFloat_t(Value()); }
|
|
virtual void Print(std::ostream &aStream) const {
|
|
if (mRegIdx == 0 && mHasSpecialValue) {
|
|
if (mSpecialValue != 0) aStream << HexPrinter(mSpecialValue); else aStream << "0";
|
|
} else {
|
|
aStream << "S" << DecPrinter(mRegIdx,0);
|
|
}
|
|
}
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
bool mHasSpecialValue;
|
|
CInt_t mSpecialValue;
|
|
};
|
|
|
|
|
|
#define RefBjk RefBjk_s(jk, *this)
|
|
#define RefB(x) RefBjk_s(x, *this)
|
|
#define RefBjkTarget RefBjk_s(jk, *this)
|
|
#define RefBTarget(x) RefBjk_s(x, *this)
|
|
struct RefBjk_s: public FieldFormatter_i {
|
|
RefBjk_s(size_t aRegIdx, SoftCpu_c &aParent):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent)
|
|
{}
|
|
RefBjk_s &operator=(CAddr_t aValue) {
|
|
aValue &= mParent.GetAddrMask();
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << " (" << DecPrinter(aValue, 0) << ")" << std::endl;
|
|
mParent.PushHistory(StateChange_s(int(Reg_e::BBase) + mRegIdx, aValue));
|
|
mParent.mState.B[mRegIdx] = aValue;
|
|
mParent.UpdateLoadUseStats(mParent.mState.BLastChange[mRegIdx]);
|
|
mParent.mState.BLastChange[mRegIdx] = mParent.mCycleCount;
|
|
return *this;
|
|
}
|
|
operator CAddr_t() const { return mParent.GetAddrMask() & mParent.mState.B[mRegIdx]; }
|
|
virtual void Print(std::ostream &aStream) const { aStream << "B" << DecPrinter(mRegIdx, 0); }
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
#define RefTjk RefTjk_s(jk, *this)
|
|
#define RefT(x) RefTjk_s(x, *this)
|
|
#define RefTjkTarget RefTjk_s(jk, *this)
|
|
#define RefTTarget(x) RefTjk_s(x, *this)
|
|
struct RefTjk_s: public FieldFormatter_i {
|
|
RefTjk_s(size_t aRegIdx, SoftCpu_c &aParent):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent)
|
|
{}
|
|
RefTjk_s &operator=(CInt_t aValue) {
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << " (" << DecPrinter(aValue, 0) << ")" << std::endl;
|
|
mParent.PushHistory(StateChange_s(int(Reg_e::TBase) + mRegIdx, aValue));
|
|
mParent.mState.T[mRegIdx] = aValue;
|
|
mParent.UpdateLoadUseStats(mParent.mState.TLastChange[mRegIdx]);
|
|
mParent.mState.TLastChange[mRegIdx] = mParent.mCycleCount;
|
|
return *this;
|
|
}
|
|
operator CInt_t() const { return mParent.mState.T[mRegIdx]; }
|
|
virtual void Print(std::ostream &aStream) const { aStream << "T" << DecPrinter(mRegIdx,0); }
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
#define RefSBj RefSBj_s(j, *this)
|
|
#define RefSBjTarget RefSBj_s(j, *this)
|
|
struct RefSBj_s: public FieldFormatter_i {
|
|
RefSBj_s(size_t aRegIdx, SoftCpu_c &aParent):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent)
|
|
{}
|
|
RefSBj_s &operator=(CAddr_t aValue) {
|
|
aValue &= mParent.GetAddrMask();
|
|
CRAY_ASSERT(mParent.mState.Cluster > 0);
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << " (" << DecPrinter(aValue, 0) << ")" << std::endl;
|
|
mParent.PushHistory(StateChange_s(int(Reg_e::SBBase) + mRegIdx, aValue));
|
|
mParent.mMainframe.GetCluster(mParent.mState.Cluster-1).SB[mRegIdx] = aValue;
|
|
return *this;
|
|
}
|
|
operator CAddr_t() const { CRAY_ASSERT(mParent.mState.Cluster > 0); return mParent.GetAddrMask() & mParent.mMainframe.GetCluster(mParent.mState.Cluster-1).SB[mRegIdx]; }
|
|
virtual void Print(std::ostream &aStream) const { aStream << "SB" << DecPrinter(mRegIdx,0); }
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
#define RefSTj RefSTj_s(j, *this)
|
|
#define RefSTjTarget RefSTj_s(j, *this)
|
|
struct RefSTj_s: public FieldFormatter_i {
|
|
RefSTj_s(size_t aRegIdx, SoftCpu_c &aParent):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent)
|
|
{}
|
|
RefSTj_s &operator=(CInt_t aValue) {
|
|
CRAY_ASSERT(mParent.mState.Cluster > 0);
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << " (" << DecPrinter(aValue, 0) << ")" << std::endl;
|
|
mParent.PushHistory(StateChange_s(int(Reg_e::STBase) + mRegIdx, aValue));
|
|
mParent.mMainframe.GetCluster(mParent.mState.Cluster-1).ST[mRegIdx] = aValue;
|
|
return *this;
|
|
}
|
|
operator CInt_t() const { CRAY_ASSERT(mParent.mState.Cluster > 0); return mParent.mMainframe.GetCluster(mParent.mState.Cluster-1).ST[mRegIdx]; }
|
|
virtual void Print(std::ostream &aStream) const { aStream << "ST" << DecPrinter(mRegIdx,0); }
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
// #define RefSM RefSM_s(*this)
|
|
// #define RefSMTarget RefSM_s(*this)
|
|
// struct RefSM_s: public FieldFormatter_i {
|
|
// RefSM_s(SoftCpu_c &aParent):
|
|
// mParent(aParent)
|
|
// {}
|
|
// RefSM_s &operator=(uint64_t aValue) {
|
|
// CRAY_ASSERT(mParent.mState.Cluster > 0);
|
|
// LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
// if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << " in cluster: " << DecPrinter(mParent.mState.Cluster) << std::endl;
|
|
// auto &Cluster = mParent.mMainframe.GetCluster(mParent.mState.Cluster - 1);
|
|
// for (int i = 0; i < 32; ++i) {
|
|
// Cluster.SM[i].store(GetBit(aValue, 63 - i) != 0));
|
|
// }
|
|
// return *this;
|
|
// }
|
|
// operator uint64_t() const {
|
|
// CRAY_ASSERT(mParent.mState.Cluster > 0);
|
|
// uint64_t RetVal = 0;
|
|
// auto &Cluster = mParent.mMainframe.GetCluster(mParent.mState.Cluster - 1);
|
|
// for (int i = 0; i < 32; ++i) {
|
|
// if (Cluster.SM[i].load()) RetVal |= (1ULL << 32);
|
|
// RetVal <<= 1;
|
|
// }
|
|
// return RetVal;
|
|
// }
|
|
// virtual void Print(std::ostream &aStream) const { aStream << "SM"; }
|
|
// protected:
|
|
// SoftCpu_c &mParent;
|
|
// };
|
|
|
|
#define RefSRj RefSRj_s(j, *this)
|
|
#define RefSRjTarget RefSRj_s(j, *this)
|
|
struct RefSRj_s: public FieldFormatter_i {
|
|
RefSRj_s(size_t aRegIdx, SoftCpu_c &aParent):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent)
|
|
{}
|
|
operator CInt_t() const { return mParent.GetSR(mRegIdx); }
|
|
virtual void Print(std::ostream &aStream) const { aStream << "SR" << DecPrinter(mRegIdx,0); }
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
#define RefVi RefVx_s(i, *this)
|
|
#define RefVj RefVx_s(j, *this)
|
|
#define RefVk RefVx_s(k, *this)
|
|
#define RefViTarget RefVx_s(i, *this)
|
|
#define RefVjTarget RefVx_s(j, *this)
|
|
#define RefVkTarget RefVx_s(k, *this)
|
|
struct RefVx_s: public FieldFormatter_i {
|
|
RefVx_s(size_t aRegIdx, SoftCpu_c &aParent):
|
|
mRegIdx(aRegIdx),
|
|
mParent(aParent)
|
|
{}
|
|
void LogState(const char *aPrefix = nullptr) {
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) {
|
|
LogLine << SideEffectIndent << (aPrefix == nullptr ? "state-change " : aPrefix) << *this << " <== (";
|
|
for (size_t i = 0; i<mParent.mState.V[mRegIdx].size(); ++i) LogLine << (i == 0 ? " " : ", ") << HexPrinter(mParent.mState.V[mRegIdx][i]);
|
|
LogLine << ")" << std::endl;
|
|
}
|
|
mParent.UpdateLoadUseStats(mParent.mState.VLastChange[mRegIdx]);
|
|
mParent.mState.VLastChange[mRegIdx] = mParent.mCycleCount;
|
|
for (size_t i = 0; i < mParent.mState.V[mRegIdx].size(); ++i) {
|
|
mParent.PushHistory(StateChange_s(int(Reg_e::VBase) + mRegIdx * 64 + i, mParent.mState.V[mRegIdx][i]));
|
|
}
|
|
}
|
|
const CInt_t operator [](size_t aIdx) const { return mParent.mState.V[mRegIdx][aIdx]; }
|
|
CInt_t operator [](size_t aIdx) {
|
|
mParent.mState.VectorNotUsed = false;
|
|
return mParent.mState.V[mRegIdx][aIdx];
|
|
}
|
|
virtual void Print(std::ostream &aStream) const {
|
|
aStream << "V" << DecPrinter(mRegIdx,0);
|
|
}
|
|
protected:
|
|
size_t mRegIdx;
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
#define RefBM RefBM_s(*this)
|
|
struct RefBM_s : public FieldFormatter_i {
|
|
RefBM_s(SoftCpu_c &aParent):
|
|
mParent(aParent)
|
|
{}
|
|
void LogState(const char *aPrefix = nullptr) {
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) {
|
|
LogLine << SideEffectIndent << (aPrefix == nullptr ? "state-change " : aPrefix) << *this << " <== (";
|
|
for (size_t i = 0; i<mParent.mState.BitMatrix.size(); ++i) LogLine << (i == 0 ? " " : ", ") << HexPrinter(mParent.mState.BitMatrix[i]);
|
|
LogLine << ")" << std::endl;
|
|
}
|
|
}
|
|
const CInt_t operator [](size_t aIdx) const { return mParent.mState.BitMatrix[aIdx]; }
|
|
CInt_t operator [](size_t aIdx) {
|
|
mParent.mState.VectorNotUsed = false;
|
|
return mParent.mState.BitMatrix[aIdx];
|
|
}
|
|
virtual void Print(std::ostream &aStream) const {
|
|
aStream << "BM";
|
|
}
|
|
protected:
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
#define RefVM RefVM_s(*this)
|
|
struct RefVM_s: public FieldFormatter_i {
|
|
RefVM_s(SoftCpu_c &aParent):
|
|
mParent(aParent)
|
|
{}
|
|
RefVM_s &operator=(CInt_t aValue) {
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << HexPrinter(aValue) << std::endl;
|
|
mParent.mState.VM = aValue;
|
|
mParent.mState.VectorNotUsed = false;
|
|
return *this;
|
|
}
|
|
operator CInt_t() const { return mParent.mState.VM; }
|
|
virtual void Print(std::ostream &aStream) const {
|
|
aStream << "VM";
|
|
}
|
|
protected:
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
#define RefVL RefVL_s(*this)
|
|
struct RefVL_s: public FieldFormatter_i {
|
|
RefVL_s(SoftCpu_c &aParent):
|
|
mParent(aParent)
|
|
{}
|
|
RefVL_s &operator=(uint8_t aValue) {
|
|
LogLine_c LogLine = mParent.mLogger << setloglevel(LogLevel_SideEffects);
|
|
if (LogLine.good()) LogLine << SideEffectIndent << "state-change " << *this << " <== " << DecPrinter(aValue, 0) << std::endl;
|
|
mParent.mState.VL = aValue;
|
|
return *this;
|
|
}
|
|
operator uint8_t() const { return mParent.mState.VL; }
|
|
virtual void Print(std::ostream &aStream) const {
|
|
aStream << "VL";
|
|
}
|
|
protected:
|
|
SoftCpu_c &mParent;
|
|
};
|
|
|
|
size_t mInstructionBurstSize;
|
|
|
|
uint64_t mCycleCount;
|
|
|
|
ExchangePacket_c CreateExchangePacket(); // Creates an exchange packet from the current state of the CPU
|
|
void RestoreFromExchangePacket(const ExchangePacket_c &aEP); // Restores state from the specified exchange packet
|
|
bool SingleStep();
|
|
bool CheckInterrupts();
|
|
void HandleCounters();
|
|
|
|
std::string ReportHist() const;
|
|
|
|
// These routines use IBA and DBA offsets, checks for out-of-boundary conditions and raise exceptions on failures
|
|
struct InstFetchOutOfBoundsError_x: public Generic_x { InstFetchOutOfBoundsError_x(): Generic_x("Instruction fetch out of bounds") {} };
|
|
struct DataReadOutOfBoundsError_x: public Generic_x { DataReadOutOfBoundsError_x() : Generic_x("Data read out of bounds") {} };
|
|
struct DataWriteOutOfBoundsError_x: public Generic_x { DataWriteOutOfBoundsError_x() : Generic_x("Data write out of bounds") {} };
|
|
struct InstDecodeError_x : public Generic_x { InstDecodeError_x() : Generic_x("Instruction decode error") {} };
|
|
struct UnknownInstError_x : public Generic_x { UnknownInstError_x(const char *aFile, size_t aLine) : Generic_x("Unknown instruction error at") { *this << aFile << ":" << DecPrinter(aLine, 0); } };
|
|
struct TerminateInstError_x : public Generic_x { TerminateInstError_x() : Generic_x("Terminate instruction executed") {} };
|
|
struct InstExecError_x : public Generic_x { InstExecError_x() : Generic_x("Instruction execution error") {} };
|
|
struct InstUnimplementedError_x : public Generic_x { InstUnimplementedError_x(const char *aFile, size_t aLine) { *this << "Unimplemented instruction at " << aFile << ":" << DecPrinter(aLine, 0); ResetSpacePrinted(); } };
|
|
|
|
CInt_t ReadDataMem(CAddr_t aAddr);
|
|
void WriteDataMem(CAddr_t aAddr, CAddr_t aData) { WriteDataMem(aAddr, CInt_t(ZeroExtend(aData))); }
|
|
#ifndef CRAY_TURBO
|
|
virtual void WriteDataMem(CAddr_t aAddr, CInt_t aData);
|
|
#else
|
|
void WriteDataMem(CAddr_t aAddr, CInt_t aData);
|
|
#endif // CRAY_TURBO
|
|
virtual ExchangePacket_c ReadExchangePacket(CAddr_t aMemAddr);
|
|
virtual void WriteExchangePacket(const ExchangePacket_c &aExchangePacket, CAddr_t aMemAddr);
|
|
|
|
struct InstMemRead_s {
|
|
uint64_t Data;
|
|
size_t Size;
|
|
};
|
|
InstMemRead_s ReadInstMem(CProgramAddr_t aAddr);
|
|
|
|
template <bool aDoExecute> size_t Decode(
|
|
uint64_t aParcels,
|
|
size_t aMaxParcelCnt,
|
|
std::ostream &aDisassembly,
|
|
std::ostream &aExplanation,
|
|
bool &aBreakBurst
|
|
); // Returns the increment to the ProgramAddress. Might throw all sorts of memory access exceptions, or even InstFetchOutOfBoundsError_x if aIsSecondParcelValid == false
|
|
|
|
template <bool aDoExecute> size_t Decode0000(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0001(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0002(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0003(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0004(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0005(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0006(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0007(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0010(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0011(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0012(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0013(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0014(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0015(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0016(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0017(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0020(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0021(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0022(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0023(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0024(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0025(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0026(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0027(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0030(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0031(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0032(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0033(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0034(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0035(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0036(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0037(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0040(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0041(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0042(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0043(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0044(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0045(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0046(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0047(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0050(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0051(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0052(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0053(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0054(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0055(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0056(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0057(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0060(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0061(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0062(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0063(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0064(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0065(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0066(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0067(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0070(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0071(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0072(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0073(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0074(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0075(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0076(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0077(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode010x(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode011x(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode012x(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode013x(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0140(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0141(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0142(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0143(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0144(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0145(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0146(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0147(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0150(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0151(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0152(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0153(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0154(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0155(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0156(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0157(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0160(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0161(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0162(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0163(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0164(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0165(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0166(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0167(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
template <bool aDoExecute> size_t Decode0170(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0171(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0172(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0173(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0174(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0175(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0176(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
template <bool aDoExecute> size_t Decode0177(uint64_t aParcels, size_t aMaxParcelCnt, std::ostream &aDisassembly, std::ostream &aExplanation, bool &aBreakBurst);
|
|
|
|
typedef size_t (SoftCpu_c::* InstImplementation)(
|
|
uint64_t aParcels,
|
|
size_t aMaxParcelCnt,
|
|
std::ostream &aDisassembly,
|
|
std::ostream &aExplanation,
|
|
bool &aBreakBurst
|
|
);
|
|
static const struct InstImplementation_s {
|
|
InstImplementation Exec, Disasm;
|
|
} mInstImplementations[];
|
|
|
|
|
|
static CAddr_t PopulationCnt(CInt_t aS) {
|
|
CInt_t Mask = 1;
|
|
CAddr_t RetVal = CAddr_t(0);
|
|
for(int i=0;i<64;++i) {
|
|
if ((aS & Mask) != 0) ++RetVal;
|
|
Mask <<= 1;
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
static CAddr_t PopulationCntParity(CInt_t aS) {
|
|
return PopulationCnt(aS) & CAddr_t(1);
|
|
}
|
|
|
|
static CAddr_t LeadingZeroCnt(CInt_t aS) {
|
|
CInt_t Mask = 0x8000000000000000ULL;
|
|
CAddr_t RetVal(0);
|
|
for(int i=0;i<64;++i) {
|
|
if ((aS & Mask) != 0) return RetVal;
|
|
++RetVal;
|
|
Mask >>= 1;
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
static CInt_t ShiftRight(CInt_t aValue, CAddr_t aAmount) {
|
|
if (aAmount >= CAddr_t(64)) return 0;
|
|
return ((uint64_t)aValue) >> size_t(aAmount);
|
|
}
|
|
static CInt_t ShiftLeft(CInt_t aValue, CAddr_t aAmount) {
|
|
if (aAmount >= CAddr_t(64)) return 0;
|
|
return aValue << size_t(aAmount);
|
|
}
|
|
static CInt_t DoubleShiftRight(CInt_t aFirst, CInt_t aSecond, CAddr_t aAmount) {
|
|
if (aAmount >= CAddr_t(128)) return 0;
|
|
if (aAmount >= CAddr_t(64)) return ((uint64_t)aFirst >> (size_t(aAmount)-64));
|
|
if (aAmount == CAddr_t(0)) return aSecond;
|
|
return ((uint64_t)aSecond >> size_t(aAmount)) | (aFirst << (64-size_t(aAmount)));
|
|
}
|
|
|
|
static CInt_t DoubleShiftLeft(CInt_t aFirst, CInt_t aSecond, CAddr_t aAmount) {
|
|
if (aAmount >= CAddr_t(128)) return 0;
|
|
if (aAmount >= CAddr_t(64)) return (aSecond << (size_t(aAmount)-64));
|
|
if (aAmount == CAddr_t(0)) return aFirst;
|
|
return (aFirst << size_t(aAmount)) | ((uint64_t)aSecond >> (64-size_t(aAmount)));
|
|
}
|
|
|
|
static std::string CodeSymbol(CAddr_t aBaseAddr, CProgramAddr_t aProgAddr) {
|
|
std::stringstream StrStrm;
|
|
StrStrm << HexPrinter(aProgAddr / 4 + aBaseAddr) << ":p" << DecPrinter(aProgAddr % 4);
|
|
return StrStrm.str();
|
|
}
|
|
|
|
static std::string DataSymbol(CAddr_t aBaseAddr, CAddr_t aAddr) {
|
|
std::stringstream StrStrm;
|
|
StrStrm << HexPrinter(aAddr);
|
|
return StrStrm.str();
|
|
}
|
|
};
|
|
|