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() public void HardReset()
{
mem.HardReset();
cia0.HardReset();
cia1.HardReset();
vic.HardReset();
sid.HardReset();
if (diskDriveAttached)
diskDrive.HardReset();
}
private void Init(Region initRegion)
{ {
// initalize cpu // initalize cpu
cpu = new MOS6502X(); cpu = new MOS6502X();
@ -63,24 +74,36 @@ namespace BizHawk.Emulation.Computers.Commodore64
cpu.DummyReadMemory = PeekMemory; cpu.DummyReadMemory = PeekMemory;
// initialize cia timers // initialize cia timers
cia0 = new Cia(Region.NTSC); cia0 = new Cia(initRegion);
cia1 = new Cia(Region.NTSC); cia1 = new Cia(initRegion);
// initialize vic // initialize vic
signal = new ChipSignals(); 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.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 // 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); syncSid = new SidSyncSoundProvider(sid);
//sidDCFilter = new Emulation.Sound.Utilities.DCFilter(sid, 2205); //sidDCFilter = new Emulation.Sound.Utilities.DCFilter(sid, 2205);
// initialize memory (this must be done AFTER all other chips are initialized) // initialize memory (this must be done AFTER all other chips are initialized)
string romPath = CoreInputComm.C64_FirmwaresPath; string romPath = CoreInputComm.C64_FirmwaresPath;
if (romPath == null)
{
romPath = @".\C64\Firmwares";
}
mem = new Memory(romPath, vic, sid, cia0, cia1); mem = new Memory(romPath, vic, sid, cia0, cia1);
vic.mem = mem; vic.mem = mem;
@ -89,7 +112,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
cpu.BCD_Enabled = true; cpu.BCD_Enabled = true;
// initailize input // 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(0, input.WritePortA);
cia0.AttachWriteHook(1, input.WritePortB); cia0.AttachWriteHook(1, input.WritePortB);
@ -97,11 +120,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
switch (extension.ToUpper()) switch (extension.ToUpper())
{ {
case @".G64": 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)); diskDrive.Insert(G64.Read(inputFile));
break; break;
case @".D64": 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)); diskDrive.Insert(D64.Read(inputFile));
break; break;
case @".PRG": case @".PRG":

View File

@ -16,43 +16,55 @@ namespace BizHawk.Emulation.Computers.Commodore64
SetupMemoryDomains(); SetupMemoryDomains();
CoreOutputComm = new CoreOutputComm(); CoreOutputComm = new CoreOutputComm();
CoreInputComm = new CoreInputComm(); CoreInputComm = new CoreInputComm();
Init(Region.NTSC);
} }
public string SystemId { get { return "C64"; } } // internal variables
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; } }
private bool _islag = true; private bool _islag = true;
private int _lagcount = 0; private int _lagcount = 0;
private int _frame = 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 ClearSaveRam() { }
public void LoadStateBinary(BinaryReader br) { }
public void LoadStateText(TextReader reader) { }
public byte[] ReadSaveRam() { return null; }
public bool SaveRamModified { get; set; } public bool SaveRamModified { get; set; }
public void Dispose() { } public void SaveStateBinary(BinaryWriter bw) { }
public IVideoProvider VideoProvider { get { return vic; } } public void SaveStateText(TextWriter writer) { }
public ISoundProvider SoundProvider { get { return sid; } } 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() public void ResetFrameCounter()
{ {
_frame = 0; _frame = 0;
} }
/*TODO*/ // audio/video
public ISyncSoundProvider SyncSoundProvider { get { return syncSid; ; } }
public bool StartAsyncSound() { return true; } //TODO
public void EndAsyncSound() { } //TODO public void EndAsyncSound() { } //TODO
public bool DeterministicEmulation { get; set; } //TODO public ISoundProvider SoundProvider { get { return sid; } }
public void SaveStateText(TextWriter writer) { } //TODO public bool StartAsyncSound() { return true; } //TODO
public void LoadStateText(TextReader reader) { } //TODO` public ISyncSoundProvider SyncSoundProvider { get { return syncSid; ; } }
public void SaveStateBinary(BinaryWriter bw) { } //TODO public IVideoProvider VideoProvider { get { return vic; } }
public void LoadStateBinary(BinaryReader br) { } //TODO
// controller
public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } } public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } }
public IController Controller { get { return input.controller; } set { input.controller = value; } } public IController Controller { get { return input.controller; } set { input.controller = value; } }
public static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition 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) public void FrameAdvance(bool render, bool rendersound)
{ {
_frame++; _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() private void SetupMemoryDomains()
{ {
var domains = new List<MemoryDomain>(1); var domains = new List<MemoryDomain>(1);
@ -130,15 +155,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
memoryDomains = domains.AsReadOnly(); 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 void SyncState(Serializer ser) //TODO
{ {
ser.Sync("Lag", ref _lagcount); ser.Sync("Lag", ref _lagcount);

View File

@ -54,24 +54,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
public CiaRegs() 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 = new DataPortBus[2];
ports[0] = new DataPortBus(); ports[0] = new DataPortBus();
ports[1] = new DataPortBus(); ports[1] = new DataPortBus();
connectors = new DataPortConnector[2]; connectors = new DataPortConnector[2];
connectors[0] = ports[0].Connect(); connectors[0] = ports[0].Connect();
connectors[1] = ports[1].Connect(); connectors[1] = ports[1].Connect();
connectors[0].Data = 0xFF; HardReset();
connectors[1].Data = 0xFF;
connectors[0].Direction = 0xFF;
connectors[1].Direction = 0xFF;
} }
public byte this[int addr] 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 public class Cia
@ -247,7 +255,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int intMask; public int intMask;
public bool lastCNT; public bool lastCNT;
public byte[] outputBitMask; public byte[] outputBitMask;
private CiaRegs regs; private CiaRegs regs = new CiaRegs();
public int todCounter; public int todCounter;
public int todFrequency; public int todFrequency;
public bool[] underflow; public bool[] underflow;
@ -353,7 +361,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void HardReset() public void HardReset()
{ {
outputBitMask = new byte[] { 0x40, 0x80 }; outputBitMask = new byte[] { 0x40, 0x80 };
regs = new CiaRegs(); regs.HardReset();
underflow = new bool[2]; underflow = new bool[2];
todCounter = todFrequency; 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, 2]] ? (byte)0x00 : (byte)0x04;
result |= controller[joystickMatrix[index, 3]] ? (byte)0x00 : (byte)0x08; result |= controller[joystickMatrix[index, 3]] ? (byte)0x00 : (byte)0x08;
result |= controller[joystickMatrix[index, 4]] ? (byte)0x00 : (byte)0x10; result |= controller[joystickMatrix[index, 4]] ? (byte)0x00 : (byte)0x10;
if (result != 0xFF)
index = index;
return result; return result;
} }

View File

@ -502,6 +502,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int[] pixelBuffer; public int[] pixelBuffer;
public bool[] pixelBufferForeground; public bool[] pixelBufferForeground;
public int pixelBufferIndex; public int pixelBufferIndex;
public int pixelBufferLength;
public int rasterInterruptLine; public int rasterInterruptLine;
public int rasterLineLeft; public int rasterLineLeft;
public int rasterOffset; public int rasterOffset;
@ -510,8 +511,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int rasterWidth; public int rasterWidth;
public int refreshAddress; public int refreshAddress;
public int renderOffset; public int renderOffset;
public int spriteFetchStartCycle;
public int spriteFetchIndex;
public bool spriteForeground; public bool spriteForeground;
public SpriteGenerator[] spriteGenerators; public SpriteGenerator[] spriteGenerators;
public int totalCycles; public int totalCycles;
@ -546,19 +545,34 @@ namespace BizHawk.Emulation.Computers.Commodore64
rasterTotalLines = 263; rasterTotalLines = 263;
rasterLineLeft = 0x19C; rasterLineLeft = 0x19C;
cycleLeft = 0; cycleLeft = 0;
spriteFetchStartCycle = 59;
visibleLeft = 0x008; visibleLeft = 0x008;
visibleRight = 0x168; visibleRight = 0x168;
visibleTop = 0x023; //0x041; visibleTop = 0x023;
visibleBottom = 0x004; //0x013; visibleBottom = 0x004;
visibleRenderX = false; visibleRenderX = false;
visibleRenderY = false; visibleRenderY = false;
visibleWidth = 352; visibleWidth = 352;
visibleHeight = 232; visibleHeight = 232;
renderOffset = 0; renderOffset = 0;
pixelBufferLength = 12;
PerformCycleFunction = PerformCycleNTSC; PerformCycleFunction = PerformCycleNTSC;
break; break;
case Region.PAL: 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; break;
default: default:
break; break;
@ -652,12 +666,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
// initialize screen buffer // initialize screen buffer
characterMemory = new byte[40]; characterMemory = new byte[40];
colorMemory = new byte[40]; colorMemory = new byte[40];
pixelBuffer = new int[12]; pixelBuffer = new int[pixelBufferLength];
pixelBufferForeground = new bool[12]; pixelBufferForeground = new bool[pixelBufferLength];
pixelBufferIndex = 0; pixelBufferIndex = 0;
// initialize registers // initialize registers
spriteFetchIndex = 0;
idle = true; idle = true;
refreshAddress = 0x3FFF; refreshAddress = 0x3FFF;
regs = new VicIIRegs(); regs = new VicIIRegs();
@ -958,6 +971,220 @@ namespace BizHawk.Emulation.Computers.Commodore64
// operations timed to PAL // operations timed to PAL
private void PerformCyclePAL() 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() private void PerformDRAMRefresh()
@ -1367,11 +1594,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
} }
} }
// process 12 pixel delay // process pixel delay
pixelBuffer[pixelBufferIndex] = inputPixel; pixelBuffer[pixelBufferIndex] = inputPixel;
pixelBufferForeground[pixelBufferIndex] = dataForeground; pixelBufferForeground[pixelBufferIndex] = dataForeground;
pixelBufferIndex++; pixelBufferIndex++;
if (pixelBufferIndex == 12) if (pixelBufferIndex == pixelBufferLength)
{ {
pixelBufferIndex = 0; pixelBufferIndex = 0;
} }