Add __hwinterrupt function decoration

This commit is contained in:
drmortalwombat 2022-02-06 10:28:09 +01:00
parent 5147ec6bc9
commit d4352ef043
16 changed files with 152 additions and 108 deletions

View File

@ -177,64 +177,45 @@ 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 <math.h>
#include <c64/memmap.h>
#include <c64/cia.h>
#include <c64/vic.h>
// 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
// some interrupt code
inc $d020 // Start colored section
inc $d021
vic.color_border--;
vic.intr_ctrl <<= 1;
}
ldx #20 // Wait for 2/3 lines
l1: dex
bne l1
int main(void)
{
__asm { sei } // Disable interrupt
mmap_set(MMAP_NO_ROM); // Disable kernal rom
cia_init(); // No more CIA interrupts
dec $d020 // End colored section
dec $d021
*(void **)0xfffe = irq; // Install interrupt routine
vic.intr_enable = VIC_INTR_RST; // Init raster interrupt
vic.ctrl1 &= ~VIC_CTRL1_RST8;
vic.raster = 100;
lda npos // Setup next interrupt
sta $d012
w1:
asl $d019 // Ack interrupt
__asm { cli } // Re-enable interrupt
jmp $ea31 // System IRQ routine
}
for(;;)
{
// Non interrupt code
}
int main(void)
{
__asm { sei } // Disable interrupt
return 0
}
*(void **)0x0314 = irq; // Install interrupt routine
*(char *)0xd01a = 1; // Enable raster interrupt
*(char *)0xd011 &= 0x7f; // Set raster line for IRQ
*(char *)0xd012 = 100;
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
The compiler does a full program compile, the linker step is part of the compilation. It knows all functions during the compilation run and includes only reachable code in the output. Source files are added to the build with the help of a pragma:

View File

@ -16,4 +16,7 @@ void cia_init(void)
cia2.prb = 0x07;
cia2.ddra = 0x3f;
char i0 = cia1.icr;
char i1 = cia2.icr;
}

View File

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

View File

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

View File

@ -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<InterInstructionPtr> tvalues(nullptr);
GrowingArray<int> 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<Dependency> dep(DEP_UNKNOWN);
GrowingArray<int64> indexStep(0), indexBase(0);
GrowingArray<InterInstructionPtr> tvalues(nullptr);
tvalues.SetSize(0);
for (int i = 0; i < mInstructions.Size(); i++)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -49,6 +49,7 @@ enum Token
TK_ASM,
TK_INTERRUPT,
TK_HWINTERRUPT,
TK_NATIVE,
TK_FASTCALL,
TK_EXPORT,

View File

@ -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
#endif
}

View File

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

View File

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

Binary file not shown.