Add assignment of structs from and to striped arrays

This commit is contained in:
drmortalwombat 2022-11-29 18:11:42 +01:00
parent 02e4d4bd1b
commit bfe6311ca4
7 changed files with 184 additions and 56 deletions

View File

@ -3640,7 +3640,17 @@ void InterInstruction::Disassemble(FILE* file)
fprintf(file, "LOAD%c%d", memchars[mSrc[0].mMemory], mSrc[0].mOperandSize); fprintf(file, "LOAD%c%d", memchars[mSrc[0].mMemory], mSrc[0].mOperandSize);
break; break;
case IC_COPY: case IC_COPY:
fprintf(file, "COPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); if (mSrc[1].mStride != 1)
{
if (mSrc[0].mStride != 1)
fprintf(file, "COPY%c%d%c%d", memchars[mSrc[0].mMemory], mSrc[0].mStride, memchars[mSrc[1].mMemory], mSrc[1].mStride);
else
fprintf(file, "COPY%c%c%d", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory], mSrc[1].mStride);
}
else if (mSrc[0].mStride != 1)
fprintf(file, "COPY%c%d%c", memchars[mSrc[0].mMemory], mSrc[0].mStride, memchars[mSrc[1].mMemory]);
else
fprintf(file, "COPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]);
break; break;
case IC_STRCPY: case IC_STRCPY:
fprintf(file, "STRCPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); fprintf(file, "STRCPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]);

View File

