commodore64: full PAL support across all chips, better HardReset behavior

This commit is contained in:
saxxonpike 2012-11-17 03:58:06 +00:00
parent e48f24d266
commit 0a8355ce1a
5 changed files with 342 additions and 66 deletions

View File

@ -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":

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}