diff --git a/README.md b/README.md index 29f712f..1227d3a 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,11 @@ A list of source files can be provided. * pet: Commodore PET, 8K RAM (0x0400..0x2000) * pet16 : Commodore PET, 16K RAM (0x0400..0x4000) * pet32 : Commodore PET, 32K RAM (0x0400..0x8000) -* nes : Nintendo entertainment system, NROM 32 K ROM +* nes : Nintendo entertainment system, NROM 32 K ROM, no mirror +* nes_nrom_h : Nintendo entertainment system, NROM 32 K ROM, h mirror +* nes_nrom_v : Nintendo entertainment system, NROM 32 K ROM, v mirror +* nes_mmc1 : Nintendo entertainment system, MMC1, 256K PROM, 128K CROM +* nes_mmc3 : Nintendo entertainment system, MMC3, 512K PROM, 256K CROM * atari : Atari 8bit systems, (0x2000..0xbc00) ### Files generated @@ -482,6 +486,50 @@ The overlay file can then be loaded in memory during program execution: krnio_setnam(P"OVL1"); krnio_load(1, 8, 1); +#### NES ROM Banks + +With NROM mappers, the prg and chr code is put into cartridge bank zero. + + #pragma section( tiles, 0 ) + + #pragma region( tbank, 0x0000, 0x2000, , 0, { tiles } ) + + #pragma data(tiles) + + __export char tiles[] = { + #embed "nesmini.chr" + }; + + #pragma data(data) + +The 32KByte of prg code starts at 0x8000 and goes upto 0xff80. A startup section from 0xff80 to 0xfff9 is taken from the crt.c. + +A six byte boot section is placed from 0xfffa to 0xffff in all modes, which has to be populated by the game code with the appropriate pointers. + + #pragma data(boot) + + __export struct Boot + { + void * nmi, * reset, * irq; + } boot = { + nmi, + (void *)0xff80, + nullptr + }; + + #pragma data(data) + +Rom mappers MMC1 and MMC3 share the last rom bank from 0xc000 to 0xffff including the boot section. This is bank 15 in MMC1 and bank 31 in MMC3. + +The pageable ROM is assumed to be 0x8000 to 0xbfff in all banks from zero up. + + #pragma section( code0, 0 ) + #pragma region( code0, 0x8000, 0xc000, , 0, { code0 } ) + +And for bank one + + #pragma section( code1, 0 ) + #pragma region( code1, 0x8000, 0xc000, , 1, { code1 } ) ### Inline Assembler diff --git a/include/crt.c b/include/crt.c index 3e78b24..c0fd628 100644 --- a/include/crt.c +++ b/include/crt.c @@ -171,6 +171,10 @@ w0: #elif defined(OSCAR_TARGET_NES) sei cld +#if defined(__NES_MMC3__) + lda #$00 + sta $8000 +#endif #else byt 0x0b byt 0x08 diff --git a/include/nes/mmc1.c b/include/nes/mmc1.c new file mode 100644 index 0000000..94a14a9 --- /dev/null +++ b/include/nes/mmc1.c @@ -0,0 +1,60 @@ +#include "mmc1.h" + + +void mmc1_reset(void) +{ + *(volatile char *)0x8000 = 0x80; +} + +void mmc1_config(MMC1Mirror mirror, MMC1MPrgMode pmode, MMC1MChrMode cmode) +{ + char reg = mirror | (pmode << 2) | (cmode << 4); + *(volatile char *)0x8000 = reg; + reg >>= 1; + *(volatile char *)0x8000 = reg; + reg >>= 1; + *(volatile char *)0x8000 = reg; + reg >>= 1; + *(volatile char *)0x8000 = reg; + reg >>= 1; + *(volatile char *)0x8000 = reg; +} + +void mmc1_bank_prg(char bank) +{ + *(volatile char *)0xe000 = bank; + bank >>= 1; + *(volatile char *)0xe000 = bank; + bank >>= 1; + *(volatile char *)0xe000 = bank; + bank >>= 1; + *(volatile char *)0xe000 = bank; + bank >>= 1; + *(volatile char *)0xe000 = bank; +} + +void mmc1_bank_chr0(char bank) +{ + *(volatile char *)0xa000 = bank; + bank >>= 1; + *(volatile char *)0xa000 = bank; + bank >>= 1; + *(volatile char *)0xa000 = bank; + bank >>= 1; + *(volatile char *)0xa000 = bank; + bank >>= 1; + *(volatile char *)0xa000 = bank; +} + +void mmc1_bank_chr1(char bank) +{ + *(volatile char *)0xc000 = bank; + bank >>= 1; + *(volatile char *)0xc000 = bank; + bank >>= 1; + *(volatile char *)0xc000 = bank; + bank >>= 1; + *(volatile char *)0xc000 = bank; + bank >>= 1; + *(volatile char *)0xc000 = bank; +} diff --git a/include/nes/mmc1.h b/include/nes/mmc1.h new file mode 100644 index 0000000..b302d17 --- /dev/null +++ b/include/nes/mmc1.h @@ -0,0 +1,41 @@ +#ifndef NES_MMC1_H +#define NES_MMC1_H + + +#include + +enum MMC1Mirror +{ + MMC1M_LOWER, + MMC1M_UPPER, + MMC1M_VERTICAL, + MMC1M_HORIZONTAL +}; + +enum MMC1MPrgMode +{ + MMC1P_32K, + MMC1P_32Kx, + MMC1P_16K_UPPER, + MMC1P_16K_LOWER +}; + +enum MMC1MChrMode +{ + MMC1C_8K, + MMC1C_4Kx, +}; + +void mmc1_reset(void); + +void mmc1_config(MMC1Mirror mirror, MMC1MPrgMode pmode, MMC1MChrMode cmode); + +void mmc1_bank_prg(char bank); + +void mmc1_bank_chr0(char bank); + +void mmc1_bank_chr1(char bank); + +#pragma compile("mmc1.c") + +#endif diff --git a/include/nes/mmc3.c b/include/nes/mmc3.c new file mode 100644 index 0000000..08b0f0c --- /dev/null +++ b/include/nes/mmc3.c @@ -0,0 +1,36 @@ +#include "mmc3.h" + +char mmc3_shadow; + +void mmc3_reset(void) +{ + mmc3_shadow = 0; +} + +void mmc3_config(MMC3MPrgMode pmode, MMC3MChrMode cmode) +{ + mmc3_shadow = (pmode << 6) | (cmode << 7); + *(volatile char *)0x8000 = mmc3_shadow; +} + +void mmc3_bank(MMC3BankReg reg, char bank) +{ + *(volatile char *)0x8000 = reg | mmc3_shadow; + *(volatile char *)0x8001 = bank; +} + +void mmc3_bank_prg(char bank) +{ + mmc3_bank(MMC3B_PRG0, bank * 2 + 0); + mmc3_bank(MMC3B_PRG1, bank * 2 + 1); +} + +void mmc3_bank_chr0(char bank) +{ + mmc3_bank(MMC3B_CHR0, bank); +} + +void mmc3_bank_chr1(char bank) +{ + mmc3_bank(MMC3B_CHR1, bank); +} diff --git a/include/nes/mmc3.h b/include/nes/mmc3.h new file mode 100644 index 0000000..70b2d0e --- /dev/null +++ b/include/nes/mmc3.h @@ -0,0 +1,48 @@ +#ifndef NES_MMC3_H +#define NES_MMC3_H + +#include + + +enum MMC3MPrgMode +{ + MMC3P_8K_LOWER, + MMC3P_8K_UPPER +}; + +enum MMC3MChrMode +{ + MMC3C_2K_LOWER, + MMC3C_2K_HIGHER, +}; + +enum MMC3BankReg +{ + MMC3B_CHR0, + MMC3B_CHR1, + MMC3B_CHR2, + MMC3B_CHR3, + MMC3B_CHR4, + MMC3B_CHR5, + + MMC3B_PRG0, + MMC3B_PRG1 +}; + +extern char mmc3_shadow; + +void mmc3_reset(void); + +void mmc3_config(MMC3MPrgMode pmode, MMC3MChrMode cmode); + +inline void mmc3_bank(MMC3BankReg reg, char bank); + +void mmc3_bank_prg(char bank); + +void mmc3_bank_chr0(char bank); + +void mmc3_bank_chr1(char bank); + +#pragma compile("mmc3.c") + +#endif diff --git a/include/nes/neslib.c b/include/nes/neslib.c index b62b324..4bac40b 100644 --- a/include/nes/neslib.c +++ b/include/nes/neslib.c @@ -641,7 +641,7 @@ __export struct Boot void * nmi, * reset, * irq; } boot = { nmi, - (void *)0x8000, + (void *)0xff80, nullptr }; diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 38f87d6..690df10 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -103,6 +103,10 @@ bool Compiler::ParseSource(void) mCompilationUnits->mSectionLowCode = mLinker->AddSection(Ident::Unique("lowcode"), LST_DATA); break; case TMACH_NES: + case TMACH_NES_NROM_H: + case TMACH_NES_NROM_V: + case TMACH_NES_MMC1: + case TMACH_NES_MMC3: mCompilationUnits->mSectionStack->mSize = 256; mCompilationUnits->mSectionHeap->mSize = 256; mCompilationUnits->mSectionBoot = mLinker->AddSection(Ident::Unique("boot"), LST_DATA); @@ -239,7 +243,7 @@ bool Compiler::GenerateCode(void) if (!regionStartup) { - if (mCompilerOptions & COPT_TARGET_PRG) + if (mCompilerOptions & (COPT_TARGET_PRG | COPT_TARGET_NES)) { switch (mTargetMachine) { @@ -310,10 +314,22 @@ bool Compiler::GenerateCode(void) else regionStartup = mLinker->AddRegion(identStartup, 0x2000, 0x2100); break; + case TMACH_NES: + case TMACH_NES_NROM_H: + case TMACH_NES_NROM_V: + regionStartup = mLinker->AddRegion(identStartup, 0xff80, 0xfffa); + regionStartup->mCartridgeBanks = 1; + break; + case TMACH_NES_MMC1: + regionStartup = mLinker->AddRegion(identStartup, 0xff80, 0xfffa); + regionStartup->mCartridgeBanks = 1ULL << 15; + break; + case TMACH_NES_MMC3: + regionStartup = mLinker->AddRegion(identStartup, 0xff80, 0xfffa); + regionStartup->mCartridgeBanks = 1ULL << 31; + break; } } - else if (mTargetMachine == TMACH_NES) - regionStartup = mLinker->AddRegion(identStartup, 0x8000, 0x8080); else regionStartup = mLinker->AddRegion(identStartup, 0x0800, 0x0900); } @@ -377,14 +393,7 @@ bool Compiler::GenerateCode(void) { if (!regionMain) { - if (mTargetMachine == TMACH_NES) - { - regionBoot = mLinker->AddRegion(identBoot, 0xfffa, 0x10000); - regionBoot->mSections.Push(mCompilationUnits->mSectionBoot); - regionRom = mLinker->AddRegion(identRom, 0x8080, 0xfffa); - regionMain = mLinker->AddRegion(identMain, 0x0200, 0x0800); - } - else if (!(mCompilerOptions & COPT_TARGET_PRG)) + if (!(mCompilerOptions & (COPT_TARGET_PRG | COPT_TARGET_NES))) regionMain = mLinker->AddRegion(identMain, 0x0900, 0x4700); else if (regionBytecode) { @@ -474,6 +483,32 @@ bool Compiler::GenerateCode(void) case TMACH_ATARI: regionMain = mLinker->AddRegion(identMain, 0x2080, 0xbc00); break; + case TMACH_NES: + case TMACH_NES_NROM_H: + case TMACH_NES_NROM_V: + regionBoot = mLinker->AddRegion(identBoot, 0xfffa, 0x10000); + regionBoot->mCartridgeBanks = 1; + regionBoot->mSections.Push(mCompilationUnits->mSectionBoot); + regionRom = mLinker->AddRegion(identRom, 0x8000, 0xff80); + regionRom->mCartridgeBanks = 1; + regionMain = mLinker->AddRegion(identMain, 0x0200, 0x0800); + break; + case TMACH_NES_MMC1: + regionBoot = mLinker->AddRegion(identBoot, 0xfffa, 0x10000); + regionBoot->mCartridgeBanks = 1ULL << 15; + regionBoot->mSections.Push(mCompilationUnits->mSectionBoot); + regionRom = mLinker->AddRegion(identRom, 0xc000, 0xff80); + regionRom->mCartridgeBanks = 1ULL << 15; + regionMain = mLinker->AddRegion(identMain, 0x0200, 0x0800); + break; + case TMACH_NES_MMC3: + regionBoot = mLinker->AddRegion(identBoot, 0xfffa, 0x10000); + regionBoot->mCartridgeBanks = 1ULL << 31; + regionBoot->mSections.Push(mCompilationUnits->mSectionBoot); + regionRom = mLinker->AddRegion(identRom, 0xc000, 0xff80); + regionRom->mCartridgeBanks = 1ULL << 31; + regionMain = mLinker->AddRegion(identMain, 0x0200, 0x0800); + break; } } } @@ -828,7 +863,7 @@ bool Compiler::WriteOutputFile(const char* targetPath, DiskImage * d64) strcat_s(prgPath, "nes"); if (mCompilerOptions & COPT_VERBOSE) printf("Writing <%s>\n", prgPath); - mLinker->WriteNesFile(prgPath); + mLinker->WriteNesFile(prgPath, mTargetMachine); } @@ -859,7 +894,7 @@ bool Compiler::WriteOutputFile(const char* targetPath, DiskImage * d64) printf("Writing <%s>\n", lblPath); if (mCompilerOptions & COPT_TARGET_NES) - mLinker->WriteMlbFile(lblPath); + mLinker->WriteMlbFile(lblPath, mTargetMachine); else mLinker->WriteLblFile(lblPath); diff --git a/oscar64/CompilerTypes.h b/oscar64/CompilerTypes.h index d4e99b8..415c74b 100644 --- a/oscar64/CompilerTypes.h +++ b/oscar64/CompilerTypes.h @@ -54,6 +54,10 @@ enum TargetMachine TMACH_PET_32K, TMACH_PLUS4, TMACH_NES, + TMACH_NES_NROM_H, + TMACH_NES_NROM_V, + TMACH_NES_MMC1, + TMACH_NES_MMC3, TMACH_ATARI }; diff --git a/oscar64/Disassembler.cpp b/oscar64/Disassembler.cpp index 030841a..1b63d36 100644 --- a/oscar64/Disassembler.cpp +++ b/oscar64/Disassembler.cpp @@ -86,7 +86,7 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int bank { ByteCode bc = ByteCode(memory[start + i] / 2); - if (bank) + if (bank >= 0) fprintf(file, "%02x:", bank); fprintf(file, "%04x:\t", start + i); @@ -627,7 +627,7 @@ void NativeCodeDisassembler::DumpMemory(FILE* file, const uint8* memory, int ban if (lobj->mSection->mType == LST_BSS) { - if (bank) + if (bank >= 0) fprintf(file, "%02x:", bank); fprintf(file, "%04x : __ __ __ BSS\t%d\n", start, size); @@ -641,7 +641,7 @@ void NativeCodeDisassembler::DumpMemory(FILE* file, const uint8* memory, int ban if (ip + n > start + size) n = start + size - ip; - if (bank) + if (bank >= 0) fprintf(file, "%02x:", bank); fprintf(file, "%04x : __ __ __ BYT", ip); @@ -693,7 +693,7 @@ void NativeCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int ba fprintf(file, ".%s:\n", proc->mLinkerObject->mRanges[i].mIdent->mString); } - if (bank) + if (bank >= 0) fprintf(file, "%02x:", bank); switch (d.mMode) diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index 0164ea6..a31933f 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -611,7 +611,7 @@ bool Linker::WriteBinFile(const char* filename) return false; } -bool Linker::WriteNesFile(const char* filename) +bool Linker::WriteNesFile(const char* filename, TargetMachine machine) { FILE* file; fopen_s(&file, filename, "wb"); @@ -619,12 +619,57 @@ bool Linker::WriteNesFile(const char* filename) { char header[16] = { 0x4e, 0x45, 0x53, 0x1a, 0x02, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00 }; - fwrite(header, 1, 16, file); - int done = fwrite(mMemory + 0x8000, 1, 0x8000, file); - done += fwrite(mCartridge[0], 1, 0x2000, file); + switch (machine) + { + case TMACH_NES: + header[6] = 0x08; + break; + case TMACH_NES_NROM_H: + header[6] = 0x00; + break; + case TMACH_NES_NROM_V: + header[6] = 0x01; + break; + case TMACH_NES_MMC1: + header[4] = 16; + header[5] = 16; + header[6] = 0x10; + break; + case TMACH_NES_MMC3: + header[4] = 32; + header[5] = 32; + header[6] = 0x48; + break; + } + + int done = fwrite(header, 1, 16, file); + + switch (machine) + { + case TMACH_NES: + case TMACH_NES_NROM_H: + case TMACH_NES_NROM_V: + fwrite(mCartridge[0] + 0x8000, 1, 0x8000, file); + fwrite(mCartridge[0], 1, 0x2000, file); + break; + case TMACH_NES_MMC1: + for(int i=0; i<15; i++) + fwrite(mCartridge[i] + 0x8000, 1, 0x4000, file); + fwrite(mCartridge[15] + 0xc000, 1, 0x4000, file); + for (int i = 0; i < 16; i++) + fwrite(mCartridge[i], 1, 0x2000, file); + break; + case TMACH_NES_MMC3: + for (int i = 0; i < 31; i++) + fwrite(mCartridge[i] + 0x8000, 1, 0x4000, file); + fwrite(mCartridge[31] + 0xc000, 1, 0x4000, file); + for (int i = 0; i < 32; i++) + fwrite(mCartridge[i], 1, 0x2000, file); + break; + } fclose(file); - return done == 0x8000 + 0x2000; + return done == 16; } else return false; @@ -944,7 +989,29 @@ bool Linker::WriteMapFile(const char* filename) return false; } -bool Linker::WriteMlbFile(const char* filename) +int Linker::TranslateMlbAddress(int address, int bank, TargetMachine machine) +{ + switch (machine) + { + default: + case TMACH_NES: + case TMACH_NES_NROM_H: + case TMACH_NES_NROM_V: + return address - 0x8000; + case TMACH_NES_MMC1: + if (bank == 15) + return 15 * 0x4000 + address - 0xc000; + else + return bank * 0x4000 + address - 0x8000; + case TMACH_NES_MMC3: + if (bank == 31) + return 31 * 0x4000 + address - 0xc000; + else + return bank * 0x4000 + address - 0x8000; + } +} + +bool Linker::WriteMlbFile(const char* filename, TargetMachine machine) { FILE* file; fopen_s(&file, filename, "wb"); @@ -964,6 +1031,12 @@ bool Linker::WriteMlbFile(const char* filename) if ((obj->mFlags & LOBJF_REFERENCED) && obj->mIdent && obj->mSize > 0) { + int bank = -1; + if (obj->mRegion->mCartridgeBanks) + { + do { bank++; } while (!((1ULL << bank) & obj->mRegion->mCartridgeBanks)); + } + if (obj->mSection->mType == LST_BSS) { if (obj->mRanges.Size() > 0) @@ -978,27 +1051,27 @@ bool Linker::WriteMlbFile(const char* filename) } else if (obj->mType == LOT_DATA) { - if (!obj->mRegion->mCartridgeBanks) + if (obj->mAddress >= 0x8000) { if (obj->mRanges.Size() > 0) { for (int i = 0; i < obj->mRanges.Size(); i++) - fprintf(file, "P:%04x-%04x:%s@%s\n", obj->mAddress + obj->mRanges[i].mOffset - 0x8000, obj->mAddress + obj->mRanges[i].mOffset + obj->mRanges[i].mSize - 0x8000 - 1, obj->mIdent->mString, obj->mRanges[i].mIdent->mString); + fprintf(file, "P:%04x-%04x:%s@%s\n", TranslateMlbAddress(obj->mAddress + obj->mRanges[i].mOffset, bank, machine), TranslateMlbAddress(obj->mAddress + obj->mRanges[i].mOffset + obj->mRanges[i].mSize - 1, bank, machine), obj->mIdent->mString, obj->mRanges[i].mIdent->mString); } - fprintf(file, "P:%04x-%04x:%s\n", obj->mAddress - 0x8000, obj->mAddress - 0x8000 + obj->mSize - 1, obj->mIdent->mString); + fprintf(file, "P:%04x-%04x:%s\n", TranslateMlbAddress(obj->mAddress, bank, machine), TranslateMlbAddress(obj->mAddress + obj->mSize - 1, bank, machine), obj->mIdent->mString); } } else if (obj->mType == LOT_NATIVE_CODE) { - if (!obj->mRegion->mCartridgeBanks) + if (obj->mAddress >= 0x8000) { if (obj->mRanges.Size() > 0) { for (int i = 0; i < obj->mRanges.Size(); i++) - fprintf(file, "P:%04x:%s@%s\n", obj->mAddress + obj->mRanges[i].mOffset - 0x8000, obj->mIdent->mString, obj->mRanges[i].mIdent->mString); + fprintf(file, "P:%04x:%s@%s\n", TranslateMlbAddress(obj->mAddress + obj->mRanges[i].mOffset, bank, machine), obj->mIdent->mString, obj->mRanges[i].mIdent->mString); } - fprintf(file, "P:%04x:%s\n", obj->mAddress - 0x8000, obj->mIdent->mString); + fprintf(file, "P:%04x:%s\n", TranslateMlbAddress(obj->mAddress, bank, machine), obj->mIdent->mString); } } } @@ -1052,7 +1125,7 @@ bool Linker::WriteAsmFile(const char* filename) switch (obj->mType) { case LOT_BYTE_CODE: - mByteCodeDisassembler.Disassemble(file, mMemory, 0, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); + mByteCodeDisassembler.Disassemble(file, mMemory, -1, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); break; case LOT_NATIVE_CODE: if (obj->mRegion->mCartridgeBanks) @@ -1063,7 +1136,7 @@ bool Linker::WriteAsmFile(const char* filename) mNativeDisassembler.Disassemble(file, mCartridge[i], i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); } else - mNativeDisassembler.Disassemble(file, mMemory, 0, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); + mNativeDisassembler.Disassemble(file, mMemory, -1, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this); break; case LOT_DATA: if (obj->mRegion->mCartridgeBanks) @@ -1074,7 +1147,7 @@ bool Linker::WriteAsmFile(const char* filename) mNativeDisassembler.DumpMemory(file, mCartridge[i], i, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); } else - mNativeDisassembler.DumpMemory(file, mMemory, 0, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); + mNativeDisassembler.DumpMemory(file, mMemory, -1, obj->mAddress, obj->mSize, obj->mProc, obj->mIdent, this, obj); break; } } diff --git a/oscar64/Linker.h b/oscar64/Linker.h index 0b56427..16719e0 100644 --- a/oscar64/Linker.h +++ b/oscar64/Linker.h @@ -6,6 +6,7 @@ #include "Errors.h" #include "Disassembler.h" #include "DiskImage.h" +#include "CompilerTypes.h" class InterCodeProcedure; @@ -238,8 +239,10 @@ public: bool WriteLblFile(const char* filename); bool WriteCrtFile(const char* filename); bool WriteBinFile(const char* filename); - bool WriteNesFile(const char* filename); - bool WriteMlbFile(const char* filename); + bool WriteNesFile(const char* filename, TargetMachine machine); + bool WriteMlbFile(const char* filename, TargetMachine machine); + + int TranslateMlbAddress(int address, int bank, TargetMachine machine); uint64 mCompilerOptions; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 0b4bccf..94b7bf5 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -3702,63 +3702,66 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT } else if (mMode == ASMIM_INDIRECT_Y) { - if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress + 1].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress].mValue + 1 == data.mRegs[mAddress + 1].mValue) + if (!(mFlags & NCIF_VOLATILE)) { - mFlags |= NICT_ZPFLIPPED; - mAddress = data.mRegs[mAddress].mValue; - if (mType == ASMIT_LDA) - data.mRegs[CPU_REG_A].Reset(); - } - else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress].mLinkerObject == data.mRegs[mAddress + 1].mLinkerObject) - { - mMode = ASMIM_ABSOLUTE_Y; - mLinkerObject = data.mRegs[mAddress].mLinkerObject; - mAddress = data.mRegs[mAddress + 1].mValue; - if (mType == ASMIT_LDA) - data.mRegs[CPU_REG_A].Reset(); - } - else if (mType == ASMIT_LDA) - { - if (!(mFlags & NCIF_VOLATILE)) + if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress + 1].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress].mValue + 1 == data.mRegs[mAddress + 1].mValue) { - if (data.mRegs[CPU_REG_A].mMode == NRDM_INDIRECT_Y && data.mRegs[CPU_REG_A].mValue == mAddress) + mFlags |= NICT_ZPFLIPPED; + mAddress = data.mRegs[mAddress].mValue; + if (mType == ASMIT_LDA) + data.mRegs[CPU_REG_A].Reset(); + } + else if (data.mRegs[mAddress].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && data.mRegs[mAddress].mLinkerObject == data.mRegs[mAddress + 1].mLinkerObject) + { + mMode = ASMIM_ABSOLUTE_Y; + mLinkerObject = data.mRegs[mAddress].mLinkerObject; + mAddress = data.mRegs[mAddress + 1].mValue; + if (mType == ASMIT_LDA) + data.mRegs[CPU_REG_A].Reset(); + } + else if (mType == ASMIT_LDA) + { + if (!(mFlags & NCIF_VOLATILE)) { - if (mLive & LIVE_CPU_REG_Z) + if (data.mRegs[CPU_REG_A].mMode == NRDM_INDIRECT_Y && data.mRegs[CPU_REG_A].mValue == mAddress) { - mType = ASMIT_ORA; - mMode = ASMIM_IMMEDIATE; - mAddress = 0; + if (mLive & LIVE_CPU_REG_Z) + { + mType = ASMIT_ORA; + mMode = ASMIM_IMMEDIATE; + mAddress = 0; + } + else + { + mType = ASMIT_NOP; + mMode = ASMIM_IMPLIED; + } + changed = true; + } + else if (data.mRegs[CPU_REG_X].SameData(*this)) + { + mType = ASMIT_TXA; + mMode = ASMIM_IMPLIED; + data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X]; + changed = true; + } + else if (data.mRegs[CPU_REG_Y].SameData(*this)) + { + mType = ASMIT_TYA; + mMode = ASMIM_IMPLIED; + data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y]; + changed = true; } else { - mType = ASMIT_NOP; - mMode = ASMIM_IMPLIED; + data.mRegs[CPU_REG_A].mMode = NRDM_INDIRECT_Y; + data.mRegs[CPU_REG_A].mValue = mAddress; + data.mRegs[CPU_REG_A].mFlags = mFlags; } - changed = true; - } - else if (data.mRegs[CPU_REG_X].SameData(*this)) - { - mType = ASMIT_TXA; - mMode = ASMIM_IMPLIED; - data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_X]; - changed = true; - } - else if (data.mRegs[CPU_REG_Y].SameData(*this)) - { - mType = ASMIT_TYA; - mMode = ASMIM_IMPLIED; - data.mRegs[CPU_REG_A] = data.mRegs[CPU_REG_Y]; - changed = true; } else - { - data.mRegs[CPU_REG_A].mMode = NRDM_INDIRECT_Y; - data.mRegs[CPU_REG_A].mValue = mAddress; - data.mRegs[CPU_REG_A].mFlags = mFlags; - } + data.mRegs[CPU_REG_A].Reset(); } - else - data.mRegs[CPU_REG_A].Reset(); } if (ChangesAddress()) @@ -25143,6 +25146,27 @@ bool NativeCodeBasicBlock::BitFieldForwarding(const NativeRegisterDataSet& data) } } #endif + if (i + 1 < mIns.Size() && + mIns[i + 0].mType == ASMIT_TXA && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) && + mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1) + { + if (mNDataSet.mRegs[CPU_REG_X].mMask & 1) + { + if (mNDataSet.mRegs[CPU_REG_X].mValue & 1) + { + mIns[i + 1].mAddress = 0; + changed = true; + } + else + { + mIns[i + 0].mType = ASMIT_INX; mIns[i + 0].mLive |= LIVE_CPU_REG_X; + mIns[i + 1].mType = ASMIT_TXA; mIns[i + 1].mMode = ASMIM_IMPLIED; + changed = true; + } + } + + } + bool skip = false; if (i + 2 < mIns.Size() && @@ -34896,7 +34920,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } else if ( mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && - mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE) + mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ABSOLUTE && !(mIns[i + 1].mFlags & NCIF_VOLATILE)) { proc->ResetPatched(); if (CheckSingleUseGlobalLoad(this, mIns[i + 0].mAddress, i + 2, mIns[i + 1], 2)) @@ -37317,7 +37341,7 @@ void NativeCodeProcedure::RebuildEntry(void) void NativeCodeProcedure::Optimize(void) { - CheckFunc = !strcmp(mInterProc->mIdent->mString, "main"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "mmc3_bank_prg"); #if 1 int step = 0; diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index b7215cf..9352835 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -293,7 +293,7 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags) dec->mIdent = mScanner->mTokenIdent; if (mScope->Insert(dec->mIdent, dec)) - mErrors->Error(dec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate name"); + mErrors->Error(dec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate name", dec->mIdent); mScanner->NextToken(); } diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index f848370..500b9b6 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -311,8 +311,22 @@ int main2(int argc, const char** argv) else if (!strcmp(targetMachine, "nes")) { compiler->mTargetMachine = TMACH_NES; - compiler->mCompilerOptions |= COPT_EXTENDED_ZERO_PAGE; - compiler->AddDefine(Ident::Unique("__NES__"), "1"); + } + else if (!strcmp(targetMachine, "nes_nrom_h")) + { + compiler->mTargetMachine = TMACH_NES_NROM_H; + } + else if (!strcmp(targetMachine, "nes_nrom_v")) + { + compiler->mTargetMachine = TMACH_NES_NROM_V; + } + else if (!strcmp(targetMachine, "nes_mmc1")) + { + compiler->mTargetMachine = TMACH_NES_MMC1; + } + else if (!strcmp(targetMachine, "nes_mmc3")) + { + compiler->mTargetMachine = TMACH_NES_MMC3; } else if (!strcmp(targetMachine, "atari")) { @@ -323,10 +337,27 @@ int main2(int argc, const char** argv) compiler->mErrors->Error(loc, EERR_COMMAND_LINE, "Invalid target machine option", targetMachine); - if (compiler->mTargetMachine == TMACH_NES) + if (compiler->mTargetMachine >= TMACH_NES && compiler->mTargetMachine <= TMACH_NES_MMC3) { compiler->mCompilerOptions |= COPT_TARGET_NES; + compiler->mCompilerOptions |= COPT_EXTENDED_ZERO_PAGE; + compiler->mCompilerOptions |= COPT_NATIVE; compiler->AddDefine(Ident::Unique("OSCAR_TARGET_NES"), "1"); + switch (compiler->mTargetMachine) + { + default: + case TMACH_NES: + case TMACH_NES_NROM_H: + case TMACH_NES_NROM_V: + break; + case TMACH_NES_MMC1: + compiler->AddDefine(Ident::Unique("__NES_MMC1__"), "1"); + break; + case TMACH_NES_MMC3: + compiler->AddDefine(Ident::Unique("__NES_MMC3__"), "1"); + break; + } + compiler->AddDefine(Ident::Unique("__NES__"), "1"); } else if (!strcmp(targetFormat, "prg")) { diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index f9bb8fc..cdb5b91 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -190,6 +190,12 @@ } "Entry" { + "MsmKey" = "8:_2CC169DCBB0B4CC0BFE38AE63B285359" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_2D828D0247F144CDB0112B2AD4004C2C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -298,6 +304,12 @@ } "Entry" { + "MsmKey" = "8:_492AD1ED992D44F1A65903A5232C0426" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_494DB63135144419A8E0E6037E1B3237" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -850,6 +862,12 @@ } "Entry" { + "MsmKey" = "8:_CDBE2B8738C843CBB146767FBEE9A828" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_D0E45B48D76B4407B0BDE4378C1DB2C7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -994,6 +1012,12 @@ } "Entry" { + "MsmKey" = "8:_ED5FED616EA64689AB793E5D8BD3F13D" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_ED872D39D58443D590B7C80604BC0FF4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -1731,6 +1755,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2CC169DCBB0B4CC0BFE38AE63B285359" + { + "SourcePath" = "8:..\\include\\nes\\mmc1.c" + "TargetName" = "8:mmc1.c" + "Tag" = "8:" + "Folder" = "8:_9F35D1516FB34C30A2C5C1CA12501231" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2D828D0247F144CDB0112B2AD4004C2C" { "SourcePath" = "8:..\\samples\\scrolling\\tunnel.c" @@ -2091,6 +2135,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_492AD1ED992D44F1A65903A5232C0426" + { + "SourcePath" = "8:..\\include\\nes\\mmc3.h" + "TargetName" = "8:mmc3.h" + "Tag" = "8:" + "Folder" = "8:_9F35D1516FB34C30A2C5C1CA12501231" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_494DB63135144419A8E0E6037E1B3237" { "SourcePath" = "8:..\\include\\c128\\bank1.c" @@ -3931,6 +3995,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CDBE2B8738C843CBB146767FBEE9A828" + { + "SourcePath" = "8:..\\include\\nes\\mmc1.h" + "TargetName" = "8:mmc1.h" + "Tag" = "8:" + "Folder" = "8:_9F35D1516FB34C30A2C5C1CA12501231" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D0E45B48D76B4407B0BDE4378C1DB2C7" { "SourcePath" = "8:..\\include\\stdlib.h" @@ -4411,6 +4495,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ED5FED616EA64689AB793E5D8BD3F13D" + { + "SourcePath" = "8:..\\include\\nes\\mmc3.c" + "TargetName" = "8:mmc3.c" + "Tag" = "8:" + "Folder" = "8:_9F35D1516FB34C30A2C5C1CA12501231" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ED872D39D58443D590B7C80604BC0FF4" { "SourcePath" = "8:..\\samples\\kernalio\\fileread.c" @@ -4963,7 +5067,7 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" "ProductCode" = "8:{85311ED7-CC4D-4512-840D-20C87C74DAC0}" - "PackageCode" = "8:{84A20228-DD88-421A-9DE4-33A058638C87}" + "PackageCode" = "8:{9C4FC9E1-982E-42B2-B9D0-8D5984BC0B2B}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE"