Commodore64: Fixed NMI not triggering on the CPU. Significant performance boost from PLA optimization and motherboard glue shortcuts.

This commit is contained in:
saxxonpike 2013-08-17 23:15:31 +00:00
parent 03087a88eb
commit 0b6bce0198
7 changed files with 204 additions and 208 deletions

View File

@ -28,7 +28,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public UserPort userPort;
// state
public int address;
//public int address;
public byte bus;
public bool inputRead;
public bool irq;
@ -62,7 +62,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
cia0.ExecutePhase1();
cia1.ExecutePhase1();
sid.ExecutePhase1();
vic.ExecutePhase1();
cpu.ExecutePhase1();
@ -73,11 +72,15 @@ namespace BizHawk.Emulation.Computers.Commodore64
cpu.ExecutePhase2();
}
public void Flush()
{
sid.Flush();
}
// -----------------------------------------
public void HardReset()
{
address = 0xFFFF;
bus = 0xFF;
inputRead = false;
@ -122,7 +125,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
cpu.ReadNMI = cia1.ReadIRQBuffer;
cpu.ReadPort = Cpu_ReadPort;
cpu.ReadRDY = vic.ReadBABuffer;
cpu.ReadMemory = pla.Read;
cpu.ReadMemory = pla.Read;
cpu.WriteMemory = pla.Write;
pla.PeekBasicRom = basicRom.Peek;

View File

@ -60,14 +60,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
return (userPort.ReadSerial2Buffer() && cia1.ReadSPBuffer());
}
byte Cpu_ReadMemory(int addr)
{
byte result = pla.ReadMemory(addr);
address = addr;
bus = result;
return result;
}
byte Cpu_ReadPort()
{
byte data = 0x1F;
@ -76,13 +68,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
return data;
}
void Cpu_WriteMemory(int addr, byte val)
{
pla.WriteMemory(addr, val);
address = addr;
bus = val;
}
bool Glue_ReadIRQ()
{
return cia0.ReadIRQBuffer() & vic.ReadIRQBuffer() & cartPort.ReadIRQBuffer();
@ -105,10 +90,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
byte Pla_ReadColorRam(int addr)
{
int result;
address = addr;
result = colorRam.Read(addr) | (bus & 0xF0);
return (byte)result;
byte result = bus;
result &= 0xF0;
result |= colorRam.Read(addr);
return result;
}
bool Pla_ReadHiRam()
@ -148,19 +133,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
byte Vic_ReadMemory(int addr)
{
switch (cia1.PortAData & 0x3)
{
case 0:
addr |= 0xC000;
break;
case 1:
addr |= 0x8000;
break;
case 2:
addr |= 0x4000;
break;
}
address = addr;
//p6 = a14 && !a13 && a12 && aec && game;
//p7 = a14 && !a13 && a12 && aec && !exrom && !game;
//(char rom from pla)
// the system sees (cia1.PortAData & 0x3) but we use a shortcut
addr |= (0x3 - (((cia1.PortALatch & cia1.PortADirection) | (~cia1.PortADirection)) & 0x3)) << 14;
if ((addr & 0x7000) == 0x1000)
bus = charRom.Read(addr);
else

View File

@ -115,6 +115,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
//disk.Execute();
board.Execute();
}
board.Flush();
_islag = !board.inputRead;
if (_islag)

View File

@ -16,6 +16,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
//private bool freezeCpu;
private bool pinNMILast;
private LatchedPort port;
private bool thisNMI;
public Func<int, byte> PeekMemory;
public Action<int, byte> PokeMemory;
@ -72,7 +73,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
public void ExecutePhase1()
{
}
cpu.IRQ = !ReadIRQ();
}
public void ExecutePhase2()
{
@ -80,16 +82,15 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
// the 6502 core expects active high
// so we reverse the polarity here
bool thisNMI = ReadNMI();
thisNMI = ReadNMI();
if (!thisNMI && pinNMILast)
cpu.NMI = true;
else
cpu.NMI = false;
pinNMILast = thisNMI;
cpu.IRQ = !ReadIRQ();
if (ReadAEC())
{
cpu.ExecuteOne();
pinNMILast = thisNMI;
}
}
// ------------------------------------

View File

@ -92,29 +92,20 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
bool p3;
bool p4;
bool p5;
bool p6;
bool p7;
bool p9;
bool p10;
bool p11;
bool p12;
bool p13;
bool p14;
bool p15;
bool p16;
bool p17;
bool p18;
bool p19;
bool p20;
bool p21;
bool p22;
bool p23;
bool p24;
bool p25;
bool p26;
bool p27;
bool p28;
bool p30;
bool loram;
bool hiram;
bool game;
@ -124,8 +115,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
bool a14;
bool a13;
bool a12;
bool aec;
bool cas;
private PLABank Bank(int addr, bool read)
{
@ -137,91 +126,93 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
a14 = (addr & 0x04000) != 0;
a13 = (addr & 0x02000) != 0;
a12 = (addr & 0x01000) != 0;
aec = !ReadAEC(); //active low
p0 = loram && hiram && a15 && !a14 && a13 && !aec && read && game;
// io/character access
if (a15 && a14 && !a13 && a12)
{
// character rom, banked in at D000-DFFF
charen = ReadCharen();
if (read && !charen)
{
p3 = hiram && game;
p4 = loram && game;
p5 = hiram && !exrom && !game;
if (p3 || p4 || p5)
return PLABank.CharROM;
}
// io block, banked in at D000-DFFF
p9 = hiram && charen && game;
p11 = loram && charen && game;
p13 = hiram && charen && !exrom && !game;
p15 = loram && charen && !exrom && !game;
p17 = exrom && !game;
if (p9 || p11 || p13 || p15 || p17)
{
if (addr < 0xD400)
return PLABank.Vic;
if (addr < 0xD800)
return PLABank.Sid;
if (addr < 0xDC00)
return PLABank.ColorRam;
if (addr < 0xDD00)
return PLABank.Cia0;
if (addr < 0xDE00)
return PLABank.Cia1;
if (addr < 0xDF00)
return PLABank.Expansion0;
return PLABank.Expansion1;
}
}
// basic rom, banked at A000-BFFF
p0 = loram && hiram && a15 && !a14 && a13 && read && game;
if (p0)
return PLABank.BasicROM;
// kernal rom, banked at E000-FFFF
exrom = ReadExRom();
p1 = hiram && a15 && a14 && a13 && !aec && read && game;
p2 = hiram && a15 && a14 && a13 && !aec && read && !exrom && !game;
if (p1 || p2)
return PLABank.KernalROM;
charen = ReadCharen();
p3 = hiram && !charen && a15 && a14 && !a13 && a12 && !aec && read && game;
p4 = loram && !charen && a15 && a14 && !a13 && a12 && !aec && read && game;
p5 = hiram && !charen && a15 && a14 && !a13 && a12 && !aec && read && !exrom && !game;
p6 = a14 && !a13 && a12 && aec && game;
p7 = a14 && !a13 && a12 && aec && !exrom && !game;
if (p3 || p4 || p5 || p6 || p7)
return PLABank.CharROM;
p9 = hiram && charen && a15 && a14 && !a13 && a12 && !aec && read && game;
p10 = hiram && charen && a15 && a14 && !a13 && a12 && !aec && !read && game;
p11 = loram && charen && a15 && a14 && !a13 && a12 && !aec && read && game;
p12 = loram && charen && a15 && a14 && !a13 && a12 && !aec && !read && game;
p13 = hiram && charen && a15 && a14 && !a13 && a12 && !aec && read && !exrom && !game;
p14 = hiram && charen && a15 && a14 && !a13 && a12 && !aec && !read && !exrom && !game;
p15 = loram && charen && a15 && a14 && !a13 && a12 && !aec && read && !exrom && !game;
p16 = loram && charen && a15 && a14 && !a13 && a12 && !aec && !read && !exrom && !game;
p17 = a15 && a14 && !a13 && a12 && !aec && read && exrom && !game;
p18 = a15 && a14 && !a13 && a12 && !aec && !read && exrom && !game;
if (p9 || p10 || p11 || p12 || p13 || p14 || p15 || p16 || p17 || p18)
if (hiram && a15 && a14 && a13 && read)
{
switch (addr & 0x0F00)
{
case 0x000:
case 0x100:
case 0x200:
case 0x300:
return PLABank.Vic;
case 0x400:
case 0x500:
case 0x600:
case 0x700:
return PLABank.Sid;
case 0x800:
case 0x900:
case 0xA00:
case 0xB00:
return PLABank.ColorRam;
case 0xC00:
return PLABank.Cia0;
case 0xD00:
return PLABank.Cia1;
case 0xE00:
return PLABank.Expansion0;
case 0xF00:
return PLABank.Expansion1;
}
return PLABank.IO;
p1 = game;
p2 = !exrom && !game;
if (p1 || p2)
return PLABank.KernalROM;
}
p19 = loram && hiram && a15 && !a14 && !a13 && !aec && read && !exrom;
p20 = a15 && !a14 && !a13 && !aec && exrom && !game;
if (p19 || p20)
return PLABank.CartridgeLo;
// cartridge low, banked at 8000-9FFF
if (a15 && !a14 && !a13)
{
p19 = loram && hiram && read && !exrom;
p20 = exrom && !game;
if (p19 || p20)
return PLABank.CartridgeLo;
}
p21 = hiram && a15 && !a14 && a13 && !aec && read && !exrom && !game;
p22 = a15 && a14 && a13 && !aec && exrom && !game;
p23 = a13 && a12 && aec && exrom && !game;
if (p21 || p22 || p23)
return PLABank.CartridgeHi;
// cartridge high, banked either at A000-BFFF or E000-FFFF depending
if (a15 && a13 && !game)
{
p21 = hiram && !a14 && read && !exrom;
p22 = a14 && exrom;
if (p21 || p22)
return PLABank.CartridgeHi;
}
cas = !true; //active low
p24 = !a15 && !a14 && a12 && exrom && !game;
p25 = !a15 && !a14 && a13 && exrom && !game;
p26 = !a15 && a14 && exrom && !game;
p27 = a15 && !a14 && a13 && exrom && !game;
p28 = a15 && a14 && !a13 && !a12 && exrom && !game;
p30 = cas;
if (!(p24 || p25 || p26 || p27 || p28 || p30))
// ultimax mode ram exclusion
if (exrom && !game)
{
p24 = !a15 && !a14 && a12;
p25 = !a15 && !a14 && a13;
p26 = !a15 && a14;
p27 = a15 && !a14 && a13;
p28 = a15 && a14 && !a13 && !a12;
if (!(p24 || p25 || p26 || p27 || p28))
return PLABank.RAM;
}
else
{
return PLABank.RAM;
//p31 = !cas && a15 && a14 && !a13 && a12 && !aec && !read;
//grw = p31;
}
return PLABank.None;
}
@ -335,8 +326,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
switch (Bank(addr, false))
{
case PLABank.BasicROM:
break;
case PLABank.CartridgeHi:
WriteCartridgeHi(addr, val);
WriteMemory(addr, val);

View File

@ -55,11 +55,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
HardReset();
}
public void ExecutePhase1()
{
// do nothing
}
public void ExecutePhase2()
{
@ -266,11 +261,15 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private class Voice
{
private int accBits;
private int accNext;
private int accumulator;
private bool controlTestPrev;
private int controlWavePrev;
private int delay;
private int floatOutputTTL;
private int frequency;
private bool msbRising;
private bool msbRising;
private int noise;
private int noNoise;
private int noNoiseOrNoise;
@ -286,6 +285,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private bool test;
private int[] wave;
private int waveform;
private int waveformIndex;
private int[][] waveTable;
public Voice(int[][] newWaveTable)
@ -315,11 +315,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
ResetShiftReg();
}
public void ExecutePhase1()
{
// do nothing
}
public void ExecutePhase2()
{
@ -334,8 +329,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
}
else
{
int accNext = (accumulator + frequency) & 0xFFFFFF;
int accBits = ~accumulator & accNext;
accNext = (accumulator + frequency) & 0xFFFFFF;
accBits = ~accumulator & accNext;
accumulator = accNext;
msbRising = ((accBits & 0x800000) != 0);
@ -353,8 +348,9 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
{
int bit0 = ((shiftRegister >> 22) ^ (shiftRegister >> 17)) & 0x1;
shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF;
shiftRegister = ((shiftRegister << 1) |
(((shiftRegister >> 22) ^ (shiftRegister >> 17)) & 0x1)
) & 0x7FFFFF;
SetNoise();
}
}
@ -410,8 +406,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
set
{
int wavePrev = waveform;
bool testPrev = test;
controlWavePrev = waveform;
controlTestPrev = test;
sync = ((value & 0x02) != 0);
ringMod = ((value & 0x04) != 0);
@ -423,20 +419,21 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
noNoiseOrNoise = noNoise | noise;
noPulse = ((waveform & 0x4) != 0) ? 0x000 : 0xFFF;
if (!testPrev && test)
if (!controlTestPrev && test)
{
accumulator = 0;
delay = 0;
shiftRegisterReset = 0x8000;
}
else if (testPrev && !test)
else if (controlTestPrev && !test)
{
int bit0 = (~shiftRegister >> 17) & 0x1;
shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF;
shiftRegister = ((shiftRegister << 1) |
((~shiftRegister >> 17) & 0x1)
) & 0x7FFFFF;
SetNoise();
}
if (waveform == 0 && wavePrev != 0)
if (waveform == 0 && controlWavePrev != 0)
floatOutputTTL = 0x28000;
}
}
@ -493,8 +490,8 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
if (waveform != 0)
{
int index = (accumulator ^ (ringModSource.accumulator & ringMsbMask)) >> 12;
output = wave[index] & (noPulse | pulse) & noNoiseOrNoise;
waveformIndex = (accumulator ^ (ringModSource.accumulator & ringMsbMask)) >> 12;
output = wave[waveformIndex] & (noPulse | pulse) & noNoiseOrNoise;
if (waveform > 8)
WriteShiftReg();
}
@ -620,6 +617,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private static int[] syncNextTable = new int[] { 1, 2, 0 };
private static int[] syncPrevTable = new int[] { 2, 0, 1 };
private int cachedCycles;
private bool disableVoice3;
private int[] envelopeOutput;
private Envelope[] envelopes;
@ -629,10 +627,12 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
private bool filterSelectBandPass;
private bool filterSelectLoPass;
private bool filterSelectHiPass;
private int potCounter;
private int mixer;
private int potCounter;
private int potX;
private int potY;
private int[] voiceOutput;
private short sample;
private int[] voiceOutput;
private Voice[] voices;
private int volume;
private int[][] waveformTable;
@ -694,66 +694,55 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
// ------------------------------------
public void ExecutePhase1()
public void ExecutePhase2()
{
// do nothing
}
cachedCycles++;
public void ExecutePhase2()
{
{
// potentiometer values refresh every 512 cycles
if (potCounter == 0)
{
potCounter = 512;
potX = ReadPotX(); //todo: implement paddles
potY = ReadPotY();
}
// potentiometer values refresh every 512 cycles
if (potCounter == 0)
{
potCounter = 512;
potX = ReadPotX();
potY = ReadPotY();
Flush(); //this is here unrelated to the pots, just to keep the buffer somewhat loaded
}
potCounter--;
}
// process voices and envelopes
voices[0].ExecutePhase2();
voices[1].ExecutePhase2();
voices[2].ExecutePhase2();
envelopes[0].ExecutePhase2();
envelopes[1].ExecutePhase2();
envelopes[2].ExecutePhase2();
public void Flush()
{
while (cachedCycles > 0)
{
// process voices and envelopes
voices[0].ExecutePhase2();
voices[1].ExecutePhase2();
voices[2].ExecutePhase2();
envelopes[0].ExecutePhase2();
envelopes[1].ExecutePhase2();
envelopes[2].ExecutePhase2();
// process sync
for (int i = 0; i < 3; i++)
voices[i].Synchronize(voices[syncNextTable[i]], voices[syncPrevTable[i]]);
// process sync
for (int i = 0; i < 3; i++)
voices[i].Synchronize(voices[syncNextTable[i]], voices[syncPrevTable[i]]);
// get output
voiceOutput[0] = voices[0].Output(voices[2]);
voiceOutput[1] = voices[1].Output(voices[0]);
voiceOutput[2] = voices[2].Output(voices[1]);
envelopeOutput[0] = envelopes[0].Level;
envelopeOutput[1] = envelopes[1].Level;
envelopeOutput[2] = envelopes[2].Level;
// get output
voiceOutput[0] = voices[0].Output(voices[2]);
voiceOutput[1] = voices[1].Output(voices[0]);
voiceOutput[2] = voices[2].Output(voices[1]);
envelopeOutput[0] = envelopes[0].Level;
envelopeOutput[1] = envelopes[1].Level;
envelopeOutput[2] = envelopes[2].Level;
// process output
//if (bufferCounter == 0)
//{
int mixer;
short sample;
//bufferCounter = bufferFrequency;
mixer = ((voiceOutput[0] * envelopeOutput[0]) >> 7);
mixer += ((voiceOutput[1] * envelopeOutput[1]) >> 7);
mixer += ((voiceOutput[2] * envelopeOutput[2]) >> 7);
mixer = (mixer * volume) >> 4;
// mix each channel (20 bits)
mixer = ((voiceOutput[0] * envelopeOutput[0]) >> 7);
mixer += ((voiceOutput[1] * envelopeOutput[1]) >> 7);
mixer += ((voiceOutput[2] * envelopeOutput[2]) >> 7);
mixer = (mixer * volume) >> 4;
sample = (short)mixer;
//buffer[bufferIndex++] = sample;
//buffer[bufferIndex++] = sample;
resampler.EnqueueSample(sample, sample);
//if (bufferIndex == bufferLength)
// bufferIndex = 0;
//}
//bufferCounter--;
}
}
sample = (short)mixer;
resampler.EnqueueSample(sample, sample);
cachedCycles--;
}
}
// ------------------------------------
@ -777,6 +766,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
case 0x1A:
case 0x1B:
case 0x1C:
Flush();
result = ReadRegister(addr);
break;
}
@ -907,6 +897,7 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
// can't write to these
break;
default:
Flush();
WriteRegister(addr, val);
break;
}

View File

@ -47,6 +47,22 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
}
}
public byte PortADirection
{
get
{
return portA.Direction;
}
}
public byte PortALatch
{
get
{
return portA.Latch;
}
}
public byte PortBData
{
get
@ -55,6 +71,22 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
}
}
public byte PortBDirection
{
get
{
return portB.Direction;
}
}
public byte PortBLatch
{
get
{
return portB.Latch;
}
}
public bool ReadIRQBuffer() { return pinIRQ; }
protected void SyncInternal(Serializer ser)