diff --git a/README.md b/README.md index 94c1ad5..a61e753 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ After extensive optimizations it turns out, that the interpreted code is not sig ## Limits and Errors -There are still several open areas, but most targets have been reached. The current Dhrystone performance is 82 iterations per second with byte code (11831) and 365 iterations with native code (11372 Bytes). This clearly shows that Dhrystone is not a valid benchmark for optimizing compilers, because it puts the 6502 on par with a 4MHz 8088 or 68k, which it clearly is not. +There are still several open areas, but most targets have been reached. The current Dhrystone performance is 94 iterations per second with byte code (11696) and 395 iterations with native code (10425 Bytes). This clearly shows that Dhrystone is not a valid benchmark for optimizing compilers, because it puts the 6502 on par with a 4MHz 8088 or 68k, which it clearly is not. ### Language @@ -516,6 +516,8 @@ 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. +The __bankof operator returns the bank id of a function or constant placed into a ROM bank. + #### Overlays diff --git a/include/cx16/vera.c b/include/cx16/vera.c index bbc3b07..4fa2cb8 100644 --- a/include/cx16/vera.c +++ b/include/cx16/vera.c @@ -7,6 +7,20 @@ void vram_addr(unsigned long addr) vera.addrh = (char)((addr >> 16) & 1) | 0x10; } +void vram_addr0(unsigned long addr) +{ + vera.ctrl &= ~VERA_CTRL_ADDRSEL; + vera.addr = (unsigned)addr; + vera.addrh = (char)((addr >> 16) & 1) | 0x00; +} + +void vram_addr2(unsigned long addr) +{ + vera.ctrl &= ~VERA_CTRL_ADDRSEL; + vera.addr = (unsigned)addr; + vera.addrh = (char)((addr >> 16) & 1) | 0x20; +} + void vram_put(char data) { vera.data0 = data; @@ -88,6 +102,17 @@ void vera_spr_set(char spr, unsigned addr32, VERASpriteMode mode8, VERASpriteSiz vram_put((h << 6) | (w << 4) | pal); } +void vera_spr_flip(char spr, bool fliph, bool flipv) +{ + __assume(spr < 128); + + vram_addr0(0x1fc00UL + spr * 8 + 6); + char b = vram_get() & 0xfc; + if (fliph) b |= 0x01; + if (flipv) b |= 0x02; + vram_put(b); +} + void vera_spr_move(char spr, int x, int y) { __assume(spr < 128); @@ -129,3 +154,13 @@ void vera_pal_putn(char index, const unsigned * color, unsigned size) size--; } } + +void vera_pal_getn(char index, unsigned * color, unsigned size) +{ + vram_addr(0x1fa00ul + 2 * index); + while (size > 0) + { + *color++ = vram_getw(); + size--; + } +} diff --git a/include/cx16/vera.h b/include/cx16/vera.h index b1d8810..6066501 100644 --- a/include/cx16/vera.h +++ b/include/cx16/vera.h @@ -114,6 +114,10 @@ enum VERASpritePriority inline void vram_addr(unsigned long addr); +inline void vram_addr0(unsigned long addr); + +inline void vram_addr2(unsigned long addr); + inline void vram_put(char data); inline void vram_putw(unsigned data); @@ -134,6 +138,8 @@ void vram_fill(unsigned long addr, char data, unsigned size); void vera_spr_set(char spr, unsigned addr32, VERASpriteMode mode8, VERASpriteSize w, VERASpriteSize h, VERASpritePriority z, char pal); +void vera_spr_flip(char spr, bool fliph, bool flipv); + void vera_spr_move(char spr, int x, int y); void vera_spr_image(char spr, unsigned addr32); @@ -144,6 +150,8 @@ unsigned vera_pal_get(char index); void vera_pal_putn(char index, const unsigned * color, unsigned size); +void vera_pal_getn(char index, unsigned * color, unsigned size); + #pragma compile("vera.c") #endif diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 9e03a48..243e362 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -150,7 +150,8 @@ enum ExpressionType EX_CASE, EX_DEFAULT, EX_CONDITIONAL, - EX_ASSUME + EX_ASSUME, + EX_BANKOF }; class Expression diff --git a/oscar64/Errors.h b/oscar64/Errors.h index 6989c88..6e0c767 100644 --- a/oscar64/Errors.h +++ b/oscar64/Errors.h @@ -67,6 +67,7 @@ enum ErrorID ERRR_SEMICOLON_EXPECTED, ERRR_USE_OF_UNINITIALIZED_VARIABLE, ERRR_STRIPE_REQUIRES_FIXED_SIZE_ARRAY, + ERRR_CANNOT_FIND_BANK_OF_EXPRESSION, ERRR_STACK_OVERFLOW, ERRR_INVALID_NUMBER, diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index 0f96d6b..6b3ad28 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -2081,6 +2081,28 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* dec->mFlags = DTF_DEFINED; return ExValue(dec, vl.mTemp, vl.mReference - 1); } + case TK_BANKOF: + { + LinkerRegion* rgn; + if (exp->mLeft->mDecValue->mSection && (rgn = mLinker->FindRegionOfSection(exp->mLeft->mDecValue->mSection))) + { + uint64 i = 0; + while (i < 64 && rgn->mCartridgeBanks != (1ULL << i)) + i++; + if (i < 64) + { + ins->mCode = IC_CONSTANT; + ins->mNumOperands = 0; + ins->mConst.mType = IT_INT8; + ins->mConst.mIntConst = i; + ins->mDst.mType = IT_INT8; + ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + block->Append(ins); + return ExValue(TheUnsignedCharTypeDeclaration, ins->mDst.mTemp, vl.mReference - 1); + } + } + mErrors->Error(exp->mLocation, ERRR_CANNOT_FIND_BANK_OF_EXPRESSION, "Cannot find bank of expressiohn"); + } break; } ins->mSrc[0].mType = InterTypeOf(vl.mType); diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index 44d929e..fdf3317 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -172,6 +172,23 @@ LinkerSection* Linker::AddSection(const Ident* section, LinkerSectionType type) } +LinkerRegion* Linker::FindRegionOfSection(LinkerSection* section) +{ + LinkerRegion* srgn = nullptr; + for (int i = 0; i < mRegions.Size(); i++) + { + LinkerRegion* rgn = mRegions[i]; + if (rgn->mSections.Contains(section)) + { + if (srgn) + return nullptr; + srgn = rgn; + } + } + + return srgn; +} + LinkerSection* Linker::FindSection(const Ident* section) { for (int i = 0; i < mSections.Size(); i++) diff --git a/oscar64/Linker.h b/oscar64/Linker.h index 1124644..02812eb 100644 --- a/oscar64/Linker.h +++ b/oscar64/Linker.h @@ -231,6 +231,8 @@ public: LinkerSection * AddSection(const Ident* section, LinkerSectionType type); LinkerSection* FindSection(const Ident* section); + LinkerRegion* FindRegionOfSection(LinkerSection* section); + LinkerObject* FindObjectByAddr(int addr); bool IsSectionPlaced(LinkerSection* section); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index ae8ad29..14caf6a 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -27443,6 +27443,10 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[0]); mIns.Remove(0); + mEntryRequiredRegs += CPU_REG_A; + mExitRequiredRegs += CPU_REG_A; + prevBlock->mExitRequiredRegs += CPU_REG_A; + CheckLive(); return true; @@ -27747,6 +27751,10 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[si]); mIns.Remove(si); + mEntryRequiredRegs += CPU_REG_A; + mExitRequiredRegs += CPU_REG_A; + prevBlock->mExitRequiredRegs += CPU_REG_A; + CheckLive(); return true; @@ -27791,6 +27799,10 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[si]); mIns.Remove(si); + mEntryRequiredRegs += CPU_REG_A; + mExitRequiredRegs += CPU_REG_A; + prevBlock->mExitRequiredRegs += CPU_REG_A; + CheckLive(); return true; @@ -27844,6 +27856,10 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[si]); mIns.Remove(si); + mEntryRequiredRegs += CPU_REG_A; + mExitRequiredRegs += CPU_REG_A; + prevBlock->mExitRequiredRegs += CPU_REG_A; + CheckLive(); return true; @@ -27893,6 +27909,9 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[0]); mIns.Remove(0); + mEntryRequiredRegs += CPU_REG_Y; + mExitRequiredRegs += CPU_REG_Y; + CheckLive(); return true; @@ -27920,6 +27939,9 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[0]); mIns.Remove(0); + mEntryRequiredRegs += CPU_REG_X; + mExitRequiredRegs += CPU_REG_X; + CheckLive(); return true; @@ -27996,6 +28018,10 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[ai]); mIns.Remove(ai); + mEntryRequiredRegs += CPU_REG_A; + mExitRequiredRegs += CPU_REG_A; + prevBlock->mExitRequiredRegs += CPU_REG_A; + changed = true; } @@ -28010,6 +28036,10 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc prevBlock->mIns.Push(mIns[ai]); mIns.Remove(ai); + mEntryRequiredRegs += CPU_REG_A; + mExitRequiredRegs += CPU_REG_A; + prevBlock->mExitRequiredRegs += CPU_REG_A; + changed = true; } } @@ -28156,6 +28186,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc } } +#if 1 if (mEntryRequiredRegs.Size() && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X])) { for (int i = 0; i + 1 < mIns.Size(); i++) @@ -28174,6 +28205,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc return OptimizeSimpleLoopInvariant(proc, full); if (!mEntryRequiredRegs[CPU_REG_A]) { + assert(mIns[0].mType != ASMIT_STA); prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress)); prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress)); } @@ -28200,6 +28232,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc if (!mEntryRequiredRegs[CPU_REG_A]) { + assert(mIns[0].mType != ASMIT_STA); prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, mIns[i + 0].mAddress)); prevBlock->mIns.Push(NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress)); } @@ -28237,6 +28270,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc if (!mEntryRequiredRegs[CPU_REG_A]) { + assert(mIns[0].mType != ASMIT_STA); prevBlock->mIns.Insert(k, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, mIns[i + 0].mAddress)); prevBlock->mIns.Insert(k + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, mIns[i + 1].mAddress)); } @@ -28250,6 +28284,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc } } } +#endif #if 1 for (int i = 0; i < mIns.Size(); i++) @@ -39543,6 +39578,7 @@ void NativeCodeProcedure::Optimize(void) else cnt++; + } while (changed); #if 1 diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index ddd2f97..a7841e4 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -1768,7 +1768,9 @@ Expression* Parser::ParsePostfixExpression(void) Expression* Parser::ParsePrefixExpression(void) { - if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT || mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND) + if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT || + mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND || + mScanner->mToken == TK_BANKOF) { Expression* nexp; if (mScanner->mToken == TK_LOGICAL_NOT) @@ -1814,6 +1816,10 @@ Expression* Parser::ParsePrefixExpression(void) pdec->mFlags |= DTF_DEFINED; nexp->mDecType = pdec; } + else if (nexp->mToken == TK_BANKOF) + { + nexp->mDecType == TheUnsignedCharTypeDeclaration; + } else nexp->mDecType = nexp->mLeft->mDecType; } diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index 08da80a..2778e97 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -44,6 +44,7 @@ const char* TokenNames[] = "'union'", "'enum'", "'sizeof'", + "'__bankof'", "'static'", "'auto'", "'extern'", @@ -1342,6 +1343,8 @@ void Scanner::NextRawToken(void) mToken = TK_ENUM; else if (!strcmp(tkident, "sizeof")) mToken = TK_SIZEOF; + else if (!strcmp(tkident, "__bankof")) + mToken = TK_BANKOF; else if (!strcmp(tkident, "typedef")) mToken = TK_TYPEDEF; else if (!strcmp(tkident, "static")) diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index f6e5b44..7099ca7 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -42,6 +42,7 @@ enum Token TK_UNION, TK_ENUM, TK_SIZEOF, + TK_BANKOF, TK_STATIC, TK_AUTO, TK_EXTERN, diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 6b31589..161e8ab 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.19.198"); + strcpy(strProductVersion, "1.19.199"); #ifdef __APPLE__ uint32_t length = sizeof(basePath); diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index d215671..35e21bf 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,19,198,0 - PRODUCTVERSION 1,19,198,0 + FILEVERSION 1,19,199,0 + PRODUCTVERSION 1,19,199,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,12 +43,12 @@ BEGIN BEGIN VALUE "CompanyName", "oscar64" VALUE "FileDescription", "oscar64 compiler" - VALUE "FileVersion", "1.19.198.0" + VALUE "FileVersion", "1.19.199.0" VALUE "InternalName", "oscar64.exe" VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "OriginalFilename", "oscar64.exe" VALUE "ProductName", "oscar64" - VALUE "ProductVersion", "1.19.198.0" + VALUE "ProductVersion", "1.19.199.0" END END BLOCK "VarFileInfo" diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index 1d1c78f..2490945 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -5155,15 +5155,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" - "ProductCode" = "8:{1E7DBEE1-2479-49F8-9F5B-1DA786C469FD}" - "PackageCode" = "8:{F178C72F-3E89-41CE-8310-E30ADA97F214}" + "ProductCode" = "8:{A34D0747-EA76-43D6-AB25-7A788C4ECAE2}" + "PackageCode" = "8:{A35E0D83-FD72-41CF-85BC-8E74BB5E9888}" "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.19.198" + "ProductVersion" = "8:1.19.199" "Manufacturer" = "8:oscar64" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/samples/memmap/easyflash.c b/samples/memmap/easyflash.c index e66c721..0ca1125 100644 --- a/samples/memmap/easyflash.c +++ b/samples/memmap/easyflash.c @@ -106,6 +106,16 @@ void print6(void) #pragma data ( data ) +// Function for indirect cross bank call +void fcall(char bank, void (* func)()) +{ + eflash.bank = bank; + func(); +} + +// Macro for indirect cross bank call +#define FCALL(f) fcall(__bankof(f), f) + int main(void) { // Enable ROM @@ -136,14 +146,15 @@ int main(void) eflash.bank = 3; print3(); - eflash.bank = 4; + // Get bank of function using __bankof operator + eflash.bank = __bankof print4; print4(); - eflash.bank = 5; - print5(); + // Indirect call + fcall(__bankof print5, print5); - eflash.bank = 6; - print6(); + // Macro call + FCALL(print6); // Loop forever while (true)