diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs index adf307eaa1..f9527c215c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs @@ -323,6 +323,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 Rom.HashSHA1(), Rom.HashMD5(), _mapper.GetType()); + + + // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. + // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 + // executing a reset sequence at power on, but it's needed so let's hard code it for now + Cpu.S = 0xFD; } private bool _pal; @@ -345,7 +351,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 M6532 = new M6532(this); Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC - } + + // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. + // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 + // executing a reset sequence at power on, but it's needed so let's hard code it for now + Cpu.S = 0xFD; + } public void FrameAdvance(bool render, bool rendersound) { diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/M6532.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/M6532.cs index 92849ef9a9..5f5155a5f3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/M6532.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/M6532.cs @@ -9,6 +9,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public byte DDRa = 0x00; public byte DDRb = 0x00; + public byte outputA = 0x00; public TimerData Timer; @@ -35,9 +36,13 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { // Read Output reg A // Combine readings from player 1 and player 2 - var temp = (byte)(_core.ReadControls1(peek) & 0xF0 | ((_core.ReadControls2(peek) >> 4) & 0x0F)); - temp = (byte)(temp & ~DDRa); - return temp; + // actually depends on setting in SWCHCNTA (aka DDRa) + + var temp = (byte)(_core.ReadControls1(peek) & 0xF0 | ((_core.ReadControls2(peek) >> 4) & 0x0F)); + temp = (byte)(temp & ~DDRa); + temp = (byte)(temp + (outputA & DDRa)); + return temp; + } if (registerAddr == 0x01) @@ -150,7 +155,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 if (registerAddr == 0x00) { - // Write Output reg A + // Write Output reg A + outputA = value; } else if (registerAddr == 0x01) { @@ -159,7 +165,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } else if (registerAddr == 0x02) { - // Write Output reg B + // Write Output reg B + // But is read only } else if (registerAddr == 0x03) { @@ -175,7 +182,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.BeginSection("M6532"); ser.Sync("ddra", ref DDRa); ser.Sync("ddrb", ref DDRb); - Timer.SyncState(ser); + ser.Sync("OutputA", ref outputA); + Timer.SyncState(ser); ser.EndSection(); } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/mCM.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/mCM.cs index aeca989106..53f64d2ef0 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/mCM.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/mCM.cs @@ -1,5 +1,6 @@ using BizHawk.Common; using BizHawk.Common.NumberExtensions; +using System; namespace BizHawk.Emulation.Cores.Atari.Atari2600 { @@ -183,6 +184,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private bool _disableRam = true; private bool _writeMode = false; private int _column = 0; + public bool _func_key = false; + public bool _shift_key = false; public override void Dispose() { @@ -197,8 +200,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _disableRam = true; _writeMode = true; _column = 0; + _func_key = false; + _shift_key = false; base.HardReset(); + + } public override void SyncState(Serializer ser) @@ -209,16 +216,62 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.Sync("column", ref _column); ser.Sync("disableRam", ref _disableRam); ser.Sync("writeMode", ref _writeMode); + ser.Sync("FuncKey", ref _func_key); + ser.Sync("ShiftKey", ref _shift_key); - base.SyncState(ser); + base.SyncState(ser); } - public override byte ReadMemory(ushort addr) + + + private byte ReadMem(ushort addr, bool peek) { - if (addr < 0x1000) + + // A unique feature of the keyboard is that it changes the operation of inputs 0-3 + // by holding them high in the no-button-pressed state. + // However exposing this behaviour to the rest of the system would be overly cunmbersome + // so instead we bypass these cases here + + + if ((addr & 0x000F) == 8 && (addr & 0x1080)==0 && addr<1000) + { + // if func key pressed + if (_func_key == true) + { + return 0x80; + } + else + { + return 0; + } + + } + else if ((addr & 0x000F) == 9 && (addr & 0x1080) == 0 && addr < 1000) + { + return 0x80; + } + else if ((addr & 0x000F) == 0xA && (addr & 0x1080) == 0 && addr < 1000) + { + return 0x80; + } + else if ((addr & 0x000F) == 0xB && (addr & 0x1080) == 0 && addr < 1000) + { + // if shift key pressed + if (_shift_key == true) + { + return 0x80; + } + else + { + return 0; + } + } + else if (addr < 0x1000) { - return base.ReadMemory(addr); - } + return base.ReadMemory(addr); + } + + // Lower 2K is always the first 2K of the ROM bank // Upper 2K is also Rom if ram is enabled @@ -233,16 +286,22 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 return _ram[addr & 0x7FF]; } - // Attempting to read while in write mode - throw new NotTestedException(); + // Attempting to read while in write mode + throw new NotTestedException(); } - public override byte PeekMemory(ushort addr) + public override byte ReadMemory(ushort addr) + { + return ReadMem(addr, false); + } + + + public override byte PeekMemory(ushort addr) { - return ReadMemory(addr); + return ReadMem(addr,true); } - public override void WriteMemory(ushort addr, byte value) + private void WriteMem(ushort addr, byte value, bool poke) { //Mimicking the 6532 logic for accesing port A, for testing var isPortA = false; @@ -267,7 +326,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 if (registerAddr == 0x00) { - if (addr != 640) + if (addr != 640 && addr>=0x280) // register addresses are only above 0x280 { // Write Output reg A isPortA = true; @@ -277,8 +336,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } - //if (addr == 0x280) //Stella uses only 280 - if (isPortA) + if (addr == 0x280 && !poke) //Stella uses only 280 + //if (isPortA && !poke) { var bit5 = value.Bit(5); var bit4 = value.Bit(4); @@ -292,9 +351,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _bank4K = value & 0x03; - //D6 = 1 -> increase key column (0 to 9) - //D5 = 1 -> reset key column to 0 (if D4 = 0) - if (bit5 && !bit4) + //D6 = 1 -> increase key column (0 to 9) + //D5 = 1 -> reset key column to 0 (if D4 = 0) + if (bit5 && !bit4) { _column = 0; } @@ -312,8 +371,20 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _ram[addr & 0x7FF] = value; } } - - base.WriteMemory(addr, value); + if (addr<0x1000) { + base.WriteMemory(addr, value); + } + } - } + + public override void WriteMemory(ushort addr, byte value) + { + WriteMem(addr, value, false); + } + + public override void PokeMemory(ushort addr, byte value) + { + WriteMem(addr, value, true); + } + } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs index d381e798f8..b1de70a977 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs @@ -1121,16 +1121,57 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 mask = 0x3f; } + // inputs 0-3 are measured by a charging capacitor, these inputs are used with the paddles and the keyboard + // Changing the hard coded value will change the paddle position. The range seems to be roughly 0-56000 according to values from stella + // 6105 roughly centers the paddle in Breakout if (maskedAddr == 0x08) // INPT0 { - // Changing the hard coded value will change the paddle position. The range seems to be roughly 0-56000 according to values from stella - // 6105 roughly centers the paddle in Breakout if (_capCharging && _core.Cpu.TotalExecutedCycles - _capChargeStart >= 6105) { coll=0x80; - } + } else + { + coll = 0x00; + } + mask = 0x7f; + } - coll=0x00; + if (maskedAddr == 0x09) // INPT1 + { + if (_capCharging && _core.Cpu.TotalExecutedCycles - _capChargeStart >= 6105) + { + coll = 0x80; + } + else + { + coll = 0x00; + } + mask = 0x7f; + } + + if (maskedAddr == 0x0A) // INPT2 + { + if (_capCharging && _core.Cpu.TotalExecutedCycles - _capChargeStart >= 6105) + { + coll = 0x80; + } + else + { + coll = 0x00; + } + mask = 0x7f; + } + + if (maskedAddr == 0x0B) // INPT3 + { + if (_capCharging && _core.Cpu.TotalExecutedCycles - _capChargeStart >= 6105) + { + coll = 0x80; + } + else + { + coll = 0x00; + } mask = 0x7f; }