diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 2a8a78c439..e390549732 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -3,7 +3,7 @@ Debug AnyCPU - 9.0.21022 + 9.0.30729 2.0 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA} Library @@ -23,6 +23,7 @@ 4 x86 true + false pdbonly @@ -56,6 +57,7 @@ + diff --git a/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs b/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs index d2ca288a82..9a8cfe6fe0 100644 --- a/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs +++ b/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs @@ -17,28 +17,20 @@ namespace BizHawk.Emulation.CPUs.M6502 PendingCycles += cycles; while (PendingCycles > 0) { - if (NMI) - { - WriteMemory((ushort)(S-- + 0x100), (byte)(PC >> 8)); - WriteMemory((ushort)(S-- + 0x100), (byte)PC); - byte oldP = P; - FlagB = false; - FlagT = true; - WriteMemory((ushort)(S-- + 0x100), P); - P = oldP; - FlagI = true; - PC = ReadWord(NMIVector); - PendingCycles -= 7; - NMI = false; - } + if (NMI) + { + TriggerException(ExceptionType.NMI); + NMI = false; + } + + if(debug) Console.WriteLine(State()); -if(debug) Console.WriteLine(State()); ushort this_pc = PC; byte opcode = ReadMemory(PC++); switch (opcode) { case 0x00: // BRK -throw new Exception("break"); +TriggerException(ExceptionType.BRK); break; case 0x01: // ORA (addr,X) value8 = ReadMemory(ReadWordPageWrap((byte)(ReadMemory(PC++)+X))); diff --git a/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs b/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs index a5eaf6e0c9..b69231c4aa 100644 --- a/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs +++ b/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs @@ -70,12 +70,34 @@ namespace BizHawk.Emulation.CPUs.M6502 // TODO IRQ, NMI functions public bool Interrupt; - public bool NMI;// + public bool NMI; private const ushort NMIVector = 0xFFFA; private const ushort ResetVector = 0xFFFC; private const ushort BRKVector = 0xFFFE; + enum ExceptionType + { + BRK, NMI + } + + void TriggerException(ExceptionType type) + { + WriteMemory((ushort)(S-- + 0x100), (byte)(PC >> 8)); + WriteMemory((ushort)(S-- + 0x100), (byte)PC); + byte oldP = P; + FlagB = false; + FlagT = true; + WriteMemory((ushort)(S-- + 0x100), P); + P = oldP; + FlagI = true; + if(type == ExceptionType.NMI) + PC = ReadWord(NMIVector); + else + PC = ReadWord(BRKVector); + PendingCycles -= 7; + } + // ==== End State ==== /// Carry Flag diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs index aaae7bf8a1..2ed85ee0d8 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs @@ -40,6 +40,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo static string ClassifyTable = @" NROM 0 1 1 NROM 0 2 1 +UXROM 2 8 0 "; } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs index 2b54b87aec..57e5760a9d 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs @@ -9,11 +9,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards { base.Initialize(romInfo, nes); Debug.Assert(romInfo.PRG_Size < 3); + mask = (RomInfo.PRG_Size << 14) - 1; } public override byte ReadPRG(int addr) { - addr &= (RomInfo.PRG_Size << 14) - 1; + addr &= mask; return RomInfo.ROM[addr]; } + + int mask; } } \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/UxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/UxROM.cs new file mode 100644 index 0000000000..9f0edd4eca --- /dev/null +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/UxROM.cs @@ -0,0 +1,64 @@ +using System; +using System.Diagnostics; + +namespace BizHawk.Emulation.Consoles.Nintendo.Boards +{ + public class UxROM : NES.NESBoardBase + { + string type; + public UxROM(string type) + { + this.type = type; + } + public override void Initialize(NES.RomInfo romInfo, NES nes) + { + base.Initialize(romInfo, nes); + Debug.Assert(Util.IsPowerOfTwo(RomInfo.PRG_Size)); + + if (type == "UNROM") pagemask = 7; + else if (type == "UOROM") pagemask = 15; + else throw new InvalidOperationException("Invalid UXROM type"); + + //guess CRAM size (this is a very confident guess!) + if (RomInfo.CRAM_Size == -1) RomInfo.CRAM_Size = 8; + + cram = new byte[RomInfo.CRAM_Size * 1024]; + cram_mask = cram.Length - 1; + } + public override byte ReadPRG(int addr) + { + int block = addr >> 14; + int page = block == 1 ? pagemask : prg; + page &= pagemask; + int ofs = addr & 0x3FFF; + return RomInfo.ROM[(page << 14) | ofs]; + } + public override void WritePRG(int addr, byte value) + { + prg = value; + } + + public override byte ReadPPU(int addr) + { + if (addr < 0x2000) + { + return cram[addr & cram_mask]; + } + else return base.ReadPPU(addr); + } + + public override void WritePPU(int addr, byte value) + { + if (addr < 0x2000) + { + cram[addr & cram_mask] = value; + } + else base.WritePPU(addr,value); + } + + int pagemask; + int prg; + byte[] cram; + int cram_mask; + } +} \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs index 3c08a50b64..18311b1970 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs @@ -22,7 +22,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo } public EHeaderType HeaderType; - public int PRG_Size = -1, CHR_Size = -1, PRAM_Size = -1; + public int PRG_Size = -1, CHR_Size = -1; + public int CRAM_Size = -1, NVWRAM_Size = -1, WRAM_Size = -1; public string BoardName; public EMirrorType MirrorType; public bool Battery; @@ -38,10 +39,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo { byte ReadPRG(int addr); byte ReadPPU(int addr); - byte ReadPRAM(int addr); + byte ReadWRAM(int addr); void WritePRG(int addr, byte value); void WritePPU(int addr, byte value); - void WritePRAM(int addr, byte value); + void WriteWRAM(int addr, byte value); void Initialize(RomInfo romInfo, NES nes); }; @@ -82,8 +83,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo public virtual byte ReadPRG(int addr) { return RomInfo.ROM[addr];} public virtual void WritePRG(int addr, byte value) { } - public virtual void WritePRAM(int addr, byte value) { } - public virtual byte ReadPRAM(int addr) { return 0xFF; } + public virtual void WriteWRAM(int addr, byte value) { } + public virtual byte ReadWRAM(int addr) { return 0xFF; } public virtual void WritePPU(int addr, byte value) @@ -533,11 +534,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo ret.CHR_Size = VROM_size; ret.Battery = (ROM_type & 2) != 0; - fixed (iNES_HEADER* self = &this) ret.PRAM_Size = self->reserve[0]; + fixed (iNES_HEADER* self = &this) ret.WRAM_Size = self->reserve[0] * 8; //0 is supposed to mean 1 (for compatibility, as this is an extension to original iNES format) - //but we're not worrying about that for now) + if (ret.WRAM_Size == 0) ret.WRAM_Size = 8; - Console.WriteLine("iNES header: map:{0}, mirror:{1}, PRG:{2}, CHR:{3}, PRAM:{4}, bat:{5}", ret.MapperNumber, ret.MirrorType, ret.PRG_Size, ret.CHR_Size, ret.PRAM_Size, ret.Battery ? 1 : 0); + Console.WriteLine("iNES header: map:{0}, mirror:{1}, PRG:{2}, CHR:{3}, CRAM:{4}, WRAM:{5}, NVWRAM:{6}, bat:{7}", ret.MapperNumber, ret.MirrorType, ret.PRG_Size, ret.CHR_Size, ret.CRAM_Size, ret.WRAM_Size, ret.NVWRAM_Size, ret.Battery ? 1 : 0); //fceux calls uppow2(PRG_Banks) here, and also ups the chr size as well //then it does something complicated that i don't understand with making sure it doesnt read too much data @@ -598,12 +599,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo romInfo.PRG_Size = int.Parse(dict["PRG"]); if (dict.ContainsKey("CHR")) romInfo.CHR_Size = int.Parse(dict["CHR"]); + if (dict.ContainsKey("CRAM")) + romInfo.CRAM_Size = int.Parse(dict["CRAM"]); + if (dict.ContainsKey("bug")) + Console.WriteLine("game is known to be BUGGED!!!"); } //construct board (todo) switch (romInfo.BoardName) { case "NROM": board = new Boards.NROM(); break; + case "UNROM": board = new Boards.UxROM("UNROM"); break; } if (board == null) throw new InvalidOperationException("Couldn't classify NES rom"); diff --git a/BizHawk.Emulation/Util.cs b/BizHawk.Emulation/Util.cs index 7f11d5575a..89be102a48 100644 --- a/BizHawk.Emulation/Util.cs +++ b/BizHawk.Emulation/Util.cs @@ -282,6 +282,13 @@ namespace BizHawk public static class Util { + public static bool IsPowerOfTwo(int x) + { + if (x == 0) return true; + if (x == 1) return true; + return (x & (x - 1)) == 0; + } + public static int SaveRamBytesUsed(byte[] SaveRAM) { for (int j = SaveRAM.Length - 1; j >= 0; j--) diff --git a/BizHawk.MultiClient/output/gamedb.txt b/BizHawk.MultiClient/output/gamedb.txt index b464a2342a..2a10df42dc 100644 --- a/BizHawk.MultiClient/output/gamedb.txt +++ b/BizHawk.MultiClient/output/gamedb.txt @@ -2258,6 +2258,7 @@ B486A8ED Dai Makai Mura SGX D4448D09BBFDE687C04F9E3310E023AB ti83_1.rom TI83 initPC=6ce +;NROM 1,1 1457475741846A01399DC663135A60C1 Balloon Fight (JU) NES board=NROM;mirror=H;PRG=1;CHR=1 576AB245B4F04C670AC312AB0D441697 Baseball (UE) NES board=NROM;mirror=H;PRG=1;CHR=1 0F9C8D3D3099C70368411F6DF9EF49C1 Bomberman (U) NES board=NROM;mirror=V;PRG=1;CHR=1 @@ -2289,6 +2290,7 @@ B0F0B0CC14958D30E89D06AF182E7CD5 Raid on Bungeling Bay (U) NES board=NROM;mirr CB7F1463C90CDCDF5EF315C125F12FE2 Urban Champion (JU) NES board=NROM;mirror=V;PRG=1;CHR=1 4635D8D82A86E8B99390A0586C96D536 Wild Gunman (JUE) NES board=NROM;mirror=V;PRG=1;CHR=1 +;NROM 2,1 BD2C15391B0641D43A35E83F5FCE073A 10-Yard Fight (U) NES board=NROM;mirror=H;PRG=2;CHR=1 0B66FDF88964235C434DAFF62837AF60 1942 (JU) NES board=NROM;mirror=H;PRG=2;CHR=1 4B3B120FA98DCAE25FA88B29818572F8 Chubby Cherub (U) NES board=NROM;mirror=V;PRG=2;CHR=1 @@ -2320,4 +2322,15 @@ E7D7225DAD044B624FBAD9C9CA96E835 Wrecking Crew (JUE) NES board=NROM;mirror=H;P 7A528FA727623BA7704FDBB519F3419F Xevious (U) NES board=NROM;mirror=H;PRG=2;CHR=1 ;todo videomation(mapper13) -;starting at arkanoid we have mappers \ No newline at end of file +;starting at arkanoid we have mappers +;http://tuxnes.sourceforge.net/nesmapper.txt a mappers list + +;UNROM +4DE82CFCEADBF1A5E693B669B1221107 Mega Man (U) NES board=UNROM;mirror=V;PRG=8;CHR=0;CRAM=8 +756170BA1E06FA26C60D10114DC6A5AE Castlevania (Rev 0) (U) NES board=UNROM;mirror=V;PRG=8;CHR=0;CRAM=8 +728E05F245AB8B7FE61083F6919DC485 Castlevania (Rev 1) (U) NES board=UNROM;mirror=V;PRG=8;CHR=0;CRAM=8 +5A5C2F4F1CAFB1F55A8DC0D5AD4550E5 Contra (U) NES board=UNROM;mirror=V;PRG=8;CHR=0;CRAM=8 +B480855FFF883B20BA403A2009A7F13C Duck Tales (U) NES board=UNROM;mirror=V;PRG=8;CHR=0;CRAM=8 + +;mapper66? mhrom? wtf?? +;27100B746D50E6AE6FBAE2C794173240 Metal Gear (U) NES board=UXROM;mirror=H;PRG=8;CHR=0;CRAM=8;bug=1 diff --git a/CpuCoreGenerator/MOS 6502/CoreGenerator.cs b/CpuCoreGenerator/MOS 6502/CoreGenerator.cs index 0e7f280728..58990fe568 100644 --- a/CpuCoreGenerator/MOS 6502/CoreGenerator.cs +++ b/CpuCoreGenerator/MOS 6502/CoreGenerator.cs @@ -329,25 +329,17 @@ namespace M6502 w.WriteLine(" while (PendingCycles > 0)"); w.WriteLine(" {"); - w.WriteLine(" if (NMI)"); - w.WriteLine(" {"); - w.WriteLine(" WriteMemory((ushort)(S-- + 0x100), (byte)(PC >> 8));"); - w.WriteLine(" WriteMemory((ushort)(S-- + 0x100), (byte)PC);"); - w.WriteLine(" byte oldP = P;"); - w.WriteLine(" FlagB = false;"); - w.WriteLine(" FlagT = true;"); - w.WriteLine(" WriteMemory((ushort)(S-- + 0x100), P);"); - w.WriteLine(" P = oldP;"); - w.WriteLine(" FlagI = true;"); - w.WriteLine(" PC = ReadWord(NMIVector);"); - w.WriteLine(" PendingCycles -= 7;"); - w.WriteLine(" NMI = false;"); - w.WriteLine(" }"); - w.WriteLine(""); + w.WriteLine(" if (NMI)"); + w.WriteLine(" {"); + w.WriteLine(" TriggerException(ExceptionType.NMI);"); + w.WriteLine(" NMI = false;"); + w.WriteLine(" }"); + w.WriteLine(""); - w.WriteLine("if(debug) Console.WriteLine(State());"); - - w.WriteLine(" ushort this_pc = PC;"); + w.WriteLine(" if(debug) Console.WriteLine(State());"); + w.WriteLine(""); + + w.WriteLine(" ushort this_pc = PC;"); w.WriteLine(" byte opcode = ReadMemory(PC++);"); w.WriteLine(" switch (opcode)"); w.WriteLine(" {"); @@ -386,7 +378,7 @@ namespace M6502 case "BMI": Branch(op, w, "N", true); break; case "BNE": Branch(op, w, "Z", false); break; case "BPL": Branch(op, w, "N", false); break; - case "BRK": w.WriteLine("throw new Exception(\"break\");"); break; + case "BRK": w.WriteLine("TriggerException(ExceptionType.BRK);"); break; case "BVC": Branch(op, w, "V", false); break; case "BVS": Branch(op, w, "V", true); break; case "CLC": CLC(op, w); break;