diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs index a72c3ebdf9..adf307eaa1 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs @@ -36,10 +36,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 if ((addr & 0x1080) == 0x0080) { - return M6532.ReadMemory(addr, false); + _tia.bus_state = M6532.ReadMemory(addr, false); + return M6532.ReadMemory(addr, false); } - return Rom[addr & 0x0FFF]; + _tia.bus_state = Rom[addr & 0x0FFF]; + return Rom[addr & 0x0FFF]; } internal byte BasePeekMemory(ushort addr) @@ -52,15 +54,15 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 if ((addr & 0x1080) == 0x0080) { - return M6532.ReadMemory(addr, true); + return M6532.ReadMemory(addr, true); } - - return Rom[addr & 0x0FFF]; + return Rom[addr & 0x0FFF]; } internal void BaseWriteMemory(ushort addr, byte value) { - if (addr != LastAddress) + _tia.bus_state = value; + if (addr != LastAddress) { DistinctAccessCount++; LastAddress = addr; @@ -69,7 +71,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 addr = (ushort)(addr & 0x1FFF); if ((addr & 0x1080) == 0) { - _tia.WriteMemory(addr, value); + _tia.WriteMemory(addr, value, false); } else if ((addr & 0x1080) == 0x0080) { @@ -83,10 +85,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 internal void BasePokeMemory(ushort addr, byte value) { - addr = (ushort)(addr & 0x1FFF); + addr = (ushort)(addr & 0x1FFF); if ((addr & 0x1080) == 0) { - _tia.WriteMemory(addr, value); + _tia.WriteMemory(addr, value, true); } else if ((addr & 0x1080) == 0x0080) { @@ -108,6 +110,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _mapper.Bit13 = addr.Bit(13); var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF)); + _tia.bus_state = temp; MemoryCallbacks.CallReads(addr); return temp; @@ -115,8 +118,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 internal byte PeekMemory(ushort addr) { - var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF)); - + var temp = _mapper.PeekMemory((ushort)(addr & 0x1FFF)); return temp; } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IMemoryDomains.cs index fdaa55729f..9dca7df95a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IMemoryDomains.cs @@ -20,7 +20,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 16, MemoryDomain.Endian.Little, addr => _tia.ReadMemory((ushort)addr, true), - (addr, value) => this._tia.WriteMemory((ushort)addr, value), 1), + (addr, value) => this._tia.WriteMemory((ushort)addr, value, true), 1), new MemoryDomainDelegate( "PIA", 1024, diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/m4A50.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/m4A50.cs index 23e278fc1a..e786465806 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/m4A50.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Mappers/m4A50.cs @@ -170,15 +170,17 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { val = RomImage[(addr & 0xff) + (RomImage.Length - 256)]; if (((_lastData & 0xe0) == 0x60) && ((_lastAddress >= 0x1000) || - (_lastAddress < 0x200))) + (_lastAddress < 0x200)) && !peek) { _sliceHigh = (_sliceHigh & 0xf0ff) | ((addr & 0x8) << 8) | ((addr & 0x70) << 4); } } - - _lastData = val; - _lastAddress = (ushort)(addr & 0x1fff); + if (!peek) + { + _lastData = val; + _lastAddress = (ushort)(addr & 0x1fff); + } return val; } @@ -226,7 +228,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 else if (addr < 0x2000 && !poke) // 256B region at 0x1f00 - 0x1fff { if (((_lastData & 0xe0) == 0x60) && - ((_lastAddress >= 0x1000) || (_lastAddress < 0x200))) + ((_lastAddress >= 0x1000) || (_lastAddress < 0x200)) && !poke) { _sliceHigh = (_sliceHigh & 0xf0ff) | ((addr & 0x8) << 8) | ((addr & 0x70) << 4); @@ -252,96 +254,95 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private void CheckBankSwitch(ushort address, byte value) { - if (((_lastData & 0xe0) == 0x60) && // Switch lower/middle/upper bank - ((_lastAddress >= 0x1000) || (_lastAddress < 0x200))) + if (((_lastData & 0xe0) == 0x60) && // Switch lower/middle/upper bank + ((_lastAddress >= 0x1000) || (_lastAddress < 0x200))) + { + if ((address & 0x0f00) == 0x0c00) // Enable 256B of ROM at 0x1e00 - 0x1eff + { + _isRomHigh = true; + _sliceHigh = (address & 0xff) << 8; + } + else if ((address & 0x0f00) == 0x0d00) // Enable 256B of RAM at 0x1e00 - 0x1eff + { + _isRomHigh = false; + _sliceHigh = (address & 0x7f) << 8; + } + else if ((address & 0x0f40) == 0x0e00) // Enable 2K of ROM at 0x1000 - 0x17ff + { + _isRomLow = true; + _sliceLow = (address & 0x1f) << 11; + } + else if ((address & 0x0f40) == 0x0e40) // Enable 2K of RAM at 0x1000 - 0x17ff + { + _isRomLow = false; + _sliceLow = (address & 0xf) << 11; + } + else if ((address & 0x0f40) == 0x0f00) // Enable 1.5K of ROM at 0x1800 - 0x1dff + { + _isRomMiddle = true; + _sliceMiddle = (address & 0x1f) << 11; + } + else if ((address & 0x0f50) == 0x0f40) // Enable 1.5K of RAM at 0x1800 - 0x1dff + { + _isRomMiddle = false; + _sliceMiddle = (address & 0xf) << 11; + } + else if ((address & 0x0f00) == 0x0400) // Toggle bit A11 of lower block address + { + _sliceLow = _sliceLow ^ 0x800; + } + else if ((address & 0x0f00) == 0x0500) // Toggle bit A12 of lower block address + { + _sliceLow = _sliceLow ^ 0x1000; + } + else if ((address & 0x0f00) == 0x0800) // Toggle bit A11 of middle block address + { + _sliceMiddle = _sliceMiddle ^ 0x800; + } + else if ((address & 0x0f00) == 0x0900) // Toggle bit A12 of middle block address + { + _sliceMiddle = _sliceMiddle ^ 0x1000; + } + } + // Zero-page hotspots for upper page + // 0xf4, 0xf6, 0xfc, 0xfe for ROM + // 0xf5, 0xf7, 0xfd, 0xff for RAM + // 0x74 - 0x7f (0x80 bytes lower) + if ((address & 0xf75) == 0x74) // Enable 256B of ROM at 0x1e00 - 0x1eff { - if ((address & 0x0f00) == 0x0c00) // Enable 256B of ROM at 0x1e00 - 0x1eff - { - _isRomHigh = true; - _sliceHigh = (address & 0xff) << 8; - } - else if ((address & 0x0f00) == 0x0d00) // Enable 256B of RAM at 0x1e00 - 0x1eff - { - _isRomHigh = false; - _sliceHigh = (address & 0x7f) << 8; - } - else if ((address & 0x0f40) == 0x0e00) // Enable 2K of ROM at 0x1000 - 0x17ff + _isRomHigh = true; + _sliceHigh = value << 8; + } + else if ((address & 0xf75) == 0x75) // Enable 256B of RAM at 0x1e00 - 0x1eff + { + _isRomHigh = false; + _sliceHigh = (value & 0x7f) << 8; + } + + // Zero-page hotspots for lower and middle blocks + // 0xf8, 0xf9, 0xfa, 0xfb + // 0x78, 0x79, 0x7a, 0x7b (0x80 bytes lower) + else if ((address & 0xf7c) == 0x78) + { + if ((value & 0xf0) == 0) // Enable 2K of ROM at 0x1000 - 0x17ff { _isRomLow = true; - _sliceLow = (address & 0x1f) << 11; + _sliceLow = (value & 0xf) << 11; } - else if ((address & 0x0f40) == 0x0e40) // Enable 2K of RAM at 0x1000 - 0x17ff + else if ((value & 0xf0) == 0x40) // Enable 2K of RAM at 0x1000 - 0x17ff { _isRomLow = false; - _sliceLow = (address & 0xf) << 11; + _sliceLow = (value & 0xf) << 11; } - else if ((address & 0x0f40) == 0x0f00) // Enable 1.5K of ROM at 0x1800 - 0x1dff + else if ((value & 0xf0) == 0x90) // Enable 1.5K of ROM at 0x1800 - 0x1dff { _isRomMiddle = true; - _sliceMiddle = (address & 0x1f) << 11; + _sliceMiddle = ((value & 0xf) | 0x10) << 11; } - else if ((address & 0x0f50) == 0x0f40) // Enable 1.5K of RAM at 0x1800 - 0x1dff + else if ((value & 0xf0) == 0xc0) // Enable 1.5K of RAM at 0x1800 - 0x1dff { _isRomMiddle = false; - _sliceMiddle = (address & 0xf) << 11; - } - else if ((address & 0x0f00) == 0x0400) // Toggle bit A11 of lower block address - { - _sliceLow = _sliceLow ^ 0x800; - } - else if ((address & 0x0f00) == 0x0500) // Toggle bit A12 of lower block address - { - _sliceLow = _sliceLow ^ 0x1000; - } - else if ((address & 0x0f00) == 0x0800) // Toggle bit A11 of middle block address - { - _sliceMiddle = _sliceMiddle ^ 0x800; - } - else if ((address & 0x0f00) == 0x0900) // Toggle bit A12 of middle block address - { - _sliceMiddle = _sliceMiddle ^ 0x1000; - } - - // Zero-page hotspots for upper page - // 0xf4, 0xf6, 0xfc, 0xfe for ROM - // 0xf5, 0xf7, 0xfd, 0xff for RAM - // 0x74 - 0x7f (0x80 bytes lower) - if ((address & 0xf75) == 0x74) // Enable 256B of ROM at 0x1e00 - 0x1eff - { - _isRomHigh = true; - _sliceHigh = value << 8; - } - else if ((address & 0xf75) == 0x75) // Enable 256B of RAM at 0x1e00 - 0x1eff - { - _isRomHigh = false; - _sliceHigh = (value & 0x7f) << 8; - } - - // Zero-page hotspots for lower and middle blocks - // 0xf8, 0xf9, 0xfa, 0xfb - // 0x78, 0x79, 0x7a, 0x7b (0x80 bytes lower) - else if ((address & 0xf7c) == 0x78) - { - if ((value & 0xf0) == 0) // Enable 2K of ROM at 0x1000 - 0x17ff - { - _isRomLow = true; - _sliceLow = (value & 0xf) << 11; - } - else if ((value & 0xf0) == 0x40) // Enable 2K of RAM at 0x1000 - 0x17ff - { - _isRomLow = false; - _sliceLow = (value & 0xf) << 11; - } - else if ((value & 0xf0) == 0x90) // Enable 1.5K of ROM at 0x1800 - 0x1dff - { - _isRomMiddle = true; - _sliceMiddle = ((value & 0xf) | 0x10) << 11; - } - else if ((value & 0xf0) == 0xc0) // Enable 1.5K of RAM at 0x1800 - 0x1dff - { - _isRomMiddle = false; - _sliceMiddle = (value & 0xf) << 11; - } + _sliceMiddle = (value & 0xf) << 11; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs index b15f6751e2..d381e798f8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs @@ -269,6 +269,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private int[] _palette; + public int bus_state; + private byte pf0_update; private byte pf1_update; private byte pf2_update; @@ -289,6 +291,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private bool enam1_val; private bool enamb_val; + private int vblank_delay; + private byte vblank_value; + private bool p0_stuff; private bool p1_stuff; private bool m0_stuff; @@ -415,10 +420,14 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _capChargeStart = 0; _capCharging = false; _vblankEnabled = false; + vblank_delay = 0; + vblank_value = 0; _vsyncEnabled = false; _CurrentScanLine = 0; _audioClocks = 0; + bus_state = 0; + pf0_update = 0; pf1_update = 0; pf2_update = 0; @@ -472,6 +481,20 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { // Still ignoring cycles... + // delay vblank latch + if (vblank_delay > 0) + { + vblank_delay++; + if (vblank_delay==3) + { + _vblankEnabled = (vblank_value & 0x02) != 0; + vblank_delay = 0; + } + + } + + + //delay latch to new playfield register if (pf0_updater == true) { @@ -716,7 +739,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - if (_playField.Score && !_playField.Priority && (collisions & CXPF) != 0 && _core.Settings.ShowPlayfield) + if (_playField.Score && !_playField.Priority && ((collisions & CXPF) != 0) && _core.Settings.ShowPlayfield) { pixelColor = !rightSide ? _palette[_player0.Color] : _palette[_player1.Color]; } @@ -1047,44 +1070,55 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public byte ReadMemory(ushort addr, bool peek) { var maskedAddr = (ushort)(addr & 0x000F); + byte coll = 0; + int mask = 0; + if (maskedAddr == 0x00) // CXM0P { - return (byte)((((_player0.Missile.Collisions & CXP1) != 0) ? 0x80 : 0x00) | (((_player0.Missile.Collisions & CXP0) != 0) ? 0x40 : 0x00)); + coll=(byte)((((_player0.Missile.Collisions & CXP1) != 0) ? 0x80 : 0x00) | (((_player0.Missile.Collisions & CXP0) != 0) ? 0x40 : 0x00)); + mask = 0x3f; } if (maskedAddr == 0x01) // CXM1P { - return (byte)((((_player1.Missile.Collisions & CXP0) != 0) ? 0x80 : 0x00) | (((_player1.Missile.Collisions & CXP1) != 0) ? 0x40 : 0x00)); + coll = (byte)((((_player1.Missile.Collisions & CXP0) != 0) ? 0x80 : 0x00) | (((_player1.Missile.Collisions & CXP1) != 0) ? 0x40 : 0x00)); + mask = 0x3f; } if (maskedAddr == 0x02) // CXP0FB { - return (byte)((((_player0.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player0.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + coll = (byte)((((_player0.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player0.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + mask = 0x3f; } if (maskedAddr == 0x03) // CXP1FB { - return (byte)((((_player1.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player1.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + coll = (byte)((((_player1.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player1.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + mask = 0x3f; } if (maskedAddr == 0x04) // CXM0FB { - return (byte)((((_player0.Missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player0.Missile.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + coll = (byte)((((_player0.Missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player0.Missile.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + mask = 0x3f; } if (maskedAddr == 0x05) // CXM1FB { - return (byte)((((_player1.Missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player1.Missile.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + coll = (byte)((((_player1.Missile.Collisions & CXPF) != 0) ? 0x80 : 0x00) | (((_player1.Missile.Collisions & CXBL) != 0) ? 0x40 : 0x00)); + mask = 0x3f; } if (maskedAddr == 0x06) // CXBLPF { - return (byte)(((_ball.Collisions & CXPF) != 0) ? 0x80 : 0x00); + coll = (byte)(((_ball.Collisions & CXPF) != 0) ? 0x80 : 0x00); + mask = 0x7f; } if (maskedAddr == 0x07) // CXPPMM { - return (byte)((((_player0.Collisions & CXP1) != 0) ? 0x80 : 0x00) | (((_player0.Missile.Collisions & CXM1) != 0) ? 0x40 : 0x00)); + coll = (byte)((((_player0.Collisions & CXP1) != 0) ? 0x80 : 0x00) | (((_player0.Missile.Collisions & CXM1) != 0) ? 0x40 : 0x00)); + mask = 0x3f; } if (maskedAddr == 0x08) // INPT0 @@ -1093,28 +1127,38 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // 6105 roughly centers the paddle in Breakout if (_capCharging && _core.Cpu.TotalExecutedCycles - _capChargeStart >= 6105) { - return 0x80; + coll=0x80; } - return 0x00; + coll=0x00; + mask = 0x7f; } if (maskedAddr == 0x0C) // INPT4 { - return (byte)((_core.ReadControls1(peek) & 0x08) != 0 ? 0x80 : 0x00); + coll = (byte)((_core.ReadControls1(peek) & 0x08) != 0 ? 0x80 : 0x00); + mask = 0x7f; } if (maskedAddr == 0x0D) // INPT5 { - return (byte)((_core.ReadControls2(peek) & 0x08) != 0 ? 0x80 : 0x00); + coll = (byte)((_core.ReadControls2(peek) & 0x08) != 0 ? 0x80 : 0x00); + mask = 0x7f; } - return 0x00; + //some bits of the databus will be undriven when a read call is made. Our goal here is to sort out what + // happens to the undriven pins. Most of the time, they will be in whatever state they were when previously + //assigned in some other bus access, so let's go with that. + coll+=(byte)(mask & bus_state); + + if (!peek) bus_state = (int)coll; + return coll; } - public void WriteMemory(ushort addr, byte value) + public void WriteMemory(ushort addr, byte value, bool poke) { var maskedAddr = (ushort)(addr & 0x3f); + if (!poke) bus_state = value; if (maskedAddr == 0x00) // VSYNC { @@ -1145,7 +1189,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } else if (maskedAddr == 0x01) // VBLANK { - _vblankEnabled = (value & 0x02) != 0; + vblank_delay = 1; + vblank_value = value; _capCharging = (value & 0x80) == 0; if ((value & 0x80) == 0) { @@ -1575,6 +1620,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.Sync("hsyncCnt", ref _hsyncCnt); // add everything to the state + ser.Sync("Bus_State", ref bus_state); + ser.Sync("PF0_up",ref pf0_update); ser.Sync("PF1_up", ref pf1_update); ser.Sync("PF2_up", ref pf2_update); @@ -1613,7 +1660,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.Sync("Ticks", ref do_ticks); - + ser.Sync("VBlankDelay", ref vblank_delay); + ser.Sync("VBlankValue", ref vblank_value); // some of these things weren't in the state because they weren't needed if // states were always taken at frame boundaries