diff --git a/README.md b/README.md index 9f76cf6..562198d 100644 --- a/README.md +++ b/README.md @@ -177,63 +177,44 @@ Labels are defined with a colon after the name. Pure assembler functions can be ### Interrupt routines -The C compiler will not generate good interrupt code, it is simply too greedy with the zero page registers. Interrupt code should therefore be written in assembler. +The compiler provides two levels of interrupt safe functions. The specifier __interrupt caues all zero page registers used by the function to be saved, the __hwinterrupt also saves the CPU registers and exits the function with rti - #include + #include + #include + #include - // Next line for interrupt - volatile char npos; + __hwinterrupt void irq(void) + { + vic.color_border++; - // Interrupt routine - __asm irq - { - lda $d019 // Check if it is raster IRQ - and #$01 - beq w1 - - inc $d020 // Start colored section - inc $d021 - - ldx #20 // Wait for 2/3 lines - l1: dex - bne l1 - - dec $d020 // End colored section - dec $d021 - - lda npos // Setup next interrupt - sta $d012 - w1: - asl $d019 // Ack interrupt - - jmp $ea31 // System IRQ routine - } + // some interrupt code - int main(void) - { - __asm { sei } // Disable interrupt - - - *(void **)0x0314 = irq; // Install interrupt routine - *(char *)0xd01a = 1; // Enable raster interrupt - *(char *)0xd011 &= 0x7f; // Set raster line for IRQ - *(char *)0xd012 = 100; + vic.color_border--; + vic.intr_ctrl <<= 1; + } + + int main(void) + { + __asm { sei } // Disable interrupt + mmap_set(MMAP_NO_ROM); // Disable kernal rom + cia_init(); // No more CIA interrupts + + *(void **)0xfffe = irq; // Install interrupt routine + vic.intr_enable = VIC_INTR_RST; // Init raster interrupt + vic.ctrl1 &= ~VIC_CTRL1_RST8; + vic.raster = 100; + + __asm { cli } // Re-enable interrupt + + for(;;) + { + // Non interrupt code + } + + return 0 + } - npos = 100; - - __asm { cli } // Re-enable interrupt - - // Move the interrupt raster line up/down - float f = 0; - while (true) - { - npos = 130 + (int)(100 * sin(f)); - f += 0.1; - } - - return 0; - } ## Implementation Details diff --git a/include/c64/cia.c b/include/c64/cia.c index 9fc0804..a13c158 100644 --- a/include/c64/cia.c +++ b/include/c64/cia.c @@ -16,4 +16,7 @@ void cia_init(void) cia2.prb = 0x07; cia2.ddra = 0x3f; + + char i0 = cia1.icr; + char i1 = cia2.icr; } diff --git a/include/c64/cia.h b/include/c64/cia.h index c1a2a75..5c18bdc 100644 --- a/include/c64/cia.h +++ b/include/c64/cia.h @@ -6,12 +6,12 @@ struct CIA { volatile byte pra, prb; - byte ddra, ddrb; - word ta, tb; - byte todt, tods, todm, todh; - byte sdr; - byte icr; - byte cra, crb; + volatile byte ddra, ddrb; + volatile word ta, tb; + volatile byte todt, tods, todm, todh; + volatile byte sdr; + volatile byte icr; + volatile byte cra, crb; }; #define cia1 (*((struct CIA *)0xdc00)) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 9f525bf..26c8c59 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -48,34 +48,35 @@ enum DecType // TypeFlags -static const uint32 DTF_SIGNED = 0x00000001; -static const uint32 DTF_DEFINED = 0x00000002; -static const uint32 DTF_GLOBAL = 0x00000004; -static const uint32 DTF_VARIADIC = 0x00000008; -static const uint32 DTF_INTRINSIC = 0x00000010; -static const uint32 DTF_STATIC = 0x00000020; -static const uint32 DTF_CONST = 0x00000040; -static const uint32 DTF_VOLATILE = 0x00000080; -static const uint32 DTF_EXTERN = 0x00000100; -static const uint32 DTF_NATIVE = 0x00000200; -static const uint32 DTF_UPPER_BYTE = 0x00000400; -static const uint32 DTF_LOWER_BYTE = 0x00000800; -static const uint32 DTF_SECTION_START = 0x00001000; -static const uint32 DTF_SECTION_END = 0x00002000; -static const uint32 DTF_FASTCALL = 0x00004000; -static const uint32 DTF_INLINE = 0x00008000; -static const uint32 DTF_ANALYZED = 0x00010000; -static const uint32 DTF_REQUEST_INLINE = 0x00020000; -static const uint32 DTF_INTERRUPT = 0x00040000; -static const uint32 DTF_EXPORT = 0x00080000; +static const uint64 DTF_SIGNED = (1ULL << 0); +static const uint64 DTF_DEFINED = (1ULL << 1); +static const uint64 DTF_GLOBAL = (1ULL << 2); +static const uint64 DTF_VARIADIC = (1ULL << 3); +static const uint64 DTF_INTRINSIC = (1ULL << 4); +static const uint64 DTF_STATIC = (1ULL << 5); +static const uint64 DTF_CONST = (1ULL << 6); +static const uint64 DTF_VOLATILE = (1ULL << 7); +static const uint64 DTF_EXTERN = (1ULL << 8); +static const uint64 DTF_NATIVE = (1ULL << 9); +static const uint64 DTF_UPPER_BYTE = (1ULL << 10); +static const uint64 DTF_LOWER_BYTE = (1ULL << 11); +static const uint64 DTF_SECTION_START = (1ULL << 12); +static const uint64 DTF_SECTION_END = (1ULL << 13); +static const uint64 DTF_FASTCALL = (1ULL << 14); +static const uint64 DTF_INLINE = (1ULL << 15); +static const uint64 DTF_ANALYZED = (1ULL << 16); +static const uint64 DTF_REQUEST_INLINE = (1ULL << 17); +static const uint64 DTF_INTERRUPT = (1ULL << 18); +static const uint64 DTF_EXPORT = (1ULL << 19); +static const uint64 DTF_HWINTERRUPT = (1ULL << 20); -static const uint32 DTF_FUNC_VARIABLE = 0x00100000; -static const uint32 DTF_FUNC_ASSEMBLER = 0x00200000; -static const uint32 DTF_FUNC_RECURSIVE = 0x00400000; -static const uint32 DTF_FUNC_ANALYZING = 0x00800000; -static const uint32 DTF_FUNC_CONSTEXPR = 0x01000000; +static const uint64 DTF_FUNC_VARIABLE = (1ULL << 32); +static const uint64 DTF_FUNC_ASSEMBLER = (1ULL << 33); +static const uint64 DTF_FUNC_RECURSIVE = (1ULL << 34); +static const uint64 DTF_FUNC_ANALYZING = (1ULL << 35); +static const uint64 DTF_FUNC_CONSTEXPR = (1ULL << 36); -static const uint32 DTF_VAR_ALIASING = 0x02000000; +static const uint64 DTF_VAR_ALIASING = (1ULL << 37); class Declaration; @@ -175,7 +176,7 @@ public: int mOffset, mSize, mVarIndex, mNumVars, mComplexity, mLocalSize, mAlignment; int64 mInteger; double mNumber; - uint32 mFlags; + uint64 mFlags; const Ident * mIdent; LinkerSection * mSection; const uint8 * mData; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 0b0751c..16b6d65 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -2976,7 +2976,9 @@ void InterCodeBasicBlock::CollectEntryBlocks(InterCodeBasicBlock* from) void InterCodeBasicBlock::BuildDominatorTree(InterCodeBasicBlock* from) { - if (!mDominator) + if (from == this) + return; + else if (!mDominator) mDominator = from; else if (from == mDominator) return; @@ -7289,6 +7291,9 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa hasCall = true; } + GrowingArray tvalues(nullptr); + GrowingArray nassigns(0); + for (int i = 0; i < mInstructions.Size(); i++) { InterInstruction* ins = mInstructions[i]; @@ -7320,7 +7325,24 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa if (sins->mSrc[1].mTemp >= 0) { if ((ins->mSrc[0].mMemory != IM_PARAM && ins->mSrc[0].mMemory != IM_FPARAM) || aliasedParams[ins->mSrc[0].mVarIndex]) - ins->mInvariant = false; + { + int k = j - 1; + while (k >= 0 && mInstructions[k]->mDst.mTemp != sins->mSrc[1].mTemp) + k--; + if (k >= 0) + { + InterInstruction* lins = mInstructions[k]; + if (lins->mCode == IC_LEA && lins->mSrc[1].mTemp < 0) + { + if (ins->mSrc[0].mMemory == lins->mSrc[1].mMemory && ins->mSrc[0].mVarIndex == lins->mSrc[1].mVarIndex && ins->mSrc[0].mLinkerObject == lins->mSrc[1].mLinkerObject) + ins->mInvariant = false; + } + else + ins->mInvariant = false; + } + else + ins->mInvariant = false; + } } else if (ins->mSrc[0].mMemory == sins->mSrc[1].mMemory && ins->mSrc[0].mVarIndex == sins->mSrc[1].mVarIndex && ins->mSrc[0].mLinkerObject == sins->mSrc[1].mLinkerObject) { @@ -7347,7 +7369,7 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa GrowingArray dep(DEP_UNKNOWN); GrowingArray indexStep(0), indexBase(0); - GrowingArray tvalues(nullptr); + tvalues.SetSize(0); for (int i = 0; i < mInstructions.Size(); i++) { diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 9d04707..6f3aae2 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -476,7 +476,7 @@ public: GrowingTypeArray mTemporaries; GrowingIntArray mTempOffset, mTempSizes; int mTempSize, mCommonFrameSize, mCallerSavedTemps; - bool mLeafProcedure, mNativeProcedure, mCallsFunctionPointer, mHasDynamicStack, mHasInlineAssembler, mCallsByteCode, mFastCallProcedure, mInterrupt; + bool mLeafProcedure, mNativeProcedure, mCallsFunctionPointer, mHasDynamicStack, mHasInlineAssembler, mCallsByteCode, mFastCallProcedure, mInterrupt, mHardwareInterrupt; GrowingInterCodeProcedurePtrArray mCalledFunctions; InterCodeModule * mModule; diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index b4ad191..1764d5a 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -3425,6 +3425,9 @@ InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod if (dec->mFlags & DTF_INTERRUPT) proc->mInterrupt = true; + if (dec->mFlags & DTF_HWINTERRUPT) + proc->mHardwareInterrupt = true; + if (dec->mBase->mFlags & DTF_FASTCALL) { proc->mFastCallProcedure = true; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 756c1a0..552a8dd 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -13810,9 +13810,9 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass) progress = true; } else if ( - mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && - (mIns[i + 1].mType == ASMIT_ASL || mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ROL || mIns[i + 1].mType == ASMIT_ROR) && - mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & LIVE_CPU_REG_A)) + mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) && + mIns[i + 1].IsShift() && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_CPU_REG_A)) { mIns[i + 2].mType = mIns[i + 1].mType; mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; @@ -15728,6 +15728,15 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal); zpLocal |= zpGlobal; + if (proc->mHardwareInterrupt) + { + mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_PHA)); + mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_TXA)); + mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_PHA)); + mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_TYA)); + mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_PHA)); + } + for (int i = 2; i < 256; i++) { if (zpLocal[i]) @@ -15745,6 +15754,15 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, i)); } } + + if (proc->mHardwareInterrupt) + { + mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_PLA)); + mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_TAY)); + mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_PLA)); + mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_TAX)); + mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_PLA)); + } } else { @@ -15959,7 +15977,10 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) proc->mLinkerObject->mZeroPageSet = zpLocal; } - mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_RTS, ASMIM_IMPLIED)); + if (proc->mHardwareInterrupt) + mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_RTI, ASMIM_IMPLIED)); + else + mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_RTS, ASMIM_IMPLIED)); mEntryBlock->Assemble(); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 7981ef8..b43319a 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -22,7 +22,7 @@ Parser::~Parser(void) } -Declaration* Parser::ParseStructDeclaration(uint32 flags, DecType dt) +Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt) { const Ident* structName = nullptr; @@ -121,7 +121,7 @@ Declaration* Parser::ParseStructDeclaration(uint32 flags, DecType dt) return dec; } -Declaration* Parser::ParseBaseTypeDeclaration(uint32 flags) +Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags) { Declaration* dec = nullptr; @@ -905,7 +905,7 @@ Expression* Parser::ParseInitExpression(Declaration* dtype) Declaration* Parser::ParseDeclaration(bool variable) { bool definingType = false; - uint32 storageFlags = 0, typeFlags = 0; + uint64 storageFlags = 0, typeFlags = 0; if (mScanner->mToken == TK_TYPEDEF) { @@ -952,6 +952,11 @@ Declaration* Parser::ParseDeclaration(bool variable) storageFlags |= DTF_INTERRUPT | DTF_NATIVE; mScanner->NextToken(); } + else if (mScanner->mToken == TK_HWINTERRUPT) + { + storageFlags |= DTF_INTERRUPT | DTF_HWINTERRUPT | DTF_NATIVE; + mScanner->NextToken(); + } else break; } @@ -1028,7 +1033,7 @@ Declaration* Parser::ParseDeclaration(bool variable) { if (!ndec->mBase->IsSame(pdec->mBase)) mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function declaration differs", ndec->mIdent->mString); - else if (ndec->mFlags & ~pdec->mFlags & (DTF_FASTCALL | DTF_NATIVE)) + else if (ndec->mFlags & ~pdec->mFlags & (DTF_HWINTERRUPT | DTF_INTERRUPT | DTF_FASTCALL | DTF_NATIVE)) mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function call type declaration differs", ndec->mIdent->mString); else { diff --git a/oscar64/Parser.h b/oscar64/Parser.h index 55ec388..6a9da96 100644 --- a/oscar64/Parser.h +++ b/oscar64/Parser.h @@ -27,9 +27,9 @@ protected: void ParsePragma(void); - Declaration* ParseBaseTypeDeclaration(uint32 flags); + Declaration* ParseBaseTypeDeclaration(uint64 flags); Declaration* ParseDeclaration(bool variable); - Declaration* ParseStructDeclaration(uint32 flags, DecType dt); + Declaration* ParseStructDeclaration(uint64 flags, DecType dt); Declaration* CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp); Expression* ParseInitExpression(Declaration* dtype); diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index 45abb46..5834518 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -51,6 +51,7 @@ const char* TokenNames[] = "__asm", "__interrupt", + "__hwinterrupt", "__native", "__fastcall", "__export", @@ -1304,6 +1305,8 @@ void Scanner::NextRawToken(void) mToken = TK_ASSUME; else if (!strcmp(tkident, "__interrupt")) mToken = TK_INTERRUPT; + else if (!strcmp(tkident, "__hwinterrupt")) + mToken = TK_HWINTERRUPT; else if (!strcmp(tkident, "__native")) mToken = TK_NATIVE; else if (!strcmp(tkident, "__fastcall")) diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index 88687ac..9b85a3b 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -49,6 +49,7 @@ enum Token TK_ASM, TK_INTERRUPT, + TK_HWINTERRUPT, TK_NATIVE, TK_FASTCALL, TK_EXPORT, diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 494405f..b486ab2 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -73,7 +73,7 @@ int main2(int argc, const char** argv) #else strcpy(strProductName, "oscar64"); - strcpy(strProductVersion, "1.4.82"); + strcpy(strProductVersion, "1.4.83"); #ifdef __APPLE__ uint32_t length = sizeof(basePath); @@ -245,18 +245,22 @@ int main2(int argc, const char** argv) int main(int argc, const char** argv) { #ifdef _WIN32 +#ifndef _DEBUG __try { +#endif #endif return main2(argc, argv); #ifdef _WIN32 - } +#ifndef _DEBUG +} __except (EXCEPTION_EXECUTE_HANDLER) { printf("oscar64 crashed."); return 30; } #endif -} \ No newline at end of file +#endif +} diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index c34f809..5b77a69 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,4,82,0 - PRODUCTVERSION 1,4,82,0 + FILEVERSION 1,4,83,0 + PRODUCTVERSION 1,4,83,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,12 +43,12 @@ BEGIN BEGIN VALUE "CompanyName", "oscar64" VALUE "FileDescription", "oscar64 compiler" - VALUE "FileVersion", "1.4.82.0" + VALUE "FileVersion", "1.4.83.0" VALUE "InternalName", "oscar64.exe" VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "OriginalFilename", "oscar64.exe" VALUE "ProductName", "oscar64" - VALUE "ProductVersion", "1.4.82.0" + VALUE "ProductVersion", "1.4.83.0" END END BLOCK "VarFileInfo" diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index faca38e..13f7427 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -3648,15 +3648,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" - "ProductCode" = "8:{D7EEA6AF-54FD-48A9-80AF-F19CA9A32D0E}" - "PackageCode" = "8:{497B8392-6DB9-4695-A4BC-E7E7CA9DCB8E}" + "ProductCode" = "8:{273BF824-E947-4B58-8992-6060F95D9EF7}" + "PackageCode" = "8:{3C6231C2-746F-4D40-83F7-159286D6BDB3}" "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.4.82" + "ProductVersion" = "8:1.4.83" "Manufacturer" = "8:oscar64" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/samples/memmap/easyflash.crt b/samples/memmap/easyflash.crt index c9356ed..ffdc72a 100644 Binary files a/samples/memmap/easyflash.crt and b/samples/memmap/easyflash.crt differ