diff --git a/include/crt.c b/include/crt.c index 62e2b98..903104c 100644 --- a/include/crt.c +++ b/include/crt.c @@ -6,12 +6,58 @@ void StackStart, StackEnd, BSSStart, BSSEnd; #pragma section(stack, 0x0000, StackStart, StackEnd) #pragma section(bss, 0x0000, BSSStart, BSSEnd) -char spentry; +char spentry = 0; int main(void); +__asm inp_exit +{ + lda #$4c + sta $54 + lda #0 + sta $13 + rts +} + + __asm startup { +#ifdef OSCAR_TARGET_CRT16 + byt 0x09 + byt 0x80 + byt 0xbc + byt 0xfe + byt 0xc3 + byt 0xc2 + byt 0xcd + byt 0x38 + byt 0x30 + +// Copy cartridge rom to ram + + ldx #$40 + ldy #$00 + lda #$80 + sta ip + 1 + lda #$08 + sta sp + 1 + sty ip + sty sp +l0: lda (ip), y + sta (sp), y + iny + bne l0 + inc ip + 1 + inc sp + 1 + dex + bne l0 + lda $01 + and #$fc + ora #$02 + sta $01 + jmp w0 +w0: +#else byt 0x0b byt 0x08 byt 0x0a @@ -24,7 +70,7 @@ __asm startup byt 0x00 byt 0x00 byt 0x00 - +#endif // Clear BSS Segment tsx @@ -60,6 +106,21 @@ l2: dey bne l2 w2: + lda #StackEnd - 2 + sta sp + 1 + +#ifdef OSCAR_NATIVE_ALL + +// All native code + jsr main +pexec: +exec: + jmp inp_exit + +#else + // Init byte code lda #bcode sta ip + 1 - lda #StackEnd - 2 - sta sp + 1 pexec: ldy #0 exec: @@ -96,6 +153,7 @@ bcode: byt >main byt BC_CALL * 2 byt BC_EXIT * 2 +#endif } #pragma startup(startup) @@ -561,15 +619,6 @@ __asm inp_nop #pragma bytecode(BC_NOP, inp_nop) -__asm inp_exit -{ - lda #$4c - sta $54 - lda #0 - sta $13 - rts -} - #pragma bytecode(BC_EXIT, inp_exit) __asm inp_jsr diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index 939856b..1e3fb6d 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -3670,6 +3670,15 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) mIns[i + 1].mCode = BC_NOP; progress = true; } + else if ( + mIns[i + 0].mCode == BC_STORE_REG_16 && + mIns[i + 1].LoadsRegister(BC_REG_ACCU) && + mIns[i + 2].IsCommutative() && mIns[i].mRegister == mIns[i + 2].mRegister && mIns[i + 2].mRegisterFinal) + { + mIns[i + 0].mCode = BC_NOP; + mIns[i + 1].mRegister = mIns[i + 0].mRegister; + progress = true; + } } #endif #if 1 @@ -3765,6 +3774,23 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) mIns[i].mCode = BC_NOP; progress = true; } + else if ((mIns[i].mCode == BC_CONST_16 || mIns[i].mCode == BC_CONST_P8 || mIns[i].mCode == BC_CONST_N8) && + (mIns[i + 1].mCode == BC_CONST_16 || mIns[i + 1].mCode == BC_CONST_P8 || mIns[i + 1].mCode == BC_CONST_N8 || mIns[i + 1].mCode == BC_CONST_32) && mIns[i].mRegister == mIns[i + 1].mRegister) + { + mIns[i].mCode = BC_NOP; + progress = true; + } + else if (mIns[i].mCode == BC_CONST_32 && mIns[i + 1].mCode == BC_CONST_32 && mIns[i].mRegister == mIns[i + 1].mRegister) + { + mIns[i].mCode = BC_NOP; + progress = true; + } + else if (mIns[i].mCode == BC_CONST_8 && mIns[i + 1].mCode == BC_CONST_8 && mIns[i].mRegister == mIns[i + 1].mRegister) + { + mIns[i].mCode = BC_NOP; + progress = true; + } + #if 0 else if ((mIns[i].mCode == BC_LOAD_LOCAL_16 || mIns[i].mCode == BC_LOAD_ABS_16) && mIns[i + 1].mCode == BC_ADDR_REG && mIns[i].mRegister == mIns[i + 1].mRegister && mIns[i + 1].mRegisterFinal) { diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 5778a78..77111d0 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -123,25 +123,45 @@ bool Compiler::GenerateCode(void) const Ident* identCode = Ident::Unique("code"); LinkerRegion* regionStartup = mLinker->FindRegion(identStartup); - if (!regionStartup) - regionStartup = mLinker->AddRegion(identStartup, 0x0801, 0x0900); - - LinkerRegion* regionBytecode = mLinker->FindRegion(identBytecode); - if (!regionBytecode) - regionBytecode = mLinker->AddRegion(identBytecode, 0x0900, 0x0a00); + if (!regionStartup) + { + if (mCompilerOptions & COPT_TARGET_PRG) + regionStartup = mLinker->AddRegion(identStartup, 0x0801, 0x0900); + else + regionStartup = mLinker->AddRegion(identStartup, 0x0800, 0x0900); + } + + LinkerRegion* regionBytecode = nullptr; + if (!(mCompilerOptions & COPT_NATIVE)) + { + regionBytecode = mLinker->FindRegion(identBytecode); + if (!regionBytecode) + regionBytecode = mLinker->AddRegion(identBytecode, 0x0900, 0x0a00); + } LinkerRegion* regionMain = mLinker->FindRegion(identMain); LinkerSection * sectionStartup = mLinker->AddSection(identStartup, LST_DATA); - LinkerSection * sectionBytecode = mLinker->AddSection(identBytecode, LST_DATA); + LinkerSection* sectionBytecode = nullptr; + if (regionBytecode) + { + sectionBytecode = mLinker->AddSection(identBytecode, LST_DATA); + } regionStartup->mSections.Push(sectionStartup); - regionBytecode->mSections.Push(sectionBytecode); + + if (regionBytecode) + regionBytecode->mSections.Push(sectionBytecode); if (!mLinker->IsSectionPlaced(mCompilationUnits->mSectionCode)) { if (!regionMain) - regionMain = mLinker->AddRegion(identMain, 0x0a00, 0xa000); + { + if (regionBytecode) + regionMain = mLinker->AddRegion(identMain, 0x0a00, 0xa000); + else + regionMain = mLinker->AddRegion(identMain, 0x0900, 0xa000); + } regionMain->mSections.Push(mCompilationUnits->mSectionCode); regionMain->mSections.Push(mCompilationUnits->mSectionData); @@ -239,49 +259,53 @@ bool Compiler::GenerateCode(void) } } - // Compile used byte code functions - - LinkerObject* byteCodeObject = mLinker->AddObject(loc, Ident::Unique("bytecode"), sectionBytecode, LOT_RUNTIME); - - for (int i = 0; i < 128; i++) + LinkerObject* byteCodeObject = nullptr; + if (!(mCompilerOptions & COPT_NATIVE)) { - if (mByteCodeGenerator->mByteCodeUsed[i]) + // Compile used byte code functions + + byteCodeObject = mLinker->AddObject(loc, Ident::Unique("bytecode"), sectionBytecode, LOT_RUNTIME); + + for (int i = 0; i < 128; i++) { - Declaration* bcdec = mCompilationUnits->mByteCodes[i]; - if (bcdec) + if (mByteCodeGenerator->mByteCodeUsed[i]) { - LinkerObject* linkerObject = nullptr; - - int offset = 0; - if (bcdec->mType == DT_CONST_ASSEMBLER) + Declaration* bcdec = mCompilationUnits->mByteCodes[i]; + if (bcdec) { - if (!bcdec->mLinkerObject) - mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mValue, nullptr); - linkerObject = bcdec->mLinkerObject; + LinkerObject* linkerObject = nullptr; + + int offset = 0; + if (bcdec->mType == DT_CONST_ASSEMBLER) + { + if (!bcdec->mLinkerObject) + mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mValue, nullptr); + linkerObject = bcdec->mLinkerObject; + } + else if (bcdec->mType == DT_LABEL) + { + if (!bcdec->mBase->mLinkerObject) + mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mBase->mValue, nullptr); + linkerObject = bcdec->mBase->mLinkerObject; + offset = bcdec->mInteger; + } + + assert(linkerObject); + + LinkerReference lref; + lref.mObject = byteCodeObject; + lref.mFlags = LREF_HIGHBYTE | LREF_LOWBYTE; + lref.mOffset = 2 * i; + lref.mRefObject = linkerObject; + lref.mRefOffset = offset; + byteCodeObject->AddReference(lref); } - else if (bcdec->mType == DT_LABEL) + else { - if (!bcdec->mBase->mLinkerObject) - mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mBase->mValue, nullptr); - linkerObject = bcdec->mBase->mLinkerObject; - offset = bcdec->mInteger; + char n[10]; + sprintf_s(n, "%d", i); + mErrors->Error(loc, EERR_RUNTIME_CODE, "Missing byte code implementation", n); } - - assert(linkerObject); - - LinkerReference lref; - lref.mObject = byteCodeObject; - lref.mFlags = LREF_HIGHBYTE | LREF_LOWBYTE; - lref.mOffset = 2 * i; - lref.mRefObject = linkerObject; - lref.mRefOffset = offset; - byteCodeObject->AddReference(lref); - } - else - { - char n[10]; - sprintf_s(n, "%d", i); - mErrors->Error(loc, EERR_RUNTIME_CODE, "Missing byte code implementation", n); } } } @@ -289,7 +313,9 @@ bool Compiler::GenerateCode(void) mLinker->CollectReferences(); mLinker->ReferenceObject(dcrtstart->mLinkerObject); - mLinker->ReferenceObject(byteCodeObject); + + if (!(mCompilerOptions & COPT_NATIVE)) + mLinker->ReferenceObject(byteCodeObject); mLinker->Link(); @@ -298,7 +324,7 @@ bool Compiler::GenerateCode(void) bool Compiler::WriteOutputFile(const char* targetPath) { - char prgPath[200], mapPath[200], asmPath[200], lblPath[200]; + char prgPath[200], mapPath[200], asmPath[200], lblPath[200], crtPath[200]; strcpy_s(prgPath, targetPath); int i = strlen(prgPath); @@ -309,14 +335,25 @@ bool Compiler::WriteOutputFile(const char* targetPath) strcpy_s(mapPath, prgPath); strcpy_s(asmPath, prgPath); strcpy_s(lblPath, prgPath); + strcpy_s(crtPath, prgPath); strcat_s(prgPath, "prg"); strcat_s(mapPath, "map"); strcat_s(asmPath, "asm"); strcat_s(lblPath, "lbl"); + strcat_s(crtPath, "crt"); + + if (mCompilerOptions & COPT_TARGET_PRG) + { + printf("Writing <%s>\n", prgPath); + mLinker->WritePrgFile(prgPath); + } + else if (mCompilerOptions & COPT_TARGET_CRT16) + { + printf("Writing <%s>\n", crtPath); + mLinker->WriteCrtFile(crtPath); + } - printf("Writing <%s>\n", prgPath); - mLinker->WritePrgFile(prgPath); printf("Writing <%s>\n", mapPath); mLinker->WriteMapFile(mapPath); @@ -336,10 +373,21 @@ int Compiler::ExecuteCode(void) printf("Running emulation...\n"); Emulator* emu = new Emulator(mLinker); - memcpy(emu->mMemory + mLinker->mProgramStart, mLinker->mMemory + mLinker->mProgramStart, mLinker->mProgramEnd - mLinker->mProgramStart); - emu->mMemory[0x2d] = mLinker->mProgramEnd & 0xff; - emu->mMemory[0x2e] = mLinker->mProgramEnd >> 8; - int ecode = emu->Emulate(2061); + + int ecode = 20; + if (mCompilerOptions & COPT_TARGET_PRG) + { + memcpy(emu->mMemory + mLinker->mProgramStart, mLinker->mMemory + mLinker->mProgramStart, mLinker->mProgramEnd - mLinker->mProgramStart); + emu->mMemory[0x2d] = mLinker->mProgramEnd & 0xff; + emu->mMemory[0x2e] = mLinker->mProgramEnd >> 8; + ecode = emu->Emulate(2061); + } + else if (mCompilerOptions & COPT_TARGET_CRT16) + { + memcpy(emu->mMemory + 0x8000, mLinker->mMemory + 0x0800, 0x4000); + ecode = emu->Emulate(0x8009); + } + printf("Emulation result %d\n", ecode); if (ecode != 0) diff --git a/oscar64/CompilerTypes.h b/oscar64/CompilerTypes.h index 9fffd9e..b05ae2a 100644 --- a/oscar64/CompilerTypes.h +++ b/oscar64/CompilerTypes.h @@ -8,6 +8,11 @@ static const uint64 COPT_OPTIMIZE_INLINE = 0x00000002; static const uint64 COPT_OPTIMIZE_AUTO_INLINE = 0x00000010; static const uint64 COPT_OPTIMIZE_AUTO_INLINE_ALL = 0x00000020; +static const uint64 COPT_TARGET_PRG = 0x100000000ULL; +static const uint64 COPT_TARGET_CRT16 = 0x200000000ULL; +static const uint64 COPT_TARGET_CRT512 = 0x400000000ULL; +static const uint64 COPT_TARGET_COPY = 0x800000000ULL; + static const uint64 COPT_NATIVE = 0x01000000; static const uint64 COPT_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE; diff --git a/oscar64/GlobalAnalyzer.cpp b/oscar64/GlobalAnalyzer.cpp index 13a675f..8215f0c 100644 --- a/oscar64/GlobalAnalyzer.cpp +++ b/oscar64/GlobalAnalyzer.cpp @@ -197,7 +197,7 @@ void GlobalAnalyzer::AnalyzeAssembler(Expression* exp, Declaration* procDec) else if (adec->mType == DT_CONST_FUNCTION) { AnalyzeProcedure(adec->mValue, adec); - RegisterCall(adec, procDec); + RegisterCall(procDec, adec); } } diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index 1add59d..fda91d4 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -333,6 +333,98 @@ bool Linker::WritePrgFile(const char* filename) return false; } +bool Linker::WriteCrtFile(const char* filename) +{ + FILE* file; + fopen_s(&file, filename, "wb"); + if (file) + { + struct CRIHeader + { + char mSignature[16]; + uint32 mHeaderLength; + uint16 mVersion, mHardware; + uint8 mExrom, mGameLine; + uint8 mPad[6]; + char mName[32]; + } criHeader = { 0 }; + + memcpy(criHeader.mSignature, "C64 CARTRIDGE ", 16); + criHeader.mHeaderLength = 0x40000000; + criHeader.mVersion = 0x0001; + criHeader.mHardware = 0x2000; + criHeader.mExrom = 1; + criHeader.mGameLine = 1; + memset(criHeader.mName, 0, 32); + strcpy_s(criHeader.mName, "OSCAR"); + + fwrite(&criHeader, sizeof(CRIHeader), 1, file); + + struct CHIPHeader + { + char mSignature[4]; + uint32 mPacketLength; + uint16 mChipType, mBankNumber, mLoadAddress, mImageSize; + } chipHeader = { 0 }; + + memcpy(chipHeader.mSignature, "CHIP", 4); + chipHeader.mPacketLength = 0x10200000; + chipHeader.mChipType = 0; + chipHeader.mBankNumber = 0; + chipHeader.mImageSize = 0x0020; + + char * bootmem = new char[8192]; + + chipHeader.mLoadAddress = 0x0080; + fwrite(&chipHeader, sizeof(chipHeader), 1, file); + fwrite(bootmem, 1, 0x2000, file); + + bootmem[0x1ffc] = 0x00; + bootmem[0x1ffd] = 0xe0; + + char bootcode[] = { + 0xa9, 0x87, + 0x8d, 0x02, 0xde, + 0xa9, 0x01, + 0x8d, 0x00, 0xde, + 0x6c, 0xfc, 0xff + }; + + int j = 0; + for (int i = 0; i < sizeof(bootcode); i++) + { + bootmem[j++] = 0xa9; + bootmem[j++] = bootcode[i]; + bootmem[j++] = 0x8d; + bootmem[j++] = i; + bootmem[j++] = 0x04; + } + bootmem[j++] = 0x4c; + bootmem[j++] = 0x00; + bootmem[j++] = 0x04; + + chipHeader.mLoadAddress = 0x00e0; + fwrite(&chipHeader, sizeof(chipHeader), 1, file); + fwrite(bootmem, 1, 0x2000, file); + + chipHeader.mBankNumber = 0x100; + + chipHeader.mLoadAddress = 0x0080; + fwrite(&chipHeader, sizeof(chipHeader), 1, file); + fwrite(mMemory + 0x0800, 1, 0x2000, file); + + chipHeader.mLoadAddress = 0x00a0; + fwrite(&chipHeader, sizeof(chipHeader), 1, file); + fwrite(mMemory + 0x2800, 1, 0x2000, file); + + fclose(file); + return true; + } + else + return false; +} + + bool Linker::WriteMapFile(const char* filename) { FILE* file; diff --git a/oscar64/Linker.h b/oscar64/Linker.h index 38805dd..79692ee 100644 --- a/oscar64/Linker.h +++ b/oscar64/Linker.h @@ -130,6 +130,7 @@ public: bool WriteMapFile(const char* filename); bool WriteAsmFile(const char* filename); bool WriteLblFile(const char* filename); + bool WriteCrtFile(const char* filename); GrowingArray mReferences; GrowingArray mRegions; diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index 5cf8b28..aa9ad02 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -978,7 +978,7 @@ void Scanner::NextRawToken(void) case '#': { - if (!mAssemblerMode || mOffset == 1) + if (!(mAssemblerMode || mPrepCondFalse) || mOffset == 1) { int n = 0; char tkprep[128]; diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 9d466c1..8d42229 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -116,6 +116,9 @@ int main(int argc, const char** argv) targetPath[0] = 0; + char targetFormat[20]; + strcpy_s(targetFormat, "prg"); + for (int i = 1; i < argc; i++) { const char* arg = argv[i]; @@ -133,9 +136,14 @@ int main(int argc, const char** argv) { strcpy_s(crtPath, arg + 4); } + else if (arg[1] == 't' && arg[2] == 'f' && arg[3] == '=') + { + strcpy_s(targetFormat, arg + 4); + } else if (arg[1] == 'n') { compiler->mCompilerOptions |= COPT_NATIVE; + compiler->AddDefine(Ident::Unique("OSCAR_NATIVE_ALL"), "1"); } else if (arg[1] == 'O') { @@ -180,16 +188,32 @@ int main(int argc, const char** argv) } } - // Add runtime module - - compiler->mCompilationUnits->AddUnit(loc, crtPath, nullptr); - - if (compiler->ParseSource() && compiler->GenerateCode()) + if (!strcmp(targetFormat, "prg")) { - compiler->WriteOutputFile(targetPath); + compiler->mCompilerOptions |= COPT_TARGET_PRG; + compiler->AddDefine(Ident::Unique("OSCAR_TARGET_PRG"), "1"); + } + else if (!strcmp(targetFormat, "crt")) + { + compiler->mCompilerOptions |= COPT_TARGET_CRT16; + compiler->AddDefine(Ident::Unique("OSCAR_TARGET_CRT16"), "1"); + } + else + compiler->mErrors->Error(loc, EERR_COMMAND_LINE, "Invalid target format option", targetFormat); - if (emulate) - compiler->ExecuteCode(); + if (compiler->mErrors->mErrorCount == 0) + { + // Add runtime module + + compiler->mCompilationUnits->AddUnit(loc, crtPath, nullptr); + + if (compiler->ParseSource() && compiler->GenerateCode()) + { + compiler->WriteOutputFile(targetPath); + + if (emulate) + compiler->ExecuteCode(); + } } if (compiler->mErrors->mErrorCount != 0)