Add overlay support

This commit is contained in:
drmortalwombat 2022-12-10 17:15:25 +01:00
parent 0aa9ca0c70
commit 0055911491
11 changed files with 327 additions and 32 deletions

View File

@ -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"

View File

@ -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)

View File

@ -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)
{
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);

View File

@ -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<LinkerRegion*> mRegions;
GrowingArray<LinkerSection*> mSections;
GrowingArray<LinkerObject*> mObjects;
GrowingArray<LinkerOverlay*> 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;

View File

@ -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();

View File

@ -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);

View File

@ -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"

View File

@ -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:"

View File

@ -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

View File

@ -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

157
samples/memmap/overlay.c Normal file
View File

@ -0,0 +1,157 @@
#include <c64/memmap.h>
#include <c64/charwin.h>
#include <c64/cia.h>
#include <c64/vic.h>
#include <c64/kernalio.h>
// 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;
}