2016-03-01 19:50:07 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using BizHawk.Common;
|
2016-03-05 22:00:19 +00:00
|
|
|
|
using BizHawk.Emulation.Common;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
|
|
|
|
|
{
|
2017-05-12 20:13:05 +00:00
|
|
|
|
public abstract class CartridgeDevice : IDriveLight
|
2016-03-01 19:50:07 +00:00
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
public Func<int> ReadOpenBus;
|
2016-03-06 22:31:29 +00:00
|
|
|
|
|
2016-03-01 19:50:07 +00:00
|
|
|
|
public static CartridgeDevice Load(byte[] crtFile)
|
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
using (var mem = new MemoryStream(crtFile))
|
|
|
|
|
{
|
|
|
|
|
var reader = new BinaryReader(mem);
|
|
|
|
|
|
|
|
|
|
if (new string(reader.ReadChars(16)) != "C64 CARTRIDGE ")
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var chipAddress = new List<int>();
|
|
|
|
|
var chipBank = new List<int>();
|
|
|
|
|
var chipData = new List<int[]>();
|
|
|
|
|
var chipType = new List<int>();
|
|
|
|
|
|
|
|
|
|
var headerLength = ReadCRTInt(reader);
|
|
|
|
|
var version = ReadCRTShort(reader);
|
|
|
|
|
var mapper = ReadCRTShort(reader);
|
|
|
|
|
var exrom = reader.ReadByte() != 0;
|
|
|
|
|
var game = reader.ReadByte() != 0;
|
|
|
|
|
|
|
|
|
|
// reserved
|
|
|
|
|
reader.ReadBytes(6);
|
|
|
|
|
|
|
|
|
|
// cartridge name
|
|
|
|
|
reader.ReadBytes(0x20);
|
|
|
|
|
|
|
|
|
|
// skip extra header bytes
|
|
|
|
|
if (headerLength > 0x40)
|
|
|
|
|
{
|
|
|
|
|
reader.ReadBytes(headerLength - 0x40);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read chips
|
|
|
|
|
while (reader.PeekChar() >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (new string(reader.ReadChars(4)) != "CHIP")
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var chipLength = ReadCRTInt(reader);
|
|
|
|
|
chipType.Add(ReadCRTShort(reader));
|
|
|
|
|
chipBank.Add(ReadCRTShort(reader));
|
|
|
|
|
chipAddress.Add(ReadCRTShort(reader));
|
|
|
|
|
var chipDataLength = ReadCRTShort(reader);
|
|
|
|
|
chipData.Add(reader.ReadBytes(chipDataLength).Select(x => (int)x).ToArray());
|
|
|
|
|
chipLength -= chipDataLength + 0x10;
|
|
|
|
|
if (chipLength > 0)
|
2017-05-30 17:09:46 +00:00
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
reader.ReadBytes(chipLength);
|
2017-05-30 17:09:46 +00:00
|
|
|
|
}
|
2017-04-24 13:35:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chipData.Count <= 0)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CartridgeDevice result;
|
|
|
|
|
switch (mapper)
|
|
|
|
|
{
|
|
|
|
|
case 0x0000: // Standard Cartridge
|
|
|
|
|
result = new Mapper0000(chipAddress, chipData, game, exrom);
|
|
|
|
|
break;
|
|
|
|
|
case 0x0001: // Action Replay (4.2 and up)
|
|
|
|
|
result = new Mapper0001(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x0005: // Ocean
|
|
|
|
|
result = new Mapper0005(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
2017-05-29 19:05:06 +00:00
|
|
|
|
case 0x0007: // Fun Play
|
|
|
|
|
result = new Mapper0007(chipData, game, exrom);
|
|
|
|
|
break;
|
2017-05-18 20:18:49 +00:00
|
|
|
|
case 0x0008: // SuperGame
|
|
|
|
|
result = new Mapper0008(chipData);
|
|
|
|
|
break;
|
2017-04-24 13:35:05 +00:00
|
|
|
|
case 0x000A: // Epyx FastLoad
|
|
|
|
|
result = new Mapper000A(chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x000B: // Westermann Learning
|
|
|
|
|
result = new Mapper000B(chipAddress, chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x000F: // C64 Game System / System 3
|
|
|
|
|
result = new Mapper000F(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x0011: // Dinamic
|
|
|
|
|
result = new Mapper0011(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x0012: // Zaxxon / Super Zaxxon
|
|
|
|
|
result = new Mapper0012(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x0013: // Domark
|
|
|
|
|
result = new Mapper0013(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x0020: // EasyFlash
|
|
|
|
|
result = new Mapper0020(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
|
|
|
|
case 0x002B: // Prophet 64
|
|
|
|
|
result = new Mapper002B(chipAddress, chipBank, chipData);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception("This cartridge file uses an unrecognized mapper: " + mapper);
|
|
|
|
|
}
|
|
|
|
|
result.HardReset();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
|
|
|
|
private static int ReadCRTShort(BinaryReader reader)
|
|
|
|
|
{
|
2017-04-24 13:35:05 +00:00
|
|
|
|
return (reader.ReadByte() << 8) |
|
|
|
|
|
reader.ReadByte();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int ReadCRTInt(BinaryReader reader)
|
|
|
|
|
{
|
|
|
|
|
return (reader.ReadByte() << 24) |
|
2017-04-24 13:35:05 +00:00
|
|
|
|
(reader.ReadByte() << 16) |
|
|
|
|
|
(reader.ReadByte() << 8) |
|
|
|
|
|
reader.ReadByte();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected bool pinExRom;
|
2017-05-13 15:11:13 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
protected bool pinGame;
|
2017-05-13 15:11:13 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
protected bool pinIRQ;
|
2017-05-13 15:11:13 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
protected bool pinNMI;
|
2017-05-13 15:11:13 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
protected bool pinReset;
|
2017-05-13 15:11:13 +00:00
|
|
|
|
|
2017-04-24 13:35:05 +00:00
|
|
|
|
protected bool validCartridge;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
2016-03-04 03:14:19 +00:00
|
|
|
|
public virtual void ExecutePhase()
|
2016-03-01 19:50:07 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 17:09:46 +00:00
|
|
|
|
public bool ExRom => pinExRom;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
2017-05-30 17:09:46 +00:00
|
|
|
|
public bool Game => pinGame;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
|
|
|
|
public virtual void HardReset()
|
|
|
|
|
{
|
|
|
|
|
pinIRQ = true;
|
|
|
|
|
pinNMI = true;
|
|
|
|
|
pinReset = true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 17:09:46 +00:00
|
|
|
|
public bool IRQ => pinIRQ;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
2017-05-30 17:09:46 +00:00
|
|
|
|
public bool NMI => pinNMI;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
|
|
|
|
public virtual int Peek8000(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual int PeekA000(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual int PeekDE00(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual int PeekDF00(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void Poke8000(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void PokeA000(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void PokeDE00(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void PokeDF00(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual int Read8000(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual int ReadA000(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual int ReadDE00(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual int ReadDF00(int addr)
|
|
|
|
|
{
|
2016-03-06 22:31:29 +00:00
|
|
|
|
return ReadOpenBus();
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 17:09:46 +00:00
|
|
|
|
public bool Reset => pinReset;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
2017-05-13 15:11:13 +00:00
|
|
|
|
protected abstract void SyncStateInternal(Serializer ser);
|
|
|
|
|
|
2016-03-01 19:50:07 +00:00
|
|
|
|
public virtual void SyncState(Serializer ser)
|
|
|
|
|
{
|
2019-03-28 03:18:58 +00:00
|
|
|
|
ser.Sync(nameof(pinExRom), ref pinExRom);
|
|
|
|
|
ser.Sync(nameof(pinGame), ref pinGame);
|
|
|
|
|
ser.Sync(nameof(pinIRQ), ref pinIRQ);
|
|
|
|
|
ser.Sync(nameof(pinNMI), ref pinNMI);
|
|
|
|
|
ser.Sync(nameof(pinReset), ref pinReset);
|
|
|
|
|
|
|
|
|
|
ser.Sync(nameof(_driveLightEnabled), ref _driveLightEnabled);
|
|
|
|
|
ser.Sync(nameof(_driveLightOn), ref _driveLightOn);
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 17:09:46 +00:00
|
|
|
|
public bool Valid => validCartridge;
|
2016-03-01 19:50:07 +00:00
|
|
|
|
|
|
|
|
|
public virtual void Write8000(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void WriteA000(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void WriteDE00(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void WriteDF00(int addr, int val)
|
|
|
|
|
{
|
|
|
|
|
}
|
2016-03-05 22:00:19 +00:00
|
|
|
|
|
2017-05-13 15:11:13 +00:00
|
|
|
|
private bool _driveLightEnabled;
|
|
|
|
|
private bool _driveLightOn;
|
|
|
|
|
|
|
|
|
|
public bool DriveLightEnabled
|
|
|
|
|
{
|
|
|
|
|
get { return _driveLightEnabled; }
|
|
|
|
|
protected set { _driveLightEnabled = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool DriveLightOn
|
|
|
|
|
{
|
|
|
|
|
get { return _driveLightOn; }
|
|
|
|
|
protected set { _driveLightOn = value; }
|
|
|
|
|
}
|
2016-03-01 19:50:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|