Atari 2600 - AR - cleanup, implement hard reset, savestates, and dispose

This commit is contained in:
adelikat 2014-05-26 00:55:12 +00:00
parent 8069653888
commit d1743a2ce3
2 changed files with 215 additions and 98 deletions

View File

@ -536,6 +536,22 @@ namespace BizHawk.Common
} }
} }
public void Sync(string name, ref ulong val)
{
if (IsText)
{
SyncText(name, ref val);
}
else if (IsReader)
{
Read(ref val);
}
else
{
Write(ref val);
}
}
public void Sync(string name, ref float val) public void Sync(string name, ref float val)
{ {
if (IsText) if (IsText)
@ -823,6 +839,18 @@ namespace BizHawk.Common
} }
} }
private void SyncText(string name, ref ulong val)
{
if (IsReader)
{
ReadText(name, ref val);
}
else
{
WriteText(name, ref val);
}
}
private void SyncText(string name, ref float val) private void SyncText(string name, ref float val)
{ {
if (IsReader) if (IsReader)
@ -1017,6 +1045,16 @@ namespace BizHawk.Common
_bw.Write(val); _bw.Write(val);
} }
private void Read(ref ulong val)
{
val = _br.ReadUInt64();
}
private void Write(ref ulong val)
{
_bw.Write(val);
}
private void ReadText(string name, ref long val) private void ReadText(string name, ref long val)
{ {
if (Present(name)) if (Present(name))
@ -1030,6 +1068,19 @@ namespace BizHawk.Common
_tw.WriteLine("{0} 0x{1:X16}", name, val); _tw.WriteLine("{0} 0x{1:X16}", name, val);
} }
private void ReadText(string name, ref ulong val)
{
if (Present(name))
{
val = ulong.Parse(Item(name).Replace("0x", ""), NumberStyles.HexNumber);
}
}
private void WriteText(string name, ref ulong val)
{
_tw.WriteLine("{0} 0x{1:X16}", name, val);
}
private void Read(ref float val) private void Read(ref float val)
{ {
val = _br.ReadSingle(); val = _br.ReadSingle();

View File

@ -35,54 +35,57 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{ {
internal class mAR : MapperBase internal class mAR : MapperBase
{ {
// TODO: can we set the defaults instead of do it in the constructor?
// TODO: fastscbios setting // TODO: fastscbios setting
// TODO: var names, savestates, hard reset, dispose, cart ram // TODO: cart ram
// TOOD: pokeMem
public mAR(Atari2600 core) public mAR(Atari2600 core)
{
Core = core;
InitializeSettings();
}
private ByteBuffer _superChargerImage = new ByteBuffer(8192);
private IntBuffer _imageOffsets = new IntBuffer(2);
private bool _writePending = false;
private int _distinctAccesses = 0;
private bool _writeEnabled = false;
private byte _dataHoldRegister;
private byte _numberOfLoadImages;
private ByteBuffer _loadedImages;
private ByteBuffer _header = new ByteBuffer(256);
private bool _powerIndicator; // Indicates if the ROM's power is on or off
private int _powerRomCycle; // Indicates when the power was last turned on
private int _size;
private ulong _elapsedCycles;
private void InitializeSettings()
{ {
// TODO: clean this stuff up // TODO: clean this stuff up
/*****************************************/ /*****************************************/
int size = core.Rom.Length; int size = Core.Rom.Length;
mySize = core.Rom.Length < 8448 ? 8448 : core.Rom.Length; //8448 or Rom size, whichever is bigger _size = Core.Rom.Length < 8448 ? 8448 : Core.Rom.Length; //8448 or Rom size, whichever is bigger
myNumberOfLoadImages = (byte)(mySize / 8448); _numberOfLoadImages = (byte)(_size / 8448);
// TODO: why are we making a redundant copy? // TODO: why are we making a redundant copy?
myLoadedImages = new ByteBuffer(mySize); _loadedImages = new ByteBuffer(_size);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
myLoadedImages[i] = core.Rom[i]; _loadedImages[i] = Core.Rom[i];
} }
if (size < 8448) if (size < 8448)
{ {
for (int i = size; i < mySize; i++) for (int i = size; i < _size; i++)
{ {
myLoadedImages[i] = DefaultHeader[i]; _loadedImages[i] = DefaultHeader[i];
} }
} }
/*****************************************/ /*****************************************/
Core = core;
InitializeRom(); InitializeRom();
BankConfiguration(0); BankConfiguration(0);
} }
private ByteBuffer myImage = new ByteBuffer(8192);
private IntBuffer myImageOffsets = new IntBuffer(2);
private bool myWritePending = false;
private int myNumberOfDistinctAccesses = 0;
private bool myWriteEnabled = false;
private byte myDataHoldRegister;
private byte myNumberOfLoadImages;
private ByteBuffer myLoadedImages;
private byte[] myHeader = new byte[256];
private bool myPower; // Indicates if the ROM's power is on or off
private int myPowerRomCycle; // Indicates when the power was last turned on
private int mySize;
private ulong _elapsedCycles;
#region SuperCharger Data #region SuperCharger Data
private readonly byte[] DummyRomCode = { private readonly byte[] DummyRomCode = {
@ -162,6 +165,59 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
#endregion #endregion
public override void HardReset()
{
_superChargerImage = new ByteBuffer(8192);
_imageOffsets = new IntBuffer(2);
_writePending = false;
_distinctAccesses = 0;
_writeEnabled = false;
_dataHoldRegister = 0;
_numberOfLoadImages = 0;
_loadedImages = null;
_header = new ByteBuffer(256);
_powerIndicator = false;
_powerRomCycle = 0;
_size = 0;
_elapsedCycles = 0;
InitializeSettings();
base.HardReset();
}
public override void Dispose()
{
_superChargerImage.Dispose();
_imageOffsets.Dispose();
_loadedImages.Dispose();
base.Dispose();
}
public override void SyncState(Serializer ser)
{
ser.Sync("superChargerImage", ref _superChargerImage);
ser.Sync("imageOffsets", ref _imageOffsets);
ser.Sync("writePending", ref _writePending);
ser.Sync("distinctAccesses", ref _distinctAccesses);
ser.Sync("writeEnabled", ref _writeEnabled);
ser.Sync("dataHoldRegister", ref _dataHoldRegister);
ser.Sync("numberOfLoadImages", ref _numberOfLoadImages);
ser.Sync("loadedImages", ref _loadedImages);
ser.Sync("header", ref _header);
ser.Sync("powerIndicator", ref _powerIndicator);
ser.Sync("powerRomCycle", ref _powerRomCycle);
ser.Sync("size", ref _size);
ser.Sync("elapsedCycles", ref _elapsedCycles);
base.SyncState(ser);
}
public override void ClockCpu() public override void ClockCpu()
{ {
_elapsedCycles++; _elapsedCycles++;
@ -174,50 +230,50 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
/*---------------------------*/ /*---------------------------*/
if (addr == 0x1850 && myImageOffsets[1] == (3 << 11)) if (addr == 0x1850 && _imageOffsets[1] == (3 << 11))
{ {
LoadIntoRam(Core.MemoryDomains["System Bus"].PeekByte(0x80)); // Get load that's being accessed (BIOS places load number at 0x80) // TODO: a better way to do this LoadIntoRam(Core.MemoryDomains["System Bus"].PeekByte(0x80)); // Get load that's being accessed (BIOS places load number at 0x80) // TODO: a better way to do this
return myImage[(addr & 0x7FF) + myImageOffsets[1]]; return _superChargerImage[(addr & 0x7FF) + _imageOffsets[1]];
} }
if (myWritePending && // Cancel any pending write if more than 5 distinct accesses have occurred // TODO: Modify to handle when the distinct counter wraps around... if (_writePending && // Cancel any pending write if more than 5 distinct accesses have occurred // TODO: Modify to handle when the distinct counter wraps around...
(Core.DistinctAccessCount > myNumberOfDistinctAccesses + 5)) (Core.DistinctAccessCount > _distinctAccesses + 5))
{ {
myWritePending = false; _writePending = false;
} }
/*---------------------------*/ /*---------------------------*/
if (!((addr & 0x0F00) > 0) && (!myWriteEnabled || !myWritePending)) if (!((addr & 0x0F00) > 0) && (!_writeEnabled || !_writePending))
{ {
myDataHoldRegister = (byte)addr; _dataHoldRegister = (byte)addr;
myNumberOfDistinctAccesses = Core.DistinctAccessCount; _distinctAccesses = Core.DistinctAccessCount;
myWritePending = true; _writePending = true;
} }
else if ((addr & 0x1FFF) == 0x1FF8) // Is the bank configuration hotspot being accessed? else if ((addr & 0x1FFF) == 0x1FF8) // Is the bank configuration hotspot being accessed?
{ {
myWritePending = false; _writePending = false;
BankConfiguration(myDataHoldRegister); BankConfiguration(_dataHoldRegister);
} }
else if (myWriteEnabled && myWritePending && else if (_writeEnabled && _writePending &&
Core.DistinctAccessCount == (myNumberOfDistinctAccesses + 5)) Core.DistinctAccessCount == (_distinctAccesses + 5))
{ {
if ((addr & 0x800) == 0) if ((addr & 0x800) == 0)
{ {
myImage[(addr & 0x07FF) + myImageOffsets[0]] = myDataHoldRegister; _superChargerImage[(addr & 0x07FF) + _imageOffsets[0]] = _dataHoldRegister;
} }
else if (myImageOffsets[1] != (3 << 11)) // Don't poke Rom else if (_imageOffsets[1] != (3 << 11)) // Don't poke Rom
{ {
myImage[(addr & 0x07FF) + myImageOffsets[1]] = myDataHoldRegister; _superChargerImage[(addr & 0x07FF) + _imageOffsets[1]] = _dataHoldRegister;
} }
myWritePending = false; _writePending = false;
} }
/*---------------------------*/ /*---------------------------*/
return myImage[(addr & 0x07FF) + myImageOffsets[((addr & 0x800) > 0) ? 1 : 0]]; return _superChargerImage[(addr & 0x07FF) + _imageOffsets[((addr & 0x800) > 0) ? 1 : 0]];
} }
public override byte ReadMemory(ushort addr) public override byte ReadMemory(ushort addr)
@ -230,7 +286,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return ReadMem(addr, true); return ReadMem(addr, true);
} }
public override void WriteMemory(ushort addr, byte value) private void WriteMem(ushort addr, byte value, bool poke)
{ {
if (addr < 0x1000) if (addr < 0x1000)
{ {
@ -238,43 +294,53 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
return; return;
} }
if (myWritePending && (Core.DistinctAccessCount > myNumberOfDistinctAccesses + 5)) if (!poke && _writePending && (Core.DistinctAccessCount > _distinctAccesses + 5))
{ {
myWritePending = false; _writePending = false;
} }
// Is the data hold register being set? // Is the data hold register being set?
if (!((addr & 0x0F00) > 0) && (!myWriteEnabled || !myWritePending)) if (!poke && !((addr & 0x0F00) > 0) && (!_writeEnabled || !_writePending))
{ {
myDataHoldRegister = (byte)addr; _dataHoldRegister = (byte)addr;
myNumberOfDistinctAccesses = Core.DistinctAccessCount; _distinctAccesses = Core.DistinctAccessCount;
myWritePending = true; _writePending = true;
} }
// Is the bank configuration hotspot being accessed? // Is the bank configuration hotspot being accessed?
else if ((addr & 0x1FFF) == 0x1FF8) else if (!poke && (addr & 0x1FFF) == 0x1FF8)
{ {
// Yes, so handle bank configuration // Yes, so handle bank configuration
myWritePending = false; _writePending = false;
BankConfiguration(myDataHoldRegister); BankConfiguration(_dataHoldRegister);
} }
// Handle poke if writing enabled // Handle poke if writing enabled
else if (myWriteEnabled && myWritePending && else if (_writeEnabled && _writePending &&
(Core.DistinctAccessCount == (myNumberOfDistinctAccesses + 5))) (Core.DistinctAccessCount == (_distinctAccesses + 5)))
{ {
if ((addr & 0x0800) == 0) if ((addr & 0x0800) == 0)
{ {
myImage[(addr & 0x07FF) + myImageOffsets[0]] = myDataHoldRegister; _superChargerImage[(addr & 0x07FF) + _imageOffsets[0]] = _dataHoldRegister;
} }
else if (myImageOffsets[1] != (3 << 11)) // Can't poke to ROM else if (_imageOffsets[1] != (3 << 11)) // Can't poke to ROM
{ {
myImage[(addr & 0x07FF) + myImageOffsets[1]] = myDataHoldRegister; _superChargerImage[(addr & 0x07FF) + _imageOffsets[1]] = _dataHoldRegister;
} }
myWritePending = false; _writePending = false;
} }
} }
public override void WriteMemory(ushort addr, byte value)
{
WriteMem(addr, value, poke: false);
}
public override void PokeMemory(ushort addr, byte value)
{
WriteMem(addr, value, poke: true);
}
private void InitializeRom() private void InitializeRom()
{ {
/* scrom.asm data borrowed from Stella: /* scrom.asm data borrowed from Stella:
@ -295,20 +361,20 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam // Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
for (int i = 0; i < 2048; i++) for (int i = 0; i < 2048; i++)
{ {
myImage[(3 << 11) + i] = 0x02; _superChargerImage[(3 << 11) + i] = 0x02;
} }
// Copy the "dummy" Supercharger BIOS code into the ROM area // Copy the "dummy" Supercharger BIOS code into the ROM area
for (int i = 0; i < DummyRomCode.Length; i++) for (int i = 0; i < DummyRomCode.Length; i++)
{ {
myImage[(3 << 11) + i] = DummyRomCode[i]; _superChargerImage[(3 << 11) + i] = DummyRomCode[i];
} }
// Finally set 6502 vectors to point to initial load code at 0xF80A of BIOS // Finally set 6502 vectors to point to initial load code at 0xF80A of BIOS
myImage[(3 << 11) + 2044] = 0x0A; _superChargerImage[(3 << 11) + 2044] = 0x0A;
myImage[(3 << 11) + 2045] = 0xF8; _superChargerImage[(3 << 11) + 2045] = 0xF8;
myImage[(3 << 11) + 2046] = 0x0A; _superChargerImage[(3 << 11) + 2046] = 0x0A;
myImage[(3 << 11) + 2047] = 0xF8; _superChargerImage[(3 << 11) + 2047] = 0xF8;
} }
private void BankConfiguration(byte configuration) private void BankConfiguration(byte configuration)
@ -332,47 +398,47 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// wanting to access the ROM for multiloads. Otherwise set to 1. // wanting to access the ROM for multiloads. Otherwise set to 1.
//_bank2k = configuration & 0x1F; // remember for the bank() method //_bank2k = configuration & 0x1F; // remember for the bank() method
myPower = !((configuration & 0x01) > 0); _powerIndicator = !((configuration & 0x01) > 0);
if (myPower) if (_powerIndicator)
{ {
myPowerRomCycle = (int)_elapsedCycles; _powerRomCycle = (int)_elapsedCycles;
} }
myWriteEnabled = (configuration & 0x02) > 0; _writeEnabled = (configuration & 0x02) > 0;
switch ((configuration >> 2) & 0x07) switch ((configuration >> 2) & 0x07)
{ {
case 0x00: case 0x00:
myImageOffsets[0] = 2 << 11; _imageOffsets[0] = 2 << 11;
myImageOffsets[1] = 3 << 11; _imageOffsets[1] = 3 << 11;
break; break;
case 0x01: case 0x01:
myImageOffsets[0] = 0; _imageOffsets[0] = 0;
myImageOffsets[1] = 3 << 11; _imageOffsets[1] = 3 << 11;
break; break;
case 0x02: case 0x02:
myImageOffsets[0] = 2 << 11; _imageOffsets[0] = 2 << 11;
myImageOffsets[1] = 0; _imageOffsets[1] = 0;
break; break;
case 0x03: case 0x03:
myImageOffsets[0] = 0; _imageOffsets[0] = 0;
myImageOffsets[1] = 2 << 11; _imageOffsets[1] = 2 << 11;
break; break;
case 0x04: case 0x04:
myImageOffsets[0] = 2 << 11; _imageOffsets[0] = 2 << 11;
myImageOffsets[1] = 3 << 11; _imageOffsets[1] = 3 << 11;
break; break;
case 0x05: case 0x05:
myImageOffsets[0] = 1 << 11; _imageOffsets[0] = 1 << 11;
myImageOffsets[1] = 3 << 11; _imageOffsets[1] = 3 << 11;
break; break;
case 0x06: case 0x06:
myImageOffsets[0] = 2 << 11; _imageOffsets[0] = 2 << 11;
myImageOffsets[1] = 1 << 11; _imageOffsets[1] = 1 << 11;
break; break;
case 0x07: case 0x07:
myImageOffsets[0] = 1 << 11; _imageOffsets[0] = 1 << 11;
myImageOffsets[1] = 2 << 11; _imageOffsets[1] = 2 << 11;
break; break;
} }
} }
@ -381,16 +447,16 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{ {
ushort image; ushort image;
for (image = 0; image < myNumberOfLoadImages; image++) for (image = 0; image < _numberOfLoadImages; image++)
{ {
if (myLoadedImages[(image * 8448) + 8192 + 5] == load) if (_loadedImages[(image * 8448) + 8192 + 5] == load)
{ {
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
{ {
myHeader[i] = myLoadedImages[(image * 8448) + 8192 + i]; _header[i] = _loadedImages[(image * 8448) + 8192 + i];
} }
if (Checksum(myHeader.Take(8).ToArray()) != 0x55) if (Checksum(_header.Arr.Take(8).ToArray()) != 0x55)
{ {
Console.WriteLine("WARNING: The Supercharger header checksum is invalid..."); Console.WriteLine("WARNING: The Supercharger header checksum is invalid...");
} }
@ -399,12 +465,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// Load all of the pages from the load // Load all of the pages from the load
bool invalidPageChecksumSeen = false; bool invalidPageChecksumSeen = false;
for (int j = 0; j < myHeader[3]; j++) for (int j = 0; j < _header[3]; j++)
{ {
int bank = myHeader[16 + j] & 0x03; int bank = _header[16 + j] & 0x03;
int page = (myHeader[16 + j] >> 2) & 0x07; int page = (_header[16 + j] >> 2) & 0x07;
var src = myLoadedImages.Arr.Skip((image * 8448) + (j * 256)).Take(256).ToArray(); var src = _loadedImages.Arr.Skip((image * 8448) + (j * 256)).Take(256).ToArray();
byte sum = (byte)(Checksum(src) + myHeader[16 + j] + myHeader[64 + j]); byte sum = (byte)(Checksum(src) + _header[16 + j] + _header[64 + j]);
if (!invalidPageChecksumSeen && (sum != 0x55)) if (!invalidPageChecksumSeen && (sum != 0x55))
{ {
@ -416,15 +482,15 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{ {
for (int k = 0; k < src.Length; k++) for (int k = 0; k < src.Length; k++)
{ {
myImage[(bank * 2048) + (page * 256) + k] = src[k]; _superChargerImage[(bank * 2048) + (page * 256) + k] = src[k];
} }
} }
} }
// TODO: is this the correct Write to do? // TODO: is this the correct Write to do?
base.WriteMemory(0xFE, myHeader[0]); base.WriteMemory(0xFE, _header[0]);
base.WriteMemory(0xFF, myHeader[1]); base.WriteMemory(0xFF, _header[1]);
base.WriteMemory(0x80, myHeader[2]); base.WriteMemory(0x80, _header[2]);
} }
} }
} }