@ -1019,11 +1019,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
ins->mSrc[0].mType = IT_POINTER; ins->mSrc[0].mType = IT_POINTER;
ins->mSrc[0].mTemp = vr.mTemp; ins->mSrc[0].mTemp = vr.mTemp;
ins->mSrc[0].mMemory = IM_INDIRECT; ins->mSrc[0].mMemory = IM_INDIRECT;
ins->mSrc[0].mOperandSize = vl.mType->mSize;
ins->mSrc[0].mStride = vr.mType->mStripe;
ins->mSrc[1].mType = IT_POINTER; ins->mSrc[1].mType = IT_POINTER;
ins->mSrc[1].mTemp = vl.mTemp; ins->mSrc[1].mTemp = vl.mTemp;
ins->mSrc[1].mMemory = IM_INDIRECT; ins->mSrc[1].mMemory = IM_INDIRECT;
ins->mSrc[0].mOperandSize = vl.mType->mSize;
ins->mSrc[1].mOperandSize = vl.mType->mSize; ins->mSrc[1].mOperandSize = vl.mType->mSize;
ins->mSrc[1].mStride = vl.mType->mStripe;
ins->mConst.mOperandSize = vl.mType->mSize; ins->mConst.mOperandSize = vl.mType->mSize;
block->Append(ins); block->Append(ins);
} }
@ -2115,14 +2118,18 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
if (vp.mTemp != vr.mTemp) if (vp.mTemp != vr.mTemp)
{ {
InterInstruction* cins = new InterInstruction(exp->mLocation, IC_COPY); InterInstruction* cins = new InterInstruction(exp->mLocation, IC_COPY);
cins->mSrc[0].mType = IT_POINTER; cins->mSrc[0].mType = IT_POINTER;
cins->mSrc[0].mTemp = vr.mTemp; cins->mSrc[0].mTemp = vr.mTemp;
cins->mSrc[0].mMemory = IM_INDIRECT; cins->mSrc[0].mMemory = IM_INDIRECT;
cins->mSrc[0].mOperandSize = vr.mType->mSize;
cins->mSrc[0].mStride = vr.mType->mStripe;
cins->mSrc[1].mType = IT_POINTER; cins->mSrc[1].mType = IT_POINTER;
cins->mSrc[1].mTemp = ains->mDst.mTemp; cins->mSrc[1].mTemp = ains->mDst.mTemp;
cins->mSrc[1].mMemory = IM_INDIRECT; cins->mSrc[1].mMemory = IM_INDIRECT;
cins->mSrc[0].mOperandSize = vr.mType->mSize;
cins->mSrc[1].mOperandSize = vr.mType->mSize; cins->mSrc[1].mOperandSize = vr.mType->mSize;
cins->mConst.mOperandSize = vr.mType->mSize; cins->mConst.mOperandSize = vr.mType->mSize;
block->Append(cins); block->Append(cins);
} }
@ -2374,11 +2381,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
cins->mSrc[0].mType = IT_POINTER; cins->mSrc[0].mType = IT_POINTER;
cins->mSrc[0].mTemp = vr.mTemp; cins->mSrc[0].mTemp = vr.mTemp;
cins->mSrc[0].mMemory = IM_INDIRECT; cins->mSrc[0].mMemory = IM_INDIRECT;
cins->mSrc[0].mOperandSize = vr.mType->mSize;
cins->mSrc[0].mStride = vr.mType->mStripe;
cins->mSrc[1].mOperandSize = vr.mType->mSize;
cins->mSrc[1].mType = IT_POINTER; cins->mSrc[1].mType = IT_POINTER;
cins->mSrc[1].mTemp = ains->mDst.mTemp; cins->mSrc[1].mTemp = ains->mDst.mTemp;
cins->mSrc[1].mMemory = IM_INDIRECT; cins->mSrc[1].mMemory = IM_INDIRECT;
cins->mSrc[0].mOperandSize = vr.mType->mSize;
cins->mSrc[1].mOperandSize = vr.mType->mSize;
cins->mConst.mOperandSize = vr.mType->mSize; cins->mConst.mOperandSize = vr.mType->mSize;
block->Append(cins); block->Append(cins);
} }
@ -2636,11 +2646,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
cins->mSrc[0].mType = IT_POINTER; cins->mSrc[0].mType = IT_POINTER;
cins->mSrc[0].mTemp = vr.mTemp; cins->mSrc[0].mTemp = vr.mTemp;
cins->mSrc[0].mMemory = IM_INDIRECT; cins->mSrc[0].mMemory = IM_INDIRECT;
cins->mSrc[0].mOperandSize = vr.mType->mSize;
cins->mSrc[0].mStride = vr.mType->mStripe;
cins->mSrc[1].mOperandSize = vr.mType->mSize;
cins->mSrc[1].mType = IT_POINTER; cins->mSrc[1].mType = IT_POINTER;
cins->mSrc[1].mTemp = ains->mDst.mTemp; cins->mSrc[1].mTemp = ains->mDst.mTemp;
cins->mSrc[1].mMemory = IM_INDIRECT; cins->mSrc[1].mMemory = IM_INDIRECT;
cins->mSrc[0].mOperandSize = vr.mType->mSize;
cins->mSrc[1].mOperandSize = vr.mType->mSize;
cins->mConst.mOperandSize = vr.mType->mSize; cins->mConst.mOperandSize = vr.mType->mSize;
block->Append(cins); block->Append(cins);
} }

View File

@ -4059,6 +4059,7 @@ void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block)
} }
else else
{ {
assert(mAddress != 0);
block->PutByte(uint8(mAddress)); block->PutByte(uint8(mAddress));
} }
break; break;
@ -5703,11 +5704,9 @@ bool NativeCodeBasicBlock::LoadOpStoreIndirectValue(InterCodeProcedure* proc, co
switch (oins->mOperator) switch (oins->mOperator)
{ {
case IA_ADD: case IA_ADD:
mIns.Push(NativeCodeInstruction(ASMIT_CLC));
at = an = ASMIT_ADC; at = an = ASMIT_ADC;
break; break;
case IA_SUB: case IA_SUB:
mIns.Push(NativeCodeInstruction(ASMIT_SEC));
at = an = ASMIT_SBC; at = an = ASMIT_SBC;
if (oindex == 1) if (oindex == 1)
reverse = true; reverse = true;
@ -5789,10 +5788,29 @@ bool NativeCodeBasicBlock::LoadOpStoreIndirectValue(InterCodeProcedure* proc, co
if (wins->mVolatile) if (wins->mVolatile)
wflags |= NCIF_VOLATILE; wflags |= NCIF_VOLATILE;
if (ram == ASMIM_INDIRECT_Y) if (ram == ASMIM_INDIRECT_Y && wam == ASMIM_INDIRECT_Y && rareg == wareg && rindex == windex)
{
CheckFrameIndex(rareg, rindex, size, BC_REG_ADDR); CheckFrameIndex(rareg, rindex, size, BC_REG_ADDR);
if (wam == ASMIM_INDIRECT_Y) windex = rindex;
CheckFrameIndex(wareg, windex, size, BC_REG_ACCU); wareg = rareg;
}
else
{
if (ram == ASMIM_INDIRECT_Y)
CheckFrameIndex(rareg, rindex, size, BC_REG_ADDR);
if (wam == ASMIM_INDIRECT_Y)
CheckFrameIndex(wareg, windex, size, BC_REG_ACCU);
}
switch (oins->mOperator)
{
case IA_ADD:
mIns.Push(NativeCodeInstruction(ASMIT_CLC));
break;
case IA_SUB:
mIns.Push(NativeCodeInstruction(ASMIT_SEC));
break;
}
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
@ -6347,13 +6365,15 @@ void NativeCodeBasicBlock::LoadValue(InterCodeProcedure* proc, const InterInstru
NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc) NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc)
{ {
int size = ins->mConst.mOperandSize; int size = ins->mConst.mOperandSize;
int msize = 4; int msize = 4, dstride = ins->mSrc[1].mStride, sstride = ins->mSrc[0].mStride;
uint32 flags = NCIF_LOWER | NCIF_UPPER; uint32 flags = NCIF_LOWER | NCIF_UPPER;
if (ins->mVolatile) if (ins->mVolatile)
flags |= NCIF_VOLATILE; flags |= NCIF_VOLATILE;
if (nproc->mGenerator->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) if (sstride > 1 || dstride > 1)
msize = 32;
else if (nproc->mGenerator->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
msize = 8; msize = 8;
else if (nproc->mGenerator->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) else if (nproc->mGenerator->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
msize = 2; msize = 2;
@ -6371,8 +6391,8 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc,
{ {
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index + i * dstride));
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i, ins->mSrc[0].mLinkerObject, flags)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i * sstride, ins->mSrc[0].mLinkerObject, flags));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, areg, nullptr, flags));
} }
@ -6462,8 +6482,8 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc,
{ {
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + offset + i, ins->mSrc[0].mLinkerObject, flags)); block->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + offset + i * sstride, ins->mSrc[0].mLinkerObject, flags));
block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i, ins->mSrc[1].mLinkerObject, flags)); block->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags));
} }
} }
else else
@ -6563,7 +6583,7 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc,
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 1));
dreg = BC_REG_ADDR; dreg = BC_REG_ADDR;
} }
else if (ins->mSrc[1].mMemory == IM_FPARAM) else if (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)
{ {
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ADDR + 0));
@ -6618,8 +6638,9 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc,
{ {
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, i)); mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, i * sstride));
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, sreg));
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, i* dstride));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, dreg));
} }
@ -16844,7 +16865,7 @@ bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) cons
#endif #endif
} }
bool NativeCodeBasicBlock::CheckGlobalAddressSumYPointer(const NativeCodeBasicBlock * block, int reg, int at, int yval) bool NativeCodeBasicBlock::CheckGlobalAddressSumYPointer(const NativeCodeBasicBlock * block, int reg, int index, int at, int yval)
{ {
if (!mPatched) if (!mPatched)
{ {
@ -16870,8 +16891,16 @@ bool NativeCodeBasicBlock::CheckGlobalAddressSumYPointer(const NativeCodeBasicBl
{ {
NativeCodeInstruction& ins(mIns[at]); NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1)) if (ins.mMode == ASMIM_ZERO_PAGE)
return false; {
if (ins.mAddress == index && ins.ChangesAddress())
return false;
else if (ins.mAddress == reg || ins.mAddress == reg + 1)
{
if (ins.ChangesAddress() || reg == index)
return false;
}
}
else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg) else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{ {
if (yval < 0) if (yval < 0)
@ -16891,7 +16920,7 @@ bool NativeCodeBasicBlock::CheckGlobalAddressSumYPointer(const NativeCodeBasicBl
yval = (yval - 1) & 255; yval = (yval - 1) & 255;
else if (ins.mType == ASMIT_JSR) else if (ins.mType == ASMIT_JSR)
{ {
if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1)) if (ins.UsesZeroPage(reg) || ins.UsesZeroPage(reg + 1) || ins.ChangesZeroPage(index))
return false; return false;
yval = -1; yval = -1;
} }
@ -16901,16 +16930,16 @@ bool NativeCodeBasicBlock::CheckGlobalAddressSumYPointer(const NativeCodeBasicBl
at++; at++;
} }
if (mTrueJump && !mTrueJump->CheckGlobalAddressSumYPointer(block, reg, 0, yval)) if (mTrueJump && !mTrueJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval))
return false; return false;
if (mFalseJump && !mFalseJump->CheckGlobalAddressSumYPointer(block, reg, 0, yval)) if (mFalseJump && !mFalseJump->CheckGlobalAddressSumYPointer(block, reg, index, 0, yval))
return false; return false;
} }
return true; return true;
} }
bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int at, int yval, LinkerObject* lobj, int address) bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int index, int at, int yval, LinkerObject* lobj, int address)
{ {
bool changed = false; bool changed = false;
@ -16924,7 +16953,7 @@ bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBl
{ {
NativeCodeInstruction& ins(mIns[at]); NativeCodeInstruction& ins(mIns[at]);
assert(!(ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1))); assert(!(ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == reg + 1) && reg == index));
if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg) if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{ {
@ -16937,7 +16966,7 @@ bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBl
ins.mAddress = address + yval; ins.mAddress = address + yval;
if (ins.mLive & LIVE_CPU_REG_Y) if (ins.mLive & LIVE_CPU_REG_Y)
mIns.Insert(at + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yval)); mIns.Insert(at + 1, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, yval));
mIns.Insert(at, NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, reg)); mIns.Insert(at, NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, index));
at++; at++;
changed = true; changed = true;
@ -16953,13 +16982,41 @@ bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBl
yval = (yval - 1) & 255; yval = (yval - 1) & 255;
else if (ins.ChangesYReg()) else if (ins.ChangesYReg())
yval = -1; yval = -1;
else if (at + 6 < mIns.Size() &&
mIns[at + 0].mType == ASMIT_CLC &&
mIns[at + 1].mType == ASMIT_LDA && mIns[at + 1].mMode == ASMIM_ZERO_PAGE && mIns[at + 1].mAddress == reg + 0 &&
mIns[at + 2].mType == ASMIT_ADC && mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 4].mType == ASMIT_LDA && mIns[at + 4].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mAddress == reg + 1 &&
mIns[at + 5].mType == ASMIT_ADC && mIns[at + 5].mMode == ASMIM_IMMEDIATE &&
mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE)
{
int add = mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress;
mIns[at + 1].mAddress = index;
mIns[at + 2].mMode = ASMIM_IMMEDIATE_ADDRESS;
mIns[at + 2].mLinkerObject = lobj;
mIns[at + 2].mAddress = address + add;
mIns[at + 2].mFlags = NCIF_LOWER;
mIns[at + 4].mMode = ASMIM_IMMEDIATE;
mIns[at + 4].mAddress = 0;
mIns[at + 5].mMode = ASMIM_IMMEDIATE_ADDRESS;
mIns[at + 5].mLinkerObject = lobj;
mIns[at + 5].mAddress = address + add;
mIns[at + 5].mFlags = NCIF_UPPER;
changed = true;
}
at++; at++;
} }
if (mTrueJump && mTrueJump->PatchGlobalAddressSumYPointer(block, reg, 0, yval, lobj, address)) if (mTrueJump && mTrueJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address))
changed = true; changed = true;
if (mFalseJump && mFalseJump->PatchGlobalAddressSumYPointer(block, reg, 0, yval, lobj, address)) if (mFalseJump && mFalseJump->PatchGlobalAddressSumYPointer(block, reg, index, 0, yval, lobj, address))
changed = true; changed = true;
} }
@ -23968,7 +24025,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc, int xen
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{ {
mIns[j + 0].mType = ASMIT_LDX; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0] = NativeCodeInstruction(ASMIT_LDX, mIns[i + 1]);
mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED; mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress; mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress;
j += 3; j += 3;
@ -23981,7 +24038,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc, int xen
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X)))
{ {
mIns[j + 0].mType = ASMIT_LDX; mIns[j + 0].mMode = ASMIM_ZERO_PAGE; mIns[j + 0].mAddress = mIns[i + 1].mAddress; mIns[j + 0] = NativeCodeInstruction(ASMIT_LDX, mIns[i + 1]);
mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED; mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED;
mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress; mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress;
j += 3; j += 3;
@ -26361,6 +26418,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 0].mType = ASMIT_LDA; mIns[i + 0].mType = ASMIT_LDA;
progress = true; progress = true;
} }
else if (mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS &&
mIns[i + 1].mType == ASMIT_INX)
{
if (mIns[i + 0].mFlags & NCIF_UPPER)
mIns[i + 0].mAddress += 0x100;
else
mIns[i + 0].mAddress++;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
progress = true;
}
#if 0 #if 0
else if ( else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
@ -26904,6 +26971,21 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 1].mLive |= LIVE_CPU_REG_C; mIns[i + 1].mLive |= LIVE_CPU_REG_C;
progress = true; progress = true;
} }
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
if (mIns[i + 1].mFlags & NCIF_UPPER)
mIns[i + 1].mAddress += 0x0100 * mIns[i + 2].mAddress;
else
mIns[i + 1].mAddress += mIns[i + 2].mAddress;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
progress = true;
}
else if ( else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
@ -27934,6 +28016,17 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 3].mAddress = mIns[i + 0].mAddress; mIns[i + 3].mAddress = mIns[i + 0].mAddress;
mIns[i + 3].mLinkerObject = mIns[i + 0].mLinkerObject; mIns[i + 3].mLinkerObject = mIns[i + 0].mLinkerObject;
mIns[i + 3].mFlags = mIns[i + 0].mFlags; mIns[i + 3].mFlags = mIns[i + 0].mFlags;
if (mIns[i + 3].RequiresYReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
}
if (mIns[i + 3].RequiresXReg())
{
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mLive |= LIVE_CPU_REG_X;
}
progress = true; progress = true;
} }
else if ( else if (
@ -28400,7 +28493,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_X &&
mIns[i + 3].mType == ASMIT_LDX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z))) mIns[i + 3].mType == ASMIT_LDX && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
{ {
mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y; mIns[i + 1].mType = ASMIT_LDY; mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_Y; mIns[i + 2].mLive |= LIVE_CPU_REG_X; mIns[i + 2].mMode = ASMIM_ABSOLUTE_Y; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
@ -28418,7 +28511,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ABSOLUTE_Y &&
mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z))) mIns[i + 3].mType == ASMIT_LDY && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & (LIVE_CPU_REG_X | LIVE_CPU_REG_Z)))
{ {
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X; mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mMode = ASMIM_ABSOLUTE_X; mIns[i + 2].mLive |= LIVE_CPU_REG_Y; mIns[i + 2].mMode = ASMIM_ABSOLUTE_X; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
@ -29091,7 +29184,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
!(mIns[i + 5].mLive & LIVE_CPU_REG_A)) !(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{ {
proc->ResetPatched(); proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, i + 6, -1)) if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
{ {
assert(mIns[i + 3].mAddress == mIns[i + 1].mAddress); assert(mIns[i + 3].mAddress == mIns[i + 1].mAddress);
@ -29102,7 +29195,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED; mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
proc->ResetPatched(); proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, i + 6, -1, mIns[i + 3].mLinkerObject, mIns[i + 3].mAddress)) if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, mIns[i + 3].mLinkerObject, mIns[i + 3].mAddress))
progress = true; progress = true;
} }
} }
@ -29118,14 +29211,14 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
!(mIns[i + 5].mLive & LIVE_CPU_REG_A)) !(mIns[i + 5].mLive & LIVE_CPU_REG_A))
{ {
proc->ResetPatched(); proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, i + 6, -1)) if (CheckGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1))
{ {
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED; mIns[i + 5].mType = ASMIT_NOP; mIns[i + 5].mMode = ASMIM_IMPLIED;
proc->ResetPatched(); proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, i + 6, -1, nullptr, 256 * mIns[i + 3].mAddress)) if (PatchGlobalAddressSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, i + 6, -1, nullptr, 256 * mIns[i + 3].mAddress))
progress = true; progress = true;
} }
} }
@ -29139,13 +29232,13 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
!(mIns[i + 2].mLive & LIVE_CPU_REG_A)) !(mIns[i + 2].mLive & LIVE_CPU_REG_A))
{ {
proc->ResetPatched(); proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, i + 3, -1)) if (CheckGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, mIns[i + 0].mAddress, i + 3, -1))
{ {
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
proc->ResetPatched(); proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, i + 3, -1, nullptr, 256 * mIns[i + 1].mAddress)) if (PatchGlobalAddressSumYPointer(this, mIns[i + 0].mAddress, mIns[i + 0].mAddress, i + 3, -1, nullptr, 256 * mIns[i + 1].mAddress))
progress = true; progress = true;
} }
} }
@ -29224,9 +29317,8 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 && mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 &&
!(mIns[i + 6].mLive & LIVE_CPU_REG_A)) !(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{ {
int reg = mIns[i + 3].mAddress;
proc->ResetPatched(); proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, i + 7, -1)) if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
{ {
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
@ -29236,9 +29328,19 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED; mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
proc->ResetPatched(); proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, i + 7, -1, mIns[i + 1].mLinkerObject, mIns[i + 1].mAddress)) if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, mIns[i + 1].mLinkerObject, mIns[i + 1].mAddress))
progress = true; progress = true;
} }
else if (mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 3].mAddress)
{
proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, i + 7, -1))
{
proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, i + 7, -1, mIns[i + 1].mLinkerObject, mIns[i + 1].mAddress))
progress = true;
}
}
} }
#endif #endif
@ -29254,7 +29356,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
!(mIns[i + 6].mLive & LIVE_CPU_REG_A)) !(mIns[i + 6].mLive & LIVE_CPU_REG_A))
{ {
proc->ResetPatched(); proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, i + 7, -1)) if (CheckGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1))
{ {
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
@ -29264,7 +29366,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED; mIns[i + 6].mType = ASMIT_NOP; mIns[i + 6].mMode = ASMIM_IMPLIED;
proc->ResetPatched(); proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, i + 7, -1, nullptr, mIns[i + 1].mAddress + 256 * mIns[i + 4].mAddress)) if (PatchGlobalAddressSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, i + 7, -1, nullptr, mIns[i + 1].mAddress + 256 * mIns[i + 4].mAddress))
progress = true; progress = true;
} }
} }
@ -29969,6 +30071,9 @@ void NativeCodeBasicBlock::CheckLive(void)
{ {
assert(mIns[j].mType != ASMIT_INV); assert(mIns[j].mType != ASMIT_INV);
if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ZERO_PAGE)
assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0);
if (mIns[j].mType != ASMIT_NOP) if (mIns[j].mType != ASMIT_NOP)
{ {
assert(!(live & ~mIns[j].mLive)); assert(!(live & ~mIns[j].mLive));

View File

@ -449,8 +449,8 @@ public:
bool CheckPatchFailReg(const NativeCodeBasicBlock* block, int reg); bool CheckPatchFailReg(const NativeCodeBasicBlock* block, int reg);
bool CheckPatchFailUse(void); bool CheckPatchFailUse(void);
bool CheckGlobalAddressSumYPointer(const NativeCodeBasicBlock * block, int reg, int at, int yval); bool CheckGlobalAddressSumYPointer(const NativeCodeBasicBlock * block, int reg, int index, int at, int yval);
bool PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int at, int yval, LinkerObject * lobj, int address); bool PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int index, int at, int yval, LinkerObject * lobj, int address);
bool CheckSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains, int cycles); bool CheckSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains, int cycles);
bool PatchSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains); bool PatchSingleUseGlobalLoad(const NativeCodeBasicBlock* block, int reg, int at, const NativeCodeInstruction& ains);

View File

@ -74,7 +74,7 @@ int main2(int argc, const char** argv)
#else #else
strcpy(strProductName, "oscar64"); strcpy(strProductName, "oscar64");
strcpy(strProductVersion, "1.11.170"); strcpy(strProductVersion, "1.11.171");
#ifdef __APPLE__ #ifdef __APPLE__
uint32_t length = sizeof(basePath); uint32_t length = sizeof(basePath);

View File

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,11,170,0 FILEVERSION 1,11,171,0
PRODUCTVERSION 1,11,170,0 PRODUCTVERSION 1,11,171,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -43,12 +43,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "oscar64" VALUE "CompanyName", "oscar64"
VALUE "FileDescription", "oscar64 compiler" VALUE "FileDescription", "oscar64 compiler"
VALUE "FileVersion", "1.11.170.0" VALUE "FileVersion", "1.11.171.0"
VALUE "InternalName", "oscar64.exe" VALUE "InternalName", "oscar64.exe"
VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "oscar64.exe" VALUE "OriginalFilename", "oscar64.exe"
VALUE "ProductName", "oscar64" VALUE "ProductName", "oscar64"
VALUE "ProductVersion", "1.11.170.0" VALUE "ProductVersion", "1.11.171.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -4283,15 +4283,15 @@
{ {
"Name" = "8:Microsoft Visual Studio" "Name" = "8:Microsoft Visual Studio"
"ProductName" = "8:oscar64" "ProductName" = "8:oscar64"
"ProductCode" = "8:{B6E47BFE-938F-4B25-8C95-E51AF35165C7}" "ProductCode" = "8:{DA1CECB4-79D8-41A0-9830-97D3055A1703}"
"PackageCode" = "8:{8AD29ABB-862F-458C-972F-A1D656646CF8}" "PackageCode" = "8:{B6FA666A-F4F3-496A-9772-09B1192805B1}"
"UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}"
"AspNetVersion" = "8:2.0.50727.0" "AspNetVersion" = "8:2.0.50727.0"
"RestartWWWService" = "11:FALSE" "RestartWWWService" = "11:FALSE"
"RemovePreviousVersions" = "11:TRUE" "RemovePreviousVersions" = "11:TRUE"
"DetectNewerInstalledVersion" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE"
"InstallAllUsers" = "11:FALSE" "InstallAllUsers" = "11:FALSE"
"ProductVersion" = "8:1.11.170" "ProductVersion" = "8:1.11.171"
"Manufacturer" = "8:oscar64" "Manufacturer" = "8:oscar64"
"ARPHELPTELEPHONE" = "8:" "ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:" "ARPHELPLINK" = "8:"