commodore64: full PAL support across all chips, better HardReset behavior
This commit is contained in:
parent
e48f24d266
commit
0a8355ce1a
|
@ -55,6 +55,17 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
mem.HardReset();
|
||||
cia0.HardReset();
|
||||
cia1.HardReset();
|
||||
vic.HardReset();
|
||||
sid.HardReset();
|
||||
if (diskDriveAttached)
|
||||
diskDrive.HardReset();
|
||||
}
|
||||
|
||||
private void Init(Region initRegion)
|
||||
{
|
||||
// initalize cpu
|
||||
cpu = new MOS6502X();
|
||||
|
@ -63,24 +74,36 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
cpu.DummyReadMemory = PeekMemory;
|
||||
|
||||
// initialize cia timers
|
||||
cia0 = new Cia(Region.NTSC);
|
||||
cia1 = new Cia(Region.NTSC);
|
||||
cia0 = new Cia(initRegion);
|
||||
cia1 = new Cia(initRegion);
|
||||
|
||||
// initialize vic
|
||||
signal = new ChipSignals();
|
||||
vic = new VicII(signal, Region.NTSC);
|
||||
vic = new VicII(signal, initRegion);
|
||||
|
||||
// assume NTSC for now
|
||||
// set vsync rate
|
||||
CoreOutputComm.VsyncDen = vic.cyclesPerFrame;
|
||||
CoreOutputComm.VsyncNum = (14318181 / 14);
|
||||
switch (initRegion)
|
||||
{
|
||||
case Region.NTSC:
|
||||
CoreOutputComm.VsyncNum = (14318181 / 14);
|
||||
break;
|
||||
case Region.PAL:
|
||||
CoreOutputComm.VsyncNum = (14318181 / 18);
|
||||
break;
|
||||
}
|
||||
|
||||
// initialize sid
|
||||
sid = new Sid(Region.NTSC, 44100); // we'll assume 44.1k for now until there's a better way
|
||||
sid = new Sid(initRegion, 44100); // we'll assume 44.1k for now until there's a better way
|
||||
syncSid = new SidSyncSoundProvider(sid);
|
||||
//sidDCFilter = new Emulation.Sound.Utilities.DCFilter(sid, 2205);
|
||||
|
||||
// initialize memory (this must be done AFTER all other chips are initialized)
|
||||
string romPath = CoreInputComm.C64_FirmwaresPath;
|
||||
if (romPath == null)
|
||||
{
|
||||
romPath = @".\C64\Firmwares";
|
||||
}
|
||||
mem = new Memory(romPath, vic, sid, cia0, cia1);
|
||||
vic.mem = mem;
|
||||
|
||||
|
@ -89,7 +112,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
cpu.BCD_Enabled = true;
|
||||
|
||||
// initailize input
|
||||
input = new Input( new DataPortConnector[] { cia0.ConnectPort(0), cia0.ConnectPort(1) } );
|
||||
input = new Input(new DataPortConnector[] { cia0.ConnectPort(0), cia0.ConnectPort(1) });
|
||||
cia0.AttachWriteHook(0, input.WritePortA);
|
||||
cia0.AttachWriteHook(1, input.WritePortB);
|
||||
|
||||
|
@ -97,11 +120,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
switch (extension.ToUpper())
|
||||
{
|
||||
case @".G64":
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC, cia1);
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1);
|
||||
diskDrive.Insert(G64.Read(inputFile));
|
||||
break;
|
||||
case @".D64":
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), Region.NTSC, cia1);
|
||||
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1);
|
||||
diskDrive.Insert(D64.Read(inputFile));
|
||||
break;
|
||||
case @".PRG":
|
||||
|
|
|
@ -16,43 +16,55 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
SetupMemoryDomains();
|
||||
CoreOutputComm = new CoreOutputComm();
|
||||
CoreInputComm = new CoreInputComm();
|
||||
Init(Region.NTSC);
|
||||
}
|
||||
|
||||
public string SystemId { get { return "C64"; } }
|
||||
public GameInfo game;
|
||||
|
||||
public CoreInputComm CoreInputComm { get; set; }
|
||||
public CoreOutputComm CoreOutputComm { get; private set; }
|
||||
private IList<MemoryDomain> memoryDomains;
|
||||
public IList<MemoryDomain> MemoryDomains { get { return memoryDomains; } }
|
||||
public MemoryDomain MainMemory { get { return memoryDomains[0]; } }
|
||||
public int Frame { get { return _frame; } set { _frame = value; } }
|
||||
public int LagCount { get { return _lagcount; } set { _lagcount = value; } }
|
||||
public bool IsLagFrame { get { return _islag; } }
|
||||
// internal variables
|
||||
private bool _islag = true;
|
||||
private int _lagcount = 0;
|
||||
private int _frame = 0;
|
||||
public byte[] ReadSaveRam() { return null; }
|
||||
public void StoreSaveRam(byte[] data) { }
|
||||
|
||||
// bizhawk I/O
|
||||
public CoreInputComm CoreInputComm { get; set; }
|
||||
public CoreOutputComm CoreOutputComm { get; private set; }
|
||||
|
||||
// game/rom specific
|
||||
public GameInfo game;
|
||||
public string SystemId { get { return "C64"; } }
|
||||
|
||||
// memory domains
|
||||
public MemoryDomain MainMemory { get { return memoryDomains[0]; } }
|
||||
private IList<MemoryDomain> memoryDomains;
|
||||
public IList<MemoryDomain> MemoryDomains { get { return memoryDomains; } }
|
||||
|
||||
// save state/ram
|
||||
public void ClearSaveRam() { }
|
||||
public void LoadStateBinary(BinaryReader br) { }
|
||||
public void LoadStateText(TextReader reader) { }
|
||||
public byte[] ReadSaveRam() { return null; }
|
||||
public bool SaveRamModified { get; set; }
|
||||
public void Dispose() { }
|
||||
public IVideoProvider VideoProvider { get { return vic; } }
|
||||
public ISoundProvider SoundProvider { get { return sid; } }
|
||||
public void SaveStateBinary(BinaryWriter bw) { }
|
||||
public void SaveStateText(TextWriter writer) { }
|
||||
public void StoreSaveRam(byte[] data) { }
|
||||
|
||||
// running state
|
||||
public bool DeterministicEmulation { get { return true; } set { ; } }
|
||||
public int Frame { get { return _frame; } set { _frame = value; } }
|
||||
public bool IsLagFrame { get { return _islag; } }
|
||||
public int LagCount { get { return _lagcount; } set { _lagcount = value; } }
|
||||
public void ResetFrameCounter()
|
||||
{
|
||||
_frame = 0;
|
||||
}
|
||||
|
||||
/*TODO*/
|
||||
public ISyncSoundProvider SyncSoundProvider { get { return syncSid; ; } }
|
||||
public bool StartAsyncSound() { return true; } //TODO
|
||||
// audio/video
|
||||
public void EndAsyncSound() { } //TODO
|
||||
public bool DeterministicEmulation { get; set; } //TODO
|
||||
public void SaveStateText(TextWriter writer) { } //TODO
|
||||
public void LoadStateText(TextReader reader) { } //TODO`
|
||||
public void SaveStateBinary(BinaryWriter bw) { } //TODO
|
||||
public void LoadStateBinary(BinaryReader br) { } //TODO
|
||||
public ISoundProvider SoundProvider { get { return sid; } }
|
||||
public bool StartAsyncSound() { return true; } //TODO
|
||||
public ISyncSoundProvider SyncSoundProvider { get { return syncSid; ; } }
|
||||
public IVideoProvider VideoProvider { get { return vic; } }
|
||||
|
||||
// controller
|
||||
public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } }
|
||||
public IController Controller { get { return input.controller; } set { input.controller = value; } }
|
||||
public static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition
|
||||
|
@ -73,6 +85,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
};
|
||||
|
||||
// framework
|
||||
public void Dispose() { }
|
||||
|
||||
// process frame
|
||||
public void FrameAdvance(bool render, bool rendersound)
|
||||
{
|
||||
_frame++;
|
||||
|
@ -114,6 +130,15 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SetupMemoryDomains()
|
||||
{
|
||||
var domains = new List<MemoryDomain>(1);
|
||||
|
@ -130,15 +155,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
memoryDomains = domains.AsReadOnly();
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
void SyncState(Serializer ser) //TODO
|
||||
{
|
||||
ser.Sync("Lag", ref _lagcount);
|
||||
|
|
|
@ -54,24 +54,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
|
||||
public CiaRegs()
|
||||
{
|
||||
// power on state
|
||||
TLATCH[0] = 0xFFFF;
|
||||
TLATCH[1] = 0xFFFF;
|
||||
T[0] = TLATCH[0];
|
||||
T[1] = TLATCH[1];
|
||||
|
||||
this[0x0B] = 0x01;
|
||||
|
||||
ports = new DataPortBus[2];
|
||||
ports[0] = new DataPortBus();
|
||||
ports[1] = new DataPortBus();
|
||||
connectors = new DataPortConnector[2];
|
||||
connectors[0] = ports[0].Connect();
|
||||
connectors[1] = ports[1].Connect();
|
||||
connectors[0].Data = 0xFF;
|
||||
connectors[1].Data = 0xFF;
|
||||
connectors[0].Direction = 0xFF;
|
||||
connectors[1].Direction = 0xFF;
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public byte this[int addr]
|
||||
|
@ -240,6 +229,25 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
// power on state
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
this[i] = 0x00;
|
||||
|
||||
TLATCH[0] = 0xFFFF;
|
||||
TLATCH[1] = 0xFFFF;
|
||||
T[0] = TLATCH[0];
|
||||
T[1] = TLATCH[1];
|
||||
|
||||
this[0x0B] = 0x01;
|
||||
|
||||
connectors[0].Data = 0xFF;
|
||||
connectors[1].Data = 0xFF;
|
||||
connectors[0].Direction = 0xFF;
|
||||
connectors[1].Direction = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
public class Cia
|
||||
|
@ -247,7 +255,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public int intMask;
|
||||
public bool lastCNT;
|
||||
public byte[] outputBitMask;
|
||||
private CiaRegs regs;
|
||||
private CiaRegs regs = new CiaRegs();
|
||||
public int todCounter;
|
||||
public int todFrequency;
|
||||
public bool[] underflow;
|
||||
|
@ -353,7 +361,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public void HardReset()
|
||||
{
|
||||
outputBitMask = new byte[] { 0x40, 0x80 };
|
||||
regs = new CiaRegs();
|
||||
regs.HardReset();
|
||||
underflow = new bool[2];
|
||||
todCounter = todFrequency;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
result |= controller[joystickMatrix[index, 2]] ? (byte)0x00 : (byte)0x04;
|
||||
result |= controller[joystickMatrix[index, 3]] ? (byte)0x00 : (byte)0x08;
|
||||
result |= controller[joystickMatrix[index, 4]] ? (byte)0x00 : (byte)0x10;
|
||||
if (result != 0xFF)
|
||||
index = index;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -502,6 +502,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public int[] pixelBuffer;
|
||||
public bool[] pixelBufferForeground;
|
||||
public int pixelBufferIndex;
|
||||
public int pixelBufferLength;
|
||||
public int rasterInterruptLine;
|
||||
public int rasterLineLeft;
|
||||
public int rasterOffset;
|
||||
|
@ -510,8 +511,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
public int rasterWidth;
|
||||
public int refreshAddress;
|
||||
public int renderOffset;
|
||||
public int spriteFetchStartCycle;
|
||||
public int spriteFetchIndex;
|
||||
public bool spriteForeground;
|
||||
public SpriteGenerator[] spriteGenerators;
|
||||
public int totalCycles;
|
||||
|
@ -546,19 +545,34 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
rasterTotalLines = 263;
|
||||
rasterLineLeft = 0x19C;
|
||||
cycleLeft = 0;
|
||||
spriteFetchStartCycle = 59;
|
||||
visibleLeft = 0x008;
|
||||
visibleRight = 0x168;
|
||||
visibleTop = 0x023; //0x041;
|
||||
visibleBottom = 0x004; //0x013;
|
||||
visibleTop = 0x023;
|
||||
visibleBottom = 0x004;
|
||||
visibleRenderX = false;
|
||||
visibleRenderY = false;
|
||||
visibleWidth = 352;
|
||||
visibleHeight = 232;
|
||||
renderOffset = 0;
|
||||
pixelBufferLength = 12;
|
||||
PerformCycleFunction = PerformCycleNTSC;
|
||||
break;
|
||||
case Region.PAL:
|
||||
totalCycles = 63;
|
||||
rasterTotalLines = 312;
|
||||
rasterLineLeft = 0x194;
|
||||
cycleLeft = 0;
|
||||
visibleLeft = 0x008;
|
||||
visibleRight = 0x168;
|
||||
visibleTop = 0x023;
|
||||
visibleBottom = 0x10B;
|
||||
visibleRenderX = false;
|
||||
visibleRenderY = false;
|
||||
visibleWidth = 352;
|
||||
visibleHeight = 232;
|
||||
renderOffset = 0;
|
||||
PerformCycleFunction = PerformCyclePAL;
|
||||
pixelBufferLength = 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -652,12 +666,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
// initialize screen buffer
|
||||
characterMemory = new byte[40];
|
||||
colorMemory = new byte[40];
|
||||
pixelBuffer = new int[12];
|
||||
pixelBufferForeground = new bool[12];
|
||||
pixelBuffer = new int[pixelBufferLength];
|
||||
pixelBufferForeground = new bool[pixelBufferLength];
|
||||
pixelBufferIndex = 0;
|
||||
|
||||
// initialize registers
|
||||
spriteFetchIndex = 0;
|
||||
idle = true;
|
||||
refreshAddress = 0x3FFF;
|
||||
regs = new VicIIRegs();
|
||||
|
@ -958,6 +971,220 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
// operations timed to PAL
|
||||
private void PerformCyclePAL()
|
||||
{
|
||||
switch (cycle)
|
||||
{
|
||||
case 0:
|
||||
// rasterline IRQ happens on cycle 1 on rasterline 0
|
||||
if (regs.RASTER > 0 && regs.RASTER == rasterInterruptLine)
|
||||
regs.IRST = true;
|
||||
PerformSpritePointerFetch(3);
|
||||
break;
|
||||
case 1:
|
||||
// rasterline IRQ happens on cycle 1 on rasterline 0
|
||||
if (regs.RASTER == 0 && regs.RASTER == rasterInterruptLine)
|
||||
regs.IRST = true;
|
||||
PerformSpriteDataFetch(3);
|
||||
break;
|
||||
case 2:
|
||||
PerformSpritePointerFetch(4);
|
||||
break;
|
||||
case 3:
|
||||
PerformSpriteDataFetch(4);
|
||||
break;
|
||||
case 4:
|
||||
PerformSpritePointerFetch(5);
|
||||
break;
|
||||
case 5:
|
||||
PerformSpriteDataFetch(5);
|
||||
break;
|
||||
case 6:
|
||||
PerformSpritePointerFetch(6);
|
||||
break;
|
||||
case 7:
|
||||
PerformSpriteDataFetch(6);
|
||||
break;
|
||||
case 8:
|
||||
PerformSpritePointerFetch(7);
|
||||
break;
|
||||
case 9:
|
||||
PerformSpriteDataFetch(7);
|
||||
break;
|
||||
case 10:
|
||||
signal.VicAEC = true;
|
||||
PerformDRAMRefresh();
|
||||
break;
|
||||
case 11:
|
||||
PerformDRAMRefresh();
|
||||
break;
|
||||
case 12:
|
||||
PerformDRAMRefresh();
|
||||
break;
|
||||
case 13:
|
||||
PerformVCReset();
|
||||
PerformDRAMRefresh();
|
||||
break;
|
||||
case 14:
|
||||
PerformDRAMRefresh();
|
||||
break;
|
||||
case 15:
|
||||
spriteGenerators[0].Render();
|
||||
spriteGenerators[1].Render();
|
||||
spriteGenerators[2].Render();
|
||||
spriteGenerators[3].Render();
|
||||
spriteGenerators[4].Render();
|
||||
spriteGenerators[5].Render();
|
||||
spriteGenerators[6].Render();
|
||||
spriteGenerators[7].Render();
|
||||
PerformSpriteMCBASEAdvance();
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 16:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 17:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 18:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 19:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 20:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 21:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 22:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 23:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 24:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 25:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 26:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 27:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 28:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 29:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 30:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 31:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 32:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 33:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 34:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 35:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 36:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 37:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 38:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 39:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 40:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 41:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 42:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 43:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 44:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 45:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 46:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 47:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 48:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 49:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 50:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 51:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 52:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 53:
|
||||
PerformScreenCAccess();
|
||||
break;
|
||||
case 54:
|
||||
PerformScreenCAccess();
|
||||
PerformSpriteYExpansionFlip();
|
||||
PerformSpriteComparison();
|
||||
break;
|
||||
case 55:
|
||||
signal.VicAEC = true;
|
||||
PerformSpriteComparison();
|
||||
break;
|
||||
case 56:
|
||||
break;
|
||||
case 57:
|
||||
PerformSpriteDMAEnable();
|
||||
PerformRCReset();
|
||||
PerformSpritePointerFetch(0);
|
||||
break;
|
||||
case 58:
|
||||
PerformSpriteDataFetch(0);
|
||||
break;
|
||||
case 59:
|
||||
PerformSpritePointerFetch(1);
|
||||
break;
|
||||
case 60:
|
||||
PerformSpriteDataFetch(1);
|
||||
break;
|
||||
case 61:
|
||||
PerformSpritePointerFetch(2);
|
||||
break;
|
||||
case 62:
|
||||
PerformBorderCheck();
|
||||
PerformSpriteDataFetch(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformDRAMRefresh()
|
||||
|
@ -1367,11 +1594,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
|
|||
}
|
||||
}
|
||||
|
||||
// process 12 pixel delay
|
||||
// process pixel delay
|
||||
pixelBuffer[pixelBufferIndex] = inputPixel;
|
||||
pixelBufferForeground[pixelBufferIndex] = dataForeground;
|
||||
pixelBufferIndex++;
|
||||
if (pixelBufferIndex == 12)
|
||||
if (pixelBufferIndex == pixelBufferLength)
|
||||
{
|
||||
pixelBufferIndex = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue