diff --git a/README.md b/README.md index d93e3f5..59f5c1f 100644 --- a/README.md +++ b/README.md @@ -684,6 +684,19 @@ The overlay file can then be loaded in memory during program execution: krnio_setnam(P"OVL1"); krnio_load(1, 8, 1); + +#### Inlays + +Inlays are sections that are compressed into constant arrays by the linker and can then be expanded by the program on demand. The array has to be declared with unknown size. + + const char Inlay1[]; + #pragma section( icode1, 0 ) + #pragma region( isec1, 0xc000, 0xd000, , Inlay1, { icode1 } ) + +The size of the array is not known at compile time, so a sizeof() will return 0. The oscar_expand_lzo can be used to expand the code and does not need the size: + + oscar_expand_lzo((char *)0xc000, Inlay1); + #### NES ROM Banks diff --git a/include/c64/iecbus.h b/include/c64/iecbus.h index cd4d4f5..814b96d 100644 --- a/include/c64/iecbus.h +++ b/include/c64/iecbus.h @@ -8,7 +8,7 @@ enum IEC_STATUS IEC_ERROR = 0x80, IEC_TIMEOUT, - IEC_DATA_CHECK + IEC_DATA_CHECK, }; extern IEC_STATUS iec_status; diff --git a/oscar64/Compression.cpp b/oscar64/Compression.cpp new file mode 100644 index 0000000..64045f9 --- /dev/null +++ b/oscar64/Compression.cpp @@ -0,0 +1,59 @@ +#include "Compression.h" + +int CompressLZO(uint8* dst, const uint8* source, int size) +{ + int csize = 0; + + int pos = 0; + while (pos < size) + { + int pi = 0; + while (pi < 127 && pos < size) + { + int bi = pi, bj = 0; + for (int i = 1; i < (pos < 255 ? pos : 255); i++) + { + int j = 0; + while (j < 127 && pos + j < size && source[pos - i + j] == source[pos + j]) + j++; + + if (j > bj) + { + bi = i; + bj = j; + } + } + + if (bj >= 4) + { + if (pi > 0) + { + dst[csize++] = pi; + for (int i = 0; i < pi; i++) + dst[csize++] = source[pos - pi + i]; + pi = 0; + } + + dst[csize++] = 128 + bj; + dst[csize++] = bi; + pos += bj; + } + else + { + pos++; + pi++; + } + } + + if (pi > 0) + { + dst[csize++] = pi; + for (int i = 0; i < pi; i++) + dst[csize++] = source[pos - pi + i]; + } + } + + dst[csize++] = 0; + + return csize; +} diff --git a/oscar64/Compression.h b/oscar64/Compression.h new file mode 100644 index 0000000..3bd4e3a --- /dev/null +++ b/oscar64/Compression.h @@ -0,0 +1,6 @@ +#pragma once + +#include "CompilerTypes.h" + +int CompressLZO(uint8* dst, const uint8* source, int size); + diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index 206fb0b..9f3fdf6 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -986,7 +986,7 @@ Declaration::Declaration(const Location& loc, DecType type) mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1), mFriends(nullptr), mInteger(0), mNumber(0), mMinValue(-0x80000000LL), mMaxValue(0x7fffffffLL), mFastCallBase(0), mFastCallSize(0), mStride(0), mStripe(1), mCompilerOptions(0), mUseCount(0), mTokens(nullptr), mParser(nullptr), - mShift(0), mBits(0), mOptFlags(0) + mShift(0), mBits(0), mOptFlags(0), mInlayRegion(nullptr) {} Declaration::~Declaration(void) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 4f3efa8..9521dae 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -8,6 +8,7 @@ class LinkerObject; class LinkerSection; +class LinkerRegion; class Linker; class Parser; @@ -99,6 +100,7 @@ static const uint64 DTF_COMPLETED = (1ULL << 30); static const uint64 DTF_CONSTEXPR = (1ULL << 31); static const uint64 DTF_AUTO_TEMPLATE = (1ULL << 32); +static const uint64 DTF_BANK_INLAY = (1ULL << 33); static const uint64 DTF_FUNC_VARIABLE = (1ULL << 36); static const uint64 DTF_FUNC_ASSEMBLER = (1ULL << 37); @@ -280,6 +282,7 @@ public: uint64 mFlags, mCompilerOptions, mOptFlags; const Ident * mIdent, * mQualIdent, * mMangleIdent; LinkerSection * mSection; + LinkerRegion * mInlayRegion; const uint8 * mData; LinkerObject * mLinkerObject; int mUseCount; diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index 82b5b2c..d7dfbc1 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -696,6 +696,11 @@ void InterCodeGenerator::InitGlobalVariable(InterCodeModule * mod, Declaration* dec->mLinkerObject->mType = LOT_SECTION_START; else if (dec->mFlags & DTF_SECTION_END) dec->mLinkerObject->mType = LOT_SECTION_END; + else if (dec->mFlags & DTF_BANK_INLAY) + { + dec->mLinkerObject->mType = LOT_INLAY; + dec->mInlayRegion->mInlayObject = dec->mLinkerObject; + } uint8* d = var->mLinkerObject->AddSpace(var->mSize); if (dec->mValue) diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index d2c988f..b22d7f7 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -2,9 +2,10 @@ #include #include #include "CompilerTypes.h" +#include "Compression.h" LinkerRegion::LinkerRegion(void) - : mSections(nullptr), mFreeChunks(FreeChunk{ 0, 0 } ), mLastObject(nullptr) + : mSections(nullptr), mFreeChunks(FreeChunk{ 0, 0 } ), mLastObject(nullptr), mInlayObject(nullptr), mCartridgeBanks(0) {} LinkerSection::LinkerSection(void) @@ -44,7 +45,7 @@ bool LinkerReference::operator!=(const LinkerReference& ref) } LinkerObject::LinkerObject(void) - : mReferences(nullptr), mNumTemporaries(0), mSize(0), mAlignment(1), mStackSection(nullptr), mIdent(nullptr), mFullIdent(nullptr) + : mReferences(nullptr), mNumTemporaries(0), mSize(0), mAlignment(1), mStackSection(nullptr), mIdent(nullptr), mFullIdent(nullptr), mStartUsed(0x10000), mEndUsed(0x00000), mMemory(nullptr) {} LinkerObject::~LinkerObject(void) @@ -339,13 +340,13 @@ void Linker::CombineSameConst(void) while (dobj->mMapID != mObjects[dobj->mMapID]->mMapID) dobj->mMapID = mObjects[dobj->mMapID]->mMapID; - if ((dobj->mFlags & LOBJF_REFERENCED) && (dobj->mFlags & LOBJF_CONST) && dobj->mMapID == dobj->mID) + if ((dobj->mFlags & LOBJF_REFERENCED) && (dobj->mFlags & LOBJF_CONST) && dobj->mMapID == dobj->mID && dobj->mType != LOT_INLAY) { for (int j = i + 1; j < mObjects.Size(); j++) { LinkerObject* sobj(mObjects[j]); - if ((sobj->mFlags & LOBJF_REFERENCED) && (sobj->mFlags & LOBJF_CONST) && sobj->mMapID == sobj->mID) + if ((sobj->mFlags & LOBJF_REFERENCED) && (sobj->mFlags & LOBJF_CONST) && sobj->mMapID == sobj->mID && sobj->mType != LOT_INLAY) { if (dobj->mSize == sobj->mSize && dobj->mSection == sobj->mSection && dobj->mReferences.Size() == sobj->mReferences.Size()) { @@ -531,7 +532,7 @@ void LinkerRegion::PlaceStackSection(LinkerSection* stackSection, LinkerSection* { int start = stackSection->mEnd; - for(int i=0; imSections.Size(); i++) + for (int i = 0; i < section->mSections.Size(); i++) { PlaceStackSection(stackSection, section->mSections[i]); if (section->mSections[i]->mStart < start) @@ -540,7 +541,7 @@ void LinkerRegion::PlaceStackSection(LinkerSection* stackSection, LinkerSection* section->mStart = start; section->mEnd = start; - + for (int i = 0; i < section->mObjects.Size(); i++) { LinkerObject* lobj = section->mObjects[i]; @@ -561,147 +562,48 @@ void LinkerRegion::PlaceStackSection(LinkerSection* stackSection, LinkerSection* } } -void Linker::Link(void) +void Linker::CopyObjects(bool inlays) { - if (mErrors->mErrorCount == 0) + for (int i = 0; i < mObjects.Size(); i++) { - - for (int i = 0; i < mSections.Size(); i++) + LinkerObject* obj = mObjects[i]; + if (obj->mType == LOT_SECTION_START) { - LinkerSection* lsec = mSections[i]; - lsec->mStart = 0x10000; - lsec->mEnd = 0x0000; + obj->mAddress = obj->mSection->mStart; + obj->mRefAddress = obj->mAddress + (obj->mRegion ? obj->mRegion->mReloc : 0); } - - // Move objects into regions - - for (int i = 0; i < mRegions.Size(); i++) + else if (obj->mType == LOT_SECTION_END) { - LinkerRegion* lrgn = mRegions[i]; - for (int j = 0; j < lrgn->mSections.Size(); j++) + obj->mAddress = obj->mSection->mEnd; + obj->mRefAddress = obj->mAddress + (obj->mRegion ? obj->mRegion->mReloc : 0); + } + else if (obj->mFlags & LOBJF_REFERENCED) + { + if (inlays) { - LinkerSection* lsec = lrgn->mSections[j]; - for (int k = 0; k < lsec->mObjects.Size(); k++) + if (obj->mRegion && obj->mRegion->mInlayObject) { - LinkerObject* lobj = lsec->mObjects[k]; - if ((lobj->mFlags & LOBJF_REFERENCED) && !(lobj->mFlags & LOBJF_PLACED) && lrgn->Allocate(this, lobj, mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)) + LinkerObject* iobj = obj->mRegion->mInlayObject; + if (!iobj->mMemory) { - if (lobj->mIdent && lobj->mIdent->mString && (mCompilerOptions & COPT_VERBOSE2)) - printf("Placed object <%s> $%04x - $%04x\n", lobj->mIdent->mString, lobj->mAddress, lobj->mAddress + lobj->mSize); - - if (lobj->mAddress < lsec->mStart) - lsec->mStart = lobj->mAddress; - if (lobj->mAddress + lobj->mSize > lsec->mEnd) - lsec->mEnd = lobj->mAddress + lobj->mSize; - - if (lsec->mType == LST_DATA && lsec->mEnd > lrgn->mNonzero) - lrgn->mNonzero = lsec->mEnd; + iobj->mMemory = new uint8[0x10000]; + memset(iobj->mMemory, 0, 0x10000); } + + memcpy(iobj->mMemory + obj->mAddress, obj->mData, obj->mSize); + if (obj->mAddress < iobj->mStartUsed) + iobj->mStartUsed = obj->mAddress; + if (obj->mAddress + obj->mSize > iobj->mEndUsed) + iobj->mEndUsed = obj->mAddress + obj->mSize; } } - - for (int j = 0; j < lrgn->mSections.Size(); j++) - { - LinkerSection* lsec = lrgn->mSections[j]; - if (lsec->mType == LST_BSS && lsec->mStart < lrgn->mNonzero) - lsec->mStart = lrgn->mNonzero; - if (lsec->mEnd < lsec->mStart) - lsec->mEnd = lsec->mStart; - } - } - - mProgramStart = 0xffff; - mProgramEnd = 0x0000; - - for (int i = 0; i < mRegions.Size(); i++) - { - LinkerRegion* lrgn = mRegions[i]; - - if (lrgn->mNonzero && lrgn->mCartridgeBanks == 0) - { - if (lrgn->mStart < mProgramStart) - mProgramStart = lrgn->mStart; - if (lrgn->mNonzero > mProgramEnd) - mProgramEnd = lrgn->mNonzero; - } - } - - // Place stack segment - - for (int i = 0; i < mRegions.Size(); i++) - { - LinkerRegion* lrgn = mRegions[i]; - for (int j = 0; j < lrgn->mSections.Size(); j++) - { - LinkerSection* lsec = lrgn->mSections[j]; - - if (lsec->mType == LST_STACK) - { - lsec->mStart = lsec->mEnd = lrgn->mEnd; - lrgn->mEnd = lsec->mStart - lsec->mSize; - - for(int i=0; imSections.Size(); i++) - lrgn->PlaceStackSection(lsec, lsec->mSections[i]); - - if (lsec->mStart < lrgn->mEnd) - { - Location loc; - mErrors->Error(loc, ERRR_INSUFFICIENT_MEMORY, "Static stack usage exceeds stack segment"); - } - - lsec->mEnd = lsec->mStart; - lsec->mStart = lrgn->mEnd; - - if (lsec->mStart < lrgn->mStart + lrgn->mUsed) - { - Location loc; - mErrors->Error(loc, ERRR_INSUFFICIENT_MEMORY, "Cannot place stack section"); - } - } - } - } - - // Now expand the heap section to cover the remainder of the region - - for (int i = 0; i < mRegions.Size(); i++) - { - LinkerRegion* lrgn = mRegions[i]; - for (int j = 0; j < lrgn->mSections.Size(); j++) - { - LinkerSection* lsec = lrgn->mSections[j]; - - if (lsec->mType == LST_HEAP) - { - lsec->mStart = (lrgn->mStart + lrgn->mUsed + 7) & ~7; - lsec->mEnd = lrgn->mEnd & ~7; - - if (lsec->mStart + lsec->mSize > lsec->mEnd) - { - Location loc; - mErrors->Error(loc, ERRR_INSUFFICIENT_MEMORY, "Cannot place heap section"); - } - } - } - } - - for (int i = 0; i < mObjects.Size(); i++) - { - LinkerObject* obj = mObjects[i]; - if (obj->mType == LOT_SECTION_START) - { - obj->mAddress = obj->mSection->mStart; - obj->mRefAddress = obj->mAddress + (obj->mRegion ? obj->mRegion->mReloc : 0); - } - else if (obj->mType == LOT_SECTION_END) - { - obj->mAddress = obj->mSection->mEnd; - obj->mRefAddress = obj->mAddress + (obj->mRegion ? obj->mRegion->mReloc : 0); - } - else if (obj->mFlags & LOBJF_REFERENCED) + else { if (!obj->mRegion) mErrors->Error(obj->mLocation, ERRR_INSUFFICIENT_MEMORY, "Could not place object", obj->mIdent); - else if (obj->mRegion->mCartridgeBanks != 0) + else if (obj->mRegion->mInlayObject) + ; + else if (obj->mRegion && obj->mRegion->mCartridgeBanks != 0) { for (int i = 0; i < 64; i++) { @@ -722,20 +624,46 @@ void Linker::Link(void) } } } + } +} - for (int i = 0; i < mReferences.Size(); i++) +void Linker::PatchReferences(bool inlays) +{ + for (int i = 0; i < mReferences.Size(); i++) + { + LinkerReference* ref = mReferences[i]; + LinkerObject* obj = ref->mObject; + if (obj->mFlags & LOBJF_REFERENCED) { - LinkerReference* ref = mReferences[i]; - LinkerObject* obj = ref->mObject; - if (obj->mFlags & LOBJF_REFERENCED) + if (obj->mRegion) { - if (obj->mRegion) + LinkerObject* robj = ref->mRefObject; + + int raddr = robj->mRefAddress + ref->mRefOffset; + uint8* dp; + + if (inlays) { - LinkerObject* robj = ref->mRefObject; + if (obj->mRegion->mInlayObject) + { + LinkerObject* iobj = obj->mRegion->mInlayObject; - int raddr = robj->mRefAddress + ref->mRefOffset; - uint8* dp; + dp = iobj->mMemory + obj->mAddress + ref->mOffset; + if (ref->mFlags & LREF_LOWBYTE) + { + *dp++ = raddr & 0xff; + } + if (ref->mFlags & LREF_HIGHBYTE) + { + *dp++ = (raddr >> 8) & 0xff; + } + if (ref->mFlags & LREF_TEMPORARY) + *dp += obj->mTemporaries[ref->mRefOffset]; + } + } + else if (!obj->mRegion->mInlayObject) + { if (obj->mRegion->mCartridgeBanks) { for (int i = 0; i < 64; i++) @@ -775,6 +703,166 @@ void Linker::Link(void) } } } + } +} + +void Linker::PlaceObjects(void) +{ + for (int i = 0; i < mRegions.Size(); i++) + { + LinkerRegion* lrgn = mRegions[i]; + for (int j = 0; j < lrgn->mSections.Size(); j++) + { + LinkerSection* lsec = lrgn->mSections[j]; + for (int k = 0; k < lsec->mObjects.Size(); k++) + { + LinkerObject* lobj = lsec->mObjects[k]; + if (lobj->mType != LOT_INLAY && (lobj->mFlags & LOBJF_REFERENCED) && !(lobj->mFlags & LOBJF_PLACED) && lrgn->Allocate(this, lobj, mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)) + { + if (lobj->mIdent && lobj->mIdent->mString && (mCompilerOptions & COPT_VERBOSE2)) + printf("Placed object <%s> $%04x - $%04x\n", lobj->mIdent->mString, lobj->mAddress, lobj->mAddress + lobj->mSize); + + if (lobj->mAddress < lsec->mStart) + lsec->mStart = lobj->mAddress; + if (lobj->mAddress + lobj->mSize > lsec->mEnd) + lsec->mEnd = lobj->mAddress + lobj->mSize; + + if (lsec->mType == LST_DATA && lsec->mEnd > lrgn->mNonzero) + lrgn->mNonzero = lsec->mEnd; + } + } + } + } +} + +void Linker::Link(void) +{ + if (mErrors->mErrorCount == 0) + { + + for (int i = 0; i < mSections.Size(); i++) + { + LinkerSection* lsec = mSections[i]; + lsec->mStart = 0x10000; + lsec->mEnd = 0x0000; + } + + // Move objects into regions + PlaceObjects(); + + // Place stack segment + + for (int i = 0; i < mRegions.Size(); i++) + { + LinkerRegion* lrgn = mRegions[i]; + for (int j = 0; j < lrgn->mSections.Size(); j++) + { + LinkerSection* lsec = lrgn->mSections[j]; + + if (lsec->mType == LST_STACK) + { + lsec->mStart = lsec->mEnd = lrgn->mEnd; + lrgn->mEnd = lsec->mStart - lsec->mSize; + + for (int i = 0; i < lsec->mSections.Size(); i++) + lrgn->PlaceStackSection(lsec, lsec->mSections[i]); + + if (lsec->mStart < lrgn->mEnd) + { + Location loc; + mErrors->Error(loc, ERRR_INSUFFICIENT_MEMORY, "Static stack usage exceeds stack segment"); + } + + lsec->mEnd = lsec->mStart; + lsec->mStart = lrgn->mEnd; + + if (lsec->mStart < lrgn->mStart + lrgn->mUsed) + { + Location loc; + mErrors->Error(loc, ERRR_INSUFFICIENT_MEMORY, "Cannot place stack section"); + } + } + } + } + + CopyObjects(true); + PatchReferences(true); + + // Move inlays into regions + + for (int i = 0; i < mRegions.Size(); i++) + { + LinkerRegion* lrgn = mRegions[i]; + if (lrgn->mInlayObject) + { + LinkerObject* iobj = lrgn->mInlayObject; + + int size = CompressLZO(mWorkspace, iobj->mMemory + iobj->mStartUsed, iobj->mEndUsed - iobj->mStartUsed); + iobj->AddData(mWorkspace, size); + iobj->mType = LOT_DATA; + } + } + + PlaceObjects(); + + // Calculate BSS storage + + for (int i = 0; i < mRegions.Size(); i++) + { + LinkerRegion* lrgn = mRegions[i]; + for (int j = 0; j < lrgn->mSections.Size(); j++) + { + LinkerSection* lsec = lrgn->mSections[j]; + if (lsec->mType == LST_BSS && lsec->mStart < lrgn->mNonzero) + lsec->mStart = lrgn->mNonzero; + if (lsec->mEnd < lsec->mStart) + lsec->mEnd = lsec->mStart; + } + } + + mProgramStart = 0xffff; + mProgramEnd = 0x0000; + + for (int i = 0; i < mRegions.Size(); i++) + { + LinkerRegion* lrgn = mRegions[i]; + + if (lrgn->mNonzero && lrgn->mCartridgeBanks == 0 && !lrgn->mInlayObject) + { + if (lrgn->mStart < mProgramStart) + mProgramStart = lrgn->mStart; + if (lrgn->mNonzero > mProgramEnd) + mProgramEnd = lrgn->mNonzero; + } + } + + // Now expand the heap section to cover the remainder of the region + + for (int i = 0; i < mRegions.Size(); i++) + { + LinkerRegion* lrgn = mRegions[i]; + for (int j = 0; j < lrgn->mSections.Size(); j++) + { + LinkerSection* lsec = lrgn->mSections[j]; + + if (lsec->mType == LST_HEAP) + { + lsec->mStart = (lrgn->mStart + lrgn->mUsed + 7) & ~7; + lsec->mEnd = lrgn->mEnd & ~7; + + if (lsec->mStart + lsec->mSize > lsec->mEnd) + { + Location loc; + mErrors->Error(loc, ERRR_INSUFFICIENT_MEMORY, "Cannot place heap section"); + } + } + } + } + + // Second patch of references + + CopyObjects(false); + PatchReferences(false); for (int i = 0; i < mObjects.Size(); i++) { @@ -1527,6 +1615,8 @@ bool Linker::WriteAsmFile(const char* filename) i++; mNativeDisassembler.Disassemble(file, mCartridge[i], i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj->mFullIdent); } + else if (obj->mRegion->mInlayObject) + mNativeDisassembler.Disassemble(file, obj->mRegion->mInlayObject->mMemory, 0xa0, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj->mFullIdent); else mNativeDisassembler.Disassemble(file, mMemory, -1, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj->mFullIdent); break; @@ -1538,6 +1628,8 @@ bool Linker::WriteAsmFile(const char* filename) i++; mNativeDisassembler.DumpMemory(file, mCartridge[i], i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); } + else if (obj->mRegion->mInlayObject) + mNativeDisassembler.DumpMemory(file, obj->mRegion->mInlayObject->mMemory, 0xa0, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); else mNativeDisassembler.DumpMemory(file, mMemory, -1, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); break; diff --git a/oscar64/Linker.h b/oscar64/Linker.h index cfa308d..a8f30e9 100644 --- a/oscar64/Linker.h +++ b/oscar64/Linker.h @@ -22,6 +22,7 @@ enum LinkerObjectType LOT_BSS, LOT_HEAP, LOT_STACK, + LOT_INLAY, LOT_SECTION_START, LOT_SECTION_END }; @@ -79,9 +80,10 @@ class LinkerRegion public: const Ident* mIdent; - uint32 mFlags; - int mStart, mEnd, mUsed, mNonzero, mReloc; - uint64 mCartridgeBanks; + uint32 mFlags; + int mStart, mEnd, mUsed, mNonzero, mReloc; + uint64 mCartridgeBanks; + LinkerObject * mInlayObject; GrowingArray mSections; @@ -183,10 +185,10 @@ public: LinkerObjectType mType; int mID, mMapID; int mAddress, mRefAddress; - int mSize, mAlignment; + int mSize, mAlignment, mStartUsed, mEndUsed; LinkerSection * mSection; LinkerRegion * mRegion; - uint8 * mData; + uint8 * mData, * mMemory; InterCodeProcedure * mProc; uint32 mFlags; uint8 mTemporaries[16], mTempSizes[16]; @@ -278,7 +280,7 @@ public: GrowingArray mObjects; GrowingArray mOverlays; - uint8 mMemory[0x10000]; + uint8 mMemory[0x10000], mWorkspace[0x10000]; uint8 mCartridge[64][0x10000]; bool mCartridgeBankUsed[64]; @@ -291,6 +293,9 @@ public: void CollectReferences(void); void CombineSameConst(void); + void PatchReferences(bool inlays); + void CopyObjects(bool inlays); + void PlaceObjects(void); void Link(void); protected: NativeCodeDisassembler mNativeDisassembler; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index ae0b5f3..8db8fba 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -1391,6 +1391,7 @@ bool NativeCodeInstruction::ChangesZFlag(void) const mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY || mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR || + mType == ASMIT_BIT || mType == ASMIT_JSR; } @@ -1457,7 +1458,7 @@ bool NativeCodeInstruction::UsesAddress(void) const mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY || mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY || - mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR; + mType == ASMIT_ADC || mType == ASMIT_SBC || mType == ASMIT_AND || mType == ASMIT_ORA || mType == ASMIT_EOR || mType == ASMIT_BIT; } else return false; @@ -2353,6 +2354,10 @@ void NativeCodeInstruction::Simulate(NativeRegisterDataSet& data) } break; + case ASMIT_BIT: + data.mRegs[CPU_REG_Z].Reset(); + break; + case ASMIT_LDA: if (reg >= 0) { @@ -3384,6 +3389,9 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT data.mRegs[CPU_REG_Z].Reset(); } break; + case ASMIT_BIT: + data.mRegs[CPU_REG_Z].Reset(); + break; case ASMIT_INX: case ASMIT_DEX: data.ResetX(); @@ -3545,7 +3553,18 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT } } #endif - +#if 1 + if (final && mType == ASMIT_STX && data.mRegs[CPU_REG_A].SameData(data.mRegs[CPU_REG_X])) + { + mType = ASMIT_STA; + changed = true; + } + else if (final && mType == ASMIT_STY && data.mRegs[CPU_REG_A].SameData(data.mRegs[CPU_REG_Y])) + { + mType = ASMIT_STA; + changed = true; + } +#endif if (mMode == ASMIM_ZERO_PAGE) { switch (mType) @@ -4453,6 +4472,10 @@ void NativeCodeInstruction::FilterRegUsage(NumberSet& requiredTemps, NumberSet& case ASMIT_TXA: case ASMIT_TAY: case ASMIT_TYA: + case ASMIT_DEY: + case ASMIT_INY: + case ASMIT_DEX: + case ASMIT_INX: providedTemps += CPU_REG_Z; break; } @@ -38892,6 +38915,30 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 1].mType = ASMIT_STA; progress = true; } + else if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 1].mType == ASMIT_INC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) && !(mIns[i + 0].mFlags & NCIF_VOLATILE)) + { + mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X; + mIns[i + 1].mType = ASMIT_STX; + progress = true; + } + else if (mIns[i + 0].mType == ASMIT_STX && mIns[i + 1].mType == ASMIT_DEC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_X) && !(mIns[i + 0].mFlags & NCIF_VOLATILE)) + { + mIns[i + 0].mType = ASMIT_DEX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X; + mIns[i + 1].mType = ASMIT_STX; + progress = true; + } + else if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 1].mType == ASMIT_INC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[i + 0].mFlags & NCIF_VOLATILE)) + { + mIns[i + 0].mType = ASMIT_INY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y; + mIns[i + 1].mType = ASMIT_STY; + progress = true; + } + else if (mIns[i + 0].mType == ASMIT_STY && mIns[i + 1].mType == ASMIT_DEC && mIns[i + 0].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[i + 0].mFlags & NCIF_VOLATILE)) + { + mIns[i + 0].mType = ASMIT_DEY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y; + mIns[i + 1].mType = ASMIT_STY; + progress = true; + } #endif else if ( mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && @@ -43527,6 +43574,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass changed = true; } +#if 1 + else if (pass >= 7 && sz >= 1 && + mIns[sz - 1].mType == ASMIT_LDA && (mIns[sz - 1].mMode == ASMIM_ABSOLUTE || mIns[sz - 1].mMode == ASMIM_ZERO_PAGE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && + (mBranch == ASMIT_BPL || mBranch == ASMIT_BMI) && !mExitRequiredRegs[CPU_REG_Z]) + { + mIns[sz - 1].mType = ASMIT_BIT; + + changed = true; + } +#endif else if (pass >= 7 && sz >= 1 && mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x40 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z]) @@ -44471,7 +44528,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "PlayingState::InitMaps"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "main"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index b81861b..5412f8c 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -11227,7 +11227,7 @@ void Parser::ParsePragma(void) ConsumeToken(TK_COMMA); exp = ParseRExpression(); - if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER) + if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_ADDRESS)) start = int(exp->mDecValue->mInteger); else mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for start expected"); @@ -11235,7 +11235,7 @@ void Parser::ParsePragma(void) ConsumeToken(TK_COMMA); exp = ParseRExpression(); - if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER) + if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_ADDRESS)) end = int(exp->mDecValue->mInteger); else mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for end expected"); @@ -11253,6 +11253,8 @@ void Parser::ParsePragma(void) ConsumeToken(TK_COMMA); + Declaration* inlay = nullptr; + if (mScanner->mToken != TK_COMMA) { if (mScanner->mToken == TK_OPEN_BRACE) @@ -11273,11 +11275,23 @@ void Parser::ParsePragma(void) } else { - exp = ParseRExpression(); - if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER) - bank = 1ULL << exp->mDecValue->mInteger; + exp = ParseExpression(true); + if (exp->mType == EX_VARIABLE && exp->mDecType->mType == DT_TYPE_ARRAY && exp->mDecType->mSize == 0 && + exp->mDecType->mBase->mType == DT_TYPE_INTEGER && exp->mDecType->mBase->mSize == 1) + { + exp->mDecValue->mFlags |= DTF_DEFINED | DTF_BANK_INLAY; + exp->mDecValue->mSection = mCodeSection; + exp->mDecType->mFlags |= DTF_DEFINED; + inlay = exp->mDecValue; + } else - mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for bank expected"); + { + exp = exp->ConstantFold(mErrors, mDataSection, mCompilationUnits->mLinker); + if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER) + bank = 1ULL << exp->mDecValue->mInteger; + else + mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for bank expected"); + } } } @@ -11291,6 +11305,10 @@ void Parser::ParsePragma(void) else if (rgn->mStart != start || rgn->mEnd != end || rgn->mFlags != flags || rgn->mCartridgeBanks != bank) mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Conflicting linker region definition"); + if (inlay) + { + inlay->mInlayRegion = rgn; + } ConsumeToken(TK_COMMA); ConsumeToken(TK_OPEN_BRACE); diff --git a/oscar64/oscar64.vcxproj b/oscar64/oscar64.vcxproj index 56e143c..53df641 100644 --- a/oscar64/oscar64.vcxproj +++ b/oscar64/oscar64.vcxproj @@ -158,6 +158,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/oscar64/oscar64.vcxproj.filters b/oscar64/oscar64.vcxproj.filters index 98e8470..a95c2e9 100644 --- a/oscar64/oscar64.vcxproj.filters +++ b/oscar64/oscar64.vcxproj.filters @@ -84,6 +84,9 @@ Source Files + + Source Files + @@ -164,6 +167,9 @@ Header Files + + Header Files +