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 ### 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 __hwinterrupt void irq(void)
volatile char npos; {
vic.color_border++;
// Interrupt routine // some interrupt code
__asm irq
{
lda $d019 // Check if it is raster IRQ
and #$01
beq w1
inc $d020 // Start colored section vic.color_border--;
inc $d021 vic.intr_ctrl <<= 1;
}
ldx #20 // Wait for 2/3 lines int main(void)
l1: dex {
bne l1 __asm { sei } // Disable interrupt
mmap_set(MMAP_NO_ROM); // Disable kernal rom
cia_init(); // No more CIA interrupts
dec $d020 // End colored section *(void **)0xfffe = irq; // Install interrupt routine
dec $d021 vic.intr_enable = VIC_INTR_RST; // Init raster interrupt
vic.ctrl1 &= ~VIC_CTRL1_RST8;
vic.raster = 100;
lda npos // Setup next interrupt __asm { cli } // Re-enable interrupt
sta $d012
w1:
asl $d019 // Ack interrupt
jmp $ea31 // System IRQ routine for(;;)
} {
// Non interrupt code
}
int main(void) return 0
{ }
__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;
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 ## 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: 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.prb = 0x07;
cia2.ddra = 0x3f; cia2.ddra = 0x3f;
char i0 = cia1.icr;
char i1 = cia2.icr;
} }

View File

@ -6,12 +6,12 @@
struct CIA struct CIA
{ {
volatile byte pra, prb; volatile byte pra, prb;
byte ddra, ddrb; volatile byte ddra, ddrb;
word ta, tb; volatile word ta, tb;
byte todt, tods, todm, todh; volatile byte todt, tods, todm, todh;
byte sdr; volatile byte sdr;
byte icr; volatile byte icr;
byte cra, crb; volatile byte cra, crb;
}; };
#define cia1 (*((struct CIA *)0xdc00)) #define cia1 (*((struct CIA *)0xdc00))

View File

@ -48,34 +48,35 @@ enum DecType
// TypeFlags // TypeFlags
static const uint32 DTF_SIGNED = 0x00000001; static const uint64 DTF_SIGNED = (1ULL << 0);
static const uint32 DTF_DEFINED = 0x00000002; static const uint64 DTF_DEFINED = (1ULL << 1);
static const uint32 DTF_GLOBAL = 0x00000004; static const uint64 DTF_GLOBAL = (1ULL << 2);
static const uint32 DTF_VARIADIC = 0x00000008; static const uint64 DTF_VARIADIC = (1ULL << 3);
static const uint32 DTF_INTRINSIC = 0x00000010; static const uint64 DTF_INTRINSIC = (1ULL << 4);
static const uint32 DTF_STATIC = 0x00000020; static const uint64 DTF_STATIC = (1ULL << 5);
static const uint32 DTF_CONST = 0x00000040; static const uint64 DTF_CONST = (1ULL << 6);
static const uint32 DTF_VOLATILE = 0x00000080; static const uint64 DTF_VOLATILE = (1ULL << 7);
static const uint32 DTF_EXTERN = 0x00000100; static const uint64 DTF_EXTERN = (1ULL << 8);
static const uint32 DTF_NATIVE = 0x00000200; static const uint64 DTF_NATIVE = (1ULL << 9);
static const uint32 DTF_UPPER_BYTE = 0x00000400; static const uint64 DTF_UPPER_BYTE = (1ULL << 10);
static const uint32 DTF_LOWER_BYTE = 0x00000800; static const uint64 DTF_LOWER_BYTE = (1ULL << 11);
static const uint32 DTF_SECTION_START = 0x00001000; static const uint64 DTF_SECTION_START = (1ULL << 12);
static const uint32 DTF_SECTION_END = 0x00002000; static const uint64 DTF_SECTION_END = (1ULL << 13);
static const uint32 DTF_FASTCALL = 0x00004000; static const uint64 DTF_FASTCALL = (1ULL << 14);
static const uint32 DTF_INLINE = 0x00008000; static const uint64 DTF_INLINE = (1ULL << 15);
static const uint32 DTF_ANALYZED = 0x00010000; static const uint64 DTF_ANALYZED = (1ULL << 16);
static const uint32 DTF_REQUEST_INLINE = 0x00020000; static const uint64 DTF_REQUEST_INLINE = (1ULL << 17);
static const uint32 DTF_INTERRUPT = 0x00040000; static const uint64 DTF_INTERRUPT = (1ULL << 18);
static const uint32 DTF_EXPORT = 0x00080000; static const uint64 DTF_EXPORT = (1ULL << 19);
static const uint64 DTF_HWINTERRUPT = (1ULL << 20);
static const uint32 DTF_FUNC_VARIABLE = 0x00100000; static const uint64 DTF_FUNC_VARIABLE = (1ULL << 32);
static const uint32 DTF_FUNC_ASSEMBLER = 0x00200000; static const uint64 DTF_FUNC_ASSEMBLER = (1ULL << 33);
static const uint32 DTF_FUNC_RECURSIVE = 0x00400000; static const uint64 DTF_FUNC_RECURSIVE = (1ULL << 34);
static const uint32 DTF_FUNC_ANALYZING = 0x00800000; static const uint64 DTF_FUNC_ANALYZING = (1ULL << 35);
static const uint32 DTF_FUNC_CONSTEXPR = 0x01000000; 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; class Declaration;
@ -175,7 +176,7 @@ public:
int mOffset, mSize, mVarIndex, mNumVars, mComplexity, mLocalSize, mAlignment; int mOffset, mSize, mVarIndex, mNumVars, mComplexity, mLocalSize, mAlignment;
int64 mInteger; int64 mInteger;
double mNumber; double mNumber;
uint32 mFlags; uint64 mFlags;
const Ident * mIdent; const Ident * mIdent;
LinkerSection * mSection; LinkerSection * mSection;
const uint8 * mData; const uint8 * mData;

View File

@ -2976,7 +2976,9 @@ void InterCodeBasicBlock::CollectEntryBlocks(InterCodeBasicBlock* from)
void InterCodeBasicBlock::BuildDominatorTree(InterCodeBasicBlock* from) void InterCodeBasicBlock::BuildDominatorTree(InterCodeBasicBlock* from)
{ {
if (!mDominator) if (from == this)
return;
else if (!mDominator)
mDominator = from; mDominator = from;
else if (from == mDominator) else if (from == mDominator)
return; return;
@ -7289,6 +7291,9 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa
hasCall = true; hasCall = true;
} }
GrowingArray<InterInstructionPtr> tvalues(nullptr);
GrowingArray<int> nassigns(0);
for (int i = 0; i < mInstructions.Size(); i++) for (int i = 0; i < mInstructions.Size(); i++)
{ {
InterInstruction* ins = mInstructions[i]; InterInstruction* ins = mInstructions[i];
@ -7320,7 +7325,24 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa
if (sins->mSrc[1].mTemp >= 0) if (sins->mSrc[1].mTemp >= 0)
{ {
if ((ins->mSrc[0].mMemory != IM_PARAM && ins->mSrc[0].mMemory != IM_FPARAM) || aliasedParams[ins->mSrc[0].mVarIndex]) 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) 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<Dependency> dep(DEP_UNKNOWN);
GrowingArray<int64> indexStep(0), indexBase(0); GrowingArray<int64> indexStep(0), indexBase(0);
GrowingArray<InterInstructionPtr> tvalues(nullptr); tvalues.SetSize(0);
for (int i = 0; i < mInstructions.Size(); i++) for (int i = 0; i < mInstructions.Size(); i++)
{ {

View File

@ -476,7 +476,7 @@ public:
GrowingTypeArray mTemporaries; GrowingTypeArray mTemporaries;
GrowingIntArray mTempOffset, mTempSizes; GrowingIntArray mTempOffset, mTempSizes;
int mTempSize, mCommonFrameSize, mCallerSavedTemps; 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; GrowingInterCodeProcedurePtrArray mCalledFunctions;
InterCodeModule * mModule; InterCodeModule * mModule;

View File

@ -3425,6 +3425,9 @@ InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod
if (dec->mFlags & DTF_INTERRUPT) if (dec->mFlags & DTF_INTERRUPT)
proc->mInterrupt = true; proc->mInterrupt = true;
if (dec->mFlags & DTF_HWINTERRUPT)
proc->mHardwareInterrupt = true;
if (dec->mBase->mFlags & DTF_FASTCALL) if (dec->mBase->mFlags & DTF_FASTCALL)
{ {
proc->mFastCallProcedure = true; proc->mFastCallProcedure = true;

View File

@ -13810,9 +13810,9 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
progress = true; progress = true;
} }
else if ( else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
(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 + 1].IsShift() &&
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 + 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 + 2].mType = mIns[i + 1].mType;
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; 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); mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal);
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++) for (int i = 2; i < 256; i++)
{ {
if (zpLocal[i]) if (zpLocal[i])
@ -15745,6 +15754,15 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, i)); 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 else
{ {
@ -15959,7 +15977,10 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
proc->mLinkerObject->mZeroPageSet = zpLocal; 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(); 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; const Ident* structName = nullptr;
@ -121,7 +121,7 @@ Declaration* Parser::ParseStructDeclaration(uint32 flags, DecType dt)
return dec; return dec;
} }
Declaration* Parser::ParseBaseTypeDeclaration(uint32 flags) Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags)
{ {
Declaration* dec = nullptr; Declaration* dec = nullptr;
@ -905,7 +905,7 @@ Expression* Parser::ParseInitExpression(Declaration* dtype)
Declaration* Parser::ParseDeclaration(bool variable) Declaration* Parser::ParseDeclaration(bool variable)
{ {
bool definingType = false; bool definingType = false;
uint32 storageFlags = 0, typeFlags = 0; uint64 storageFlags = 0, typeFlags = 0;
if (mScanner->mToken == TK_TYPEDEF) if (mScanner->mToken == TK_TYPEDEF)
{ {
@ -952,6 +952,11 @@ Declaration* Parser::ParseDeclaration(bool variable)
storageFlags |= DTF_INTERRUPT | DTF_NATIVE; storageFlags |= DTF_INTERRUPT | DTF_NATIVE;
mScanner->NextToken(); mScanner->NextToken();
} }
else if (mScanner->mToken == TK_HWINTERRUPT)
{
storageFlags |= DTF_INTERRUPT | DTF_HWINTERRUPT | DTF_NATIVE;
mScanner->NextToken();
}
else else
break; break;
} }
@ -1028,7 +1033,7 @@ Declaration* Parser::ParseDeclaration(bool variable)
{ {
if (!ndec->mBase->IsSame(pdec->mBase)) if (!ndec->mBase->IsSame(pdec->mBase))
mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function declaration differs", ndec->mIdent->mString); 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); mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function call type declaration differs", ndec->mIdent->mString);
else else
{ {

View File

@ -27,9 +27,9 @@ protected:
void ParsePragma(void); void ParsePragma(void);
Declaration* ParseBaseTypeDeclaration(uint32 flags); Declaration* ParseBaseTypeDeclaration(uint64 flags);
Declaration* ParseDeclaration(bool variable); Declaration* ParseDeclaration(bool variable);
Declaration* ParseStructDeclaration(uint32 flags, DecType dt); Declaration* ParseStructDeclaration(uint64 flags, DecType dt);
Declaration* CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp); Declaration* CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp);
Expression* ParseInitExpression(Declaration* dtype); Expression* ParseInitExpression(Declaration* dtype);

View File

@ -51,6 +51,7 @@ const char* TokenNames[] =
"__asm", "__asm",
"__interrupt", "__interrupt",
"__hwinterrupt",
"__native", "__native",
"__fastcall", "__fastcall",
"__export", "__export",
@ -1304,6 +1305,8 @@ void Scanner::NextRawToken(void)
mToken = TK_ASSUME; mToken = TK_ASSUME;
else if (!strcmp(tkident, "__interrupt")) else if (!strcmp(tkident, "__interrupt"))
mToken = TK_INTERRUPT; mToken = TK_INTERRUPT;
else if (!strcmp(tkident, "__hwinterrupt"))
mToken = TK_HWINTERRUPT;
else if (!strcmp(tkident, "__native")) else if (!strcmp(tkident, "__native"))
mToken = TK_NATIVE; mToken = TK_NATIVE;
else if (!strcmp(tkident, "__fastcall")) else if (!strcmp(tkident, "__fastcall"))

View File

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

View File

@ -73,7 +73,7 @@ int main2(int argc, const char** argv)
#else #else
strcpy(strProductName, "oscar64"); strcpy(strProductName, "oscar64");
strcpy(strProductVersion, "1.4.82"); strcpy(strProductVersion, "1.4.83");
#ifdef __APPLE__ #ifdef __APPLE__
uint32_t length = sizeof(basePath); uint32_t length = sizeof(basePath);
@ -245,18 +245,22 @@ int main2(int argc, const char** argv)
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
#ifdef _WIN32 #ifdef _WIN32
#ifndef _DEBUG
__try __try
{ {
#endif
#endif #endif
return main2(argc, argv); return main2(argc, argv);
#ifdef _WIN32 #ifdef _WIN32
} #ifndef _DEBUG
}
__except (EXCEPTION_EXECUTE_HANDLER) __except (EXCEPTION_EXECUTE_HANDLER)
{ {
printf("oscar64 crashed."); printf("oscar64 crashed.");
return 30; return 30;
} }
#endif #endif
#endif
} }

View File

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,82,0 FILEVERSION 1,4,83,0
PRODUCTVERSION 1,4,82,0 PRODUCTVERSION 1,4,83,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -43,12 +43,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "oscar64" VALUE "CompanyName", "oscar64"
VALUE "FileDescription", "oscar64 compiler" VALUE "FileDescription", "oscar64 compiler"
VALUE "FileVersion", "1.4.82.0" VALUE "FileVersion", "1.4.83.0"
VALUE "InternalName", "oscar64.exe" VALUE "InternalName", "oscar64.exe"
VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "oscar64.exe" VALUE "OriginalFilename", "oscar64.exe"
VALUE "ProductName", "oscar64" VALUE "ProductName", "oscar64"
VALUE "ProductVersion", "1.4.82.0" VALUE "ProductVersion", "1.4.83.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -3648,15 +3648,15 @@
{ {
"Name" = "8:Microsoft Visual Studio" "Name" = "8:Microsoft Visual Studio"
"ProductName" = "8:oscar64" "ProductName" = "8:oscar64"
"ProductCode" = "8:{D7EEA6AF-54FD-48A9-80AF-F19CA9A32D0E}" "ProductCode" = "8:{273BF824-E947-4B58-8992-6060F95D9EF7}"
"PackageCode" = "8:{497B8392-6DB9-4695-A4BC-E7E7CA9DCB8E}" "PackageCode" = "8:{3C6231C2-746F-4D40-83F7-159286D6BDB3}"
"UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}"
"AspNetVersion" = "8:2.0.50727.0" "AspNetVersion" = "8:2.0.50727.0"
"RestartWWWService" = "11:FALSE" "RestartWWWService" = "11:FALSE"
"RemovePreviousVersions" = "11:TRUE" "RemovePreviousVersions" = "11:TRUE"
"DetectNewerInstalledVersion" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE"
"InstallAllUsers" = "11:FALSE" "InstallAllUsers" = "11:FALSE"
"ProductVersion" = "8:1.4.82" "ProductVersion" = "8:1.4.83"
"Manufacturer" = "8:oscar64" "Manufacturer" = "8:oscar64"
"ARPHELPTELEPHONE" = "8:" "ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:" "ARPHELPLINK" = "8:"

Binary file not shown.