diff --git a/README.md b/README.md index a12abe8..8602d38 100644 --- a/README.md +++ b/README.md @@ -448,6 +448,22 @@ the start of the stack section. The size of the stack and the minimum size of t The linker will throw an error if the heap or stack cannot be placed without collision. + +#### Overlays + +The linker can generate overlay files that are stored as .prg in the .d64 when selected as target. + +The mechanism uses the cartridge bank to denote up to 64 overlays. Each bank can be associated with one overlay file, which will then contain the used content of this bank. + + #pragma overlay( ovl1, 1 ) + +The overlay file can then be loaded in memory during program execution: + + krnio_setnam(P"OVL1"); + krnio_load(1, 8, 1); + + + ### Inline Assembler Inline assembler can be embedded inside of any functions, regardles of their compilation target of byte code or native. @@ -608,6 +624,10 @@ An alternative to calling the function in the cartridge ROM itself is to copy it This sample will use the memory area starting from 0x0400 for the main code section when copying the code, using the stack page 0x100 for the startup itself, thus wasting small amount of RAM space. +#### Dynamic overlays "overlay.c" + +When compiling for .d64 format, the linker will place code and data sections from virtual cartridge banks into overlay files. These files can be loaded when needed and called using normal function calls. + #### Terminate stay resident "tsr.c" diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 81af7d1..41af7bc 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -546,9 +546,7 @@ bool Compiler::WriteOutputFile(const char* targetPath, DiskImage * d64) while (i > 0 && prgPath[i - 1] != '/' && prgPath[i - 1] != '\\') i--; - d64->OpenFile(prgPath + i); - mLinker->WritePrgFile(d64); - d64->CloseFile(); + mLinker->WritePrgFile(d64, prgPath + i); } if (mCompilerOptions & COPT_VERBOSE) diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index cc416e3..7f8427d 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -82,14 +82,25 @@ uint8* LinkerObject::AddSpace(int size) return mData; } +LinkerOverlay::LinkerOverlay(void) +{ + +} + +LinkerOverlay::~LinkerOverlay(void) +{ + +} + Linker::Linker(Errors* errors) - : mErrors(errors), mSections(nullptr), mReferences(nullptr), mObjects(nullptr), mRegions(nullptr), mCompilerOptions(COPT_DEFAULT) + : mErrors(errors), mSections(nullptr), mReferences(nullptr), mObjects(nullptr), mRegions(nullptr), mOverlays(nullptr), mCompilerOptions(COPT_DEFAULT) { for (int i = 0; i < 64; i++) { mCartridgeBankUsed[i] = 0; - mCartridgeBankSize[i] = 0; - memset(mCartridge[i], 0, 0x4000); + mCartridgeBankStart[i] = 0x10000; + mCartridgeBankEnd[i] = 0x00000; + memset(mCartridge[i], 0, 0x10000); } memset(mMemory, 0, 0x10000); } @@ -147,6 +158,17 @@ LinkerSection* Linker::FindSection(const Ident* section) return nullptr; } +LinkerOverlay* Linker::AddOverlay(const Location& location, const Ident* ident, int bank) +{ + LinkerOverlay* lovl = new LinkerOverlay; + lovl->mLocation = location; + lovl->mIdent = ident; + lovl->mBank = bank; + mOverlays.Push(lovl); + + return lovl; +} + bool Linker::IsSectionPlaced(LinkerSection* section) { for (int i = 0; i < mRegions.Size(); i++) @@ -376,7 +398,7 @@ void Linker::Link(void) { LinkerRegion* lrgn = mRegions[i]; - if (lrgn->mNonzero) + if (lrgn->mNonzero && lrgn->mCartridgeBanks == 0) { if (lrgn->mStart < mProgramStart) mProgramStart = lrgn->mStart; @@ -461,9 +483,11 @@ void Linker::Link(void) if (obj->mRegion->mCartridgeBanks & (1ULL << i)) { mCartridgeBankUsed[i] = true; - memcpy(mCartridge[i] + obj->mAddress - 0x8000, obj->mData, obj->mSize); - if (obj->mAddress - 0x8000 + obj->mSize > mCartridgeBankSize[i]) - mCartridgeBankSize[i] = obj->mAddress - 0x8000 + obj->mSize; + memcpy(mCartridge[i] + obj->mAddress, obj->mData, obj->mSize); + if (obj->mAddress < mCartridgeBankStart[i]) + mCartridgeBankStart[i] = obj->mAddress; + if (obj->mAddress + obj->mSize > mCartridgeBankEnd[i]) + mCartridgeBankEnd[i] = obj->mAddress + obj->mSize; } } } @@ -493,7 +517,7 @@ void Linker::Link(void) { if (obj->mRegion->mCartridgeBanks & (1ULL << i)) { - dp = mCartridge[i] + obj->mAddress - 0x8000 + ref->mOffset; + dp = mCartridge[i] + obj->mAddress + ref->mOffset; if (ref->mFlags & LREF_LOWBYTE) { @@ -569,12 +593,38 @@ bool Linker::WriteBinFile(const char* filename) return false; } -bool Linker::WritePrgFile(DiskImage* image) +bool Linker::WritePrgFile(DiskImage* image, const char* filename) { - mMemory[mProgramStart - 2] = mProgramStart & 0xff; - mMemory[mProgramStart - 1] = mProgramStart >> 8; + if (image->OpenFile(filename)) + { + mMemory[mProgramStart - 2] = mProgramStart & 0xff; + mMemory[mProgramStart - 1] = mProgramStart >> 8; - return image->WriteBytes(mMemory + mProgramStart - 2, mProgramEnd - mProgramStart + 2); + image->WriteBytes(mMemory + mProgramStart - 2, mProgramEnd - mProgramStart + 2); + image->CloseFile(); + + for (int i = 0; i < mOverlays.Size(); i++) + { + if (image->OpenFile(mOverlays[i]->mIdent->mString)) + { + int b = mOverlays[i]->mBank; + int s = mCartridgeBankStart[b]; + + mCartridge[b][s - 2] = s & 0xff; + mCartridge[b][s - 1] = s >> 8; + + image->WriteBytes(mCartridge[b] + s - 2, mCartridgeBankEnd[b] - s + 2); + + image->CloseFile(); + } + else + return false; + } + + return true; + } + + return false; } bool Linker::WritePrgFile(const char* filename) @@ -742,7 +792,8 @@ bool Linker::WriteCrtFile(const char* filename) fwrite(bootmem + 0x2000, 1, 0x2000, file); mCartridgeBankUsed[0] = true; - mCartridgeBankSize[0] = usedlz + 0x200; + mCartridgeBankStart[0] = 0x8000; + mCartridgeBankEnd[0] = 0x8000 + usedlz + 0x200; for (int i = 1; i < 64; i++) { @@ -752,11 +803,11 @@ bool Linker::WriteCrtFile(const char* filename) chipHeader.mLoadAddress = 0x0080; fwrite(&chipHeader, sizeof(chipHeader), 1, file); - fwrite(mCartridge[i] + 0x0000, 1, 0x2000, file); + fwrite(mCartridge[i] + 0x8000, 1, 0x2000, file); chipHeader.mLoadAddress = 0x00a0; fwrite(&chipHeader, sizeof(chipHeader), 1, file); - fwrite(mCartridge[i] + 0x2000, 1, 0x2000, file); + fwrite(mCartridge[i] + 0xa000, 1, 0x2000, file); } } @@ -813,7 +864,7 @@ bool Linker::WriteMapFile(const char* filename) for (int i = 0; i < 64; i++) { if (mCartridgeBankUsed[i]) - fprintf(file, "%02d : %04x\n", i, mCartridgeBankSize[i]); + fprintf(file, "%02d : %04x .. %04x (%04x)\n", i, mCartridgeBankStart[i], mCartridgeBankEnd[i], mCartridgeBankEnd[i] - mCartridgeBankStart[i]); } } @@ -873,7 +924,7 @@ bool Linker::WriteAsmFile(const char* filename) int i = 0; while (!(obj->mRegion->mCartridgeBanks & (1ULL << i))) i++; - mNativeDisassembler.Disassemble(file, mCartridge[i] - 0x8000, i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); + mNativeDisassembler.Disassemble(file, mCartridge[i], i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); } else mNativeDisassembler.Disassemble(file, mMemory, 0, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); @@ -884,7 +935,7 @@ bool Linker::WriteAsmFile(const char* filename) int i = 0; while (!(obj->mRegion->mCartridgeBanks & (1ULL << i))) i++; - mNativeDisassembler.DumpMemory(file, mCartridge[i] - 0x8000, i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); + mNativeDisassembler.DumpMemory(file, mCartridge[i], i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); } else mNativeDisassembler.DumpMemory(file, mMemory, 0, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); diff --git a/oscar64/Linker.h b/oscar64/Linker.h index 54ed65e..3973027 100644 --- a/oscar64/Linker.h +++ b/oscar64/Linker.h @@ -172,6 +172,17 @@ public: void MarkRelevant(void); }; +class LinkerOverlay +{ +public: + LinkerOverlay(void); + ~LinkerOverlay(void); + + Location mLocation; + const Ident * mIdent; + int mBank; +}; + class Linker { public: @@ -190,9 +201,11 @@ public: LinkerObject * AddObject(const Location & location, const Ident* ident, LinkerSection * section, LinkerObjectType type, int alignment = 1); + LinkerOverlay* AddOverlay(const Location& location, const Ident* ident, int bank); + // void AddReference(const LinkerReference& ref); - bool WritePrgFile(DiskImage * image); + bool WritePrgFile(DiskImage * image, const char* filename); bool WritePrgFile(const char* filename); bool WriteMapFile(const char* filename); bool WriteAsmFile(const char* filename); @@ -206,13 +219,14 @@ public: GrowingArray mRegions; GrowingArray mSections; GrowingArray mObjects; + GrowingArray mOverlays; uint8 mMemory[0x10000]; - uint8 mCartridge[64][0x4000]; + uint8 mCartridge[64][0x10000]; bool mCartridgeBankUsed[64]; - uint32 mCartridgeBankSize[64]; + uint32 mCartridgeBankStart[64], mCartridgeBankEnd[64]; int mProgramStart, mProgramEnd; diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index a9f3e8e..2d6c284 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -3607,6 +3607,33 @@ void Parser::ParsePragma(void) ConsumeToken(TK_CLOSE_PARENTHESIS); } + else if (!strcmp(mScanner->mTokenIdent->mString, "overlay")) + { + mScanner->NextToken(); + ConsumeToken(TK_OPEN_PARENTHESIS); + + if (mScanner->mToken == TK_IDENT) + { + const Ident* overlayIdent = mScanner->mTokenIdent; + mScanner->NextToken(); + + int bank = 0; + + ConsumeToken(TK_COMMA); + + Expression* exp; + + exp = ParseRExpression(); + if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER) + bank = exp->mDecValue->mInteger; + else + mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for bank expected"); + + LinkerOverlay* lovl = mCompilationUnits->mLinker->AddOverlay(mScanner->mLocation, overlayIdent, bank); + } + + ConsumeToken(TK_CLOSE_PARENTHESIS); + } else if (!strcmp(mScanner->mTokenIdent->mString, "section")) { mScanner->NextToken(); diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 0146bf7..4c1687f 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -74,7 +74,7 @@ int main2(int argc, const char** argv) #else strcpy(strProductName, "oscar64"); - strcpy(strProductVersion, "1.11.173"); + strcpy(strProductVersion, "1.12.174"); #ifdef __APPLE__ uint32_t length = sizeof(basePath); diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index 253d461..8f4f025 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,11,173,0 - PRODUCTVERSION 1,11,173,0 + FILEVERSION 1,12,174,0 + PRODUCTVERSION 1,12,174,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,12 +43,12 @@ BEGIN BEGIN VALUE "CompanyName", "oscar64" VALUE "FileDescription", "oscar64 compiler" - VALUE "FileVersion", "1.11.173.0" + VALUE "FileVersion", "1.12.174.0" VALUE "InternalName", "oscar64.exe" VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "OriginalFilename", "oscar64.exe" VALUE "ProductName", "oscar64" - VALUE "ProductVersion", "1.11.173.0" + VALUE "ProductVersion", "1.12.174.0" END END BLOCK "VarFileInfo" diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index 1575ad3..f4cf023 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -838,6 +838,12 @@ } "Entry" { + "MsmKey" = "8:_E3FF6A8B315C439DA54DE18DB39FB3AD" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_E4138658F1F544CF86255EDC1659936D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -3777,6 +3783,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E3FF6A8B315C439DA54DE18DB39FB3AD" + { + "SourcePath" = "8:..\\samples\\memmap\\overlay.c" + "TargetName" = "8:overlay.c" + "Tag" = "8:" + "Folder" = "8:_A62A71A6A08941C5964B90112D87731F" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E4138658F1F544CF86255EDC1659936D" { "SourcePath" = "8:..\\samples\\kernalio\\charread.c" @@ -4424,15 +4450,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" - "ProductCode" = "8:{B37C3691-BB18-4F82-B574-F47BF7A70D6E}" - "PackageCode" = "8:{1B3B4C99-2560-4BE0-8F6A-05067CD5006F}" + "ProductCode" = "8:{2FD4FD95-A0D1-4DC0-A9F4-DE9085C7F327}" + "PackageCode" = "8:{9C02A8C7-2D5F-4FAB-8185-219EDC622E4E}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:1.11.173" + "ProductVersion" = "8:1.12.174" "Manufacturer" = "8:oscar64" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/samples/memmap/build.sh b/samples/memmap/build.sh index 95e4873..da7133a 100644 --- a/samples/memmap/build.sh +++ b/samples/memmap/build.sh @@ -10,3 +10,4 @@ ../../bin/oscar64 easyflashreloc.c -n -tf=crt ../../bin/oscar64 easyflashshared.c -n -tf=crt ../../bin/oscar64 tsr.c -n -dNOFLOAT -dNOLONG +../../bin/oscar64 overlay.c -n -d64=overlay.d64 diff --git a/samples/memmap/make.bat b/samples/memmap/make.bat index 88aa25d..7382770 100644 --- a/samples/memmap/make.bat +++ b/samples/memmap/make.bat @@ -10,3 +10,4 @@ call ..\..\bin\oscar64 easyflashreloc.c -n -tf=crt call ..\..\bin\oscar64 easyflashshared.c -n -tf=crt call ..\..\bin\oscar64 easyflashlow.c -n -tf=crt call ..\..\bin\oscar64 tsr.c -n -dNOFLOAT -dNOLONG +call ..\..\bin\oscar64 overlay.c -n -d64=overlay.d64 diff --git a/samples/memmap/overlay.c b/samples/memmap/overlay.c new file mode 100644 index 0000000..6fb93ae --- /dev/null +++ b/samples/memmap/overlay.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include + +// Common memory area for all overlays + +#pragma region( main, 0x0900, 0x8000, , , { code, data, bss, heap, stack } ) + +// Section and region for first overlay bank + +#pragma overlay( ovl1, 1 ) +#pragma section( bcode1, 0 ) +#pragma section( bdata1, 0 ) +#pragma region(bank1, 0x8000, 0xc000, , 1, { bcode1, bdata1 } ) + +// Section and region for second overlay bank + +#pragma overlay( ovl2, 2 ) +#pragma section( bcode2, 0 ) +#pragma section( bdata2, 0 ) +#pragma region(bank2, 0x8000, 0xc000, , 2, { bcode2, bdata2 } ) + +#pragma overlay( ovl3, 3 ) +#pragma section( bcode3, 0 ) +#pragma section( bdata3, 0 ) +#pragma region(bank3, 0x8000, 0xc000, , 3, { bcode3, bdata3 } ) + +#pragma overlay( ovl4, 4 ) +#pragma section( bcode4, 0 ) +#pragma section( bdata4, 0 ) +#pragma region(bank4, 0x8000, 0xc000, , 4, { bcode4, bdata4 } ) + +#pragma overlay( ovl5, 5 ) +#pragma section( bcode5, 0 ) +#pragma section( bdata5, 0 ) +#pragma region(bank5, 0x8000, 0xc000, , 5, { bcode5, bdata5 } ) + +#pragma overlay( ovl6, 6 ) +#pragma section( bcode6, 0 ) +#pragma section( bdata6, 0 ) +#pragma region(bank6, 0x8000, 0xc000, , 6, { bcode6, bdata6 } ) + +// Charwin in shared memory section + +CharWin cw; + +// Now switch code generation to bank 1 + +#pragma code ( bcode1 ) +#pragma data ( bdata1 ) + +// Print into shared charwin + +void print1(void) +{ + cwin_put_string(&cw, p"This is first overlay", 7); + cwin_cursor_newline(&cw); +} + +// Now switch code generation to bank 2 + +#pragma code ( bcode2 ) +#pragma data ( bdata2 ) + +void print2(void) +{ + cwin_put_string(&cw, p"This is second overlay", 7); + cwin_cursor_newline(&cw); +} + +#pragma code ( bcode3 ) +#pragma data ( bdata3 ) + +void print3(void) +{ + cwin_put_string(&cw, p"This is third overlay", 7); + cwin_cursor_newline(&cw); +} + +#pragma code ( bcode4 ) +#pragma data ( bdata4 ) + +void print4(void) +{ + cwin_put_string(&cw, p"This is fourth overlay", 7); + cwin_cursor_newline(&cw); +} + +#pragma code ( bcode5 ) +#pragma data ( bdata5 ) + +void print5(void) +{ + cwin_put_string(&cw, p"This is fifth overlay", 7); + cwin_cursor_newline(&cw); +} + +#pragma code ( bcode6 ) +#pragma data ( bdata6 ) + +void print6(void) +{ + cwin_put_string(&cw, p"This is sixth overlay", 7); + cwin_cursor_newline(&cw); +} + +// Switching code generation back to shared section + +#pragma code ( code ) +#pragma data ( data ) + +// Load an overlay section into memory + +void load(const char * fname) +{ + krnio_setnam(fname); + krnio_load(1, 8, 1); +} + +int main(void) +{ + // Kernal memory only + mmap_set(MMAP_NO_BASIC); + + // Init VIC + vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800); + + // Prepare output window + cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25); + cwin_clear(&cw); + + // Call function in overlay 1 + load(P"OVL1"); + print1(); + + // Call function in overlay 2 + load(P"OVL2"); + print2(); + + load(P"OVL3"); + print3(); + + load(P"OVL4"); + print4(); + + load(P"OVL5"); + print5(); + + load(P"OVL6"); + print6(); + + mmap_set(MMAP_ROM); + + return 0; +}