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

View File

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

View File

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

View File

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

View File

@ -92,29 +92,20 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
bool p3; bool p3;
bool p4; bool p4;
bool p5; bool p5;
bool p6;
bool p7;
bool p9; bool p9;
bool p10;
bool p11; bool p11;
bool p12;
bool p13; bool p13;
bool p14;
bool p15; bool p15;
bool p16;
bool p17; bool p17;
bool p18;
bool p19; bool p19;
bool p20; bool p20;
bool p21; bool p21;
bool p22; bool p22;
bool p23;
bool p24; bool p24;
bool p25; bool p25;
bool p26; bool p26;
bool p27; bool p27;
bool p28; bool p28;
bool p30;
bool loram; bool loram;
bool hiram; bool hiram;
bool game; bool game;
@ -124,8 +115,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
bool a14; bool a14;
bool a13; bool a13;
bool a12; bool a12;
bool aec;
bool cas;
private PLABank Bank(int addr, bool read) private PLABank Bank(int addr, bool read)
{ {
@ -137,91 +126,93 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
a14 = (addr & 0x04000) != 0; a14 = (addr & 0x04000) != 0;
a13 = (addr & 0x02000) != 0; a13 = (addr & 0x02000) != 0;
a12 = (addr & 0x01000) != 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) if (p0)
return PLABank.BasicROM; return PLABank.BasicROM;
// kernal rom, banked at E000-FFFF
exrom = ReadExRom(); exrom = ReadExRom();
p1 = hiram && a15 && a14 && a13 && !aec && read && game; if (hiram && a15 && a14 && a13 && read)
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)
{ {
switch (addr & 0x0F00) p1 = game;
{ p2 = !exrom && !game;
case 0x000: if (p1 || p2)
case 0x100: return PLABank.KernalROM;
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;
} }
p19 = loram && hiram && a15 && !a14 && !a13 && !aec && read && !exrom; // cartridge low, banked at 8000-9FFF
p20 = a15 && !a14 && !a13 && !aec && exrom && !game; if (a15 && !a14 && !a13)
if (p19 || p20) {
return PLABank.CartridgeLo; p19 = loram && hiram && read && !exrom;
p20 = exrom && !game;
if (p19 || p20)
return PLABank.CartridgeLo;
}
p21 = hiram && a15 && !a14 && a13 && !aec && read && !exrom && !game; // cartridge high, banked either at A000-BFFF or E000-FFFF depending
p22 = a15 && a14 && a13 && !aec && exrom && !game; if (a15 && a13 && !game)
p23 = a13 && a12 && aec && exrom && !game; {
if (p21 || p22 || p23) p21 = hiram && !a14 && read && !exrom;
return PLABank.CartridgeHi; p22 = a14 && exrom;
if (p21 || p22)
return PLABank.CartridgeHi;
}
cas = !true; //active low // ultimax mode ram exclusion
p24 = !a15 && !a14 && a12 && exrom && !game; if (exrom && !game)
p25 = !a15 && !a14 && a13 && exrom && !game; {
p26 = !a15 && a14 && exrom && !game; p24 = !a15 && !a14 && a12;
p27 = a15 && !a14 && a13 && exrom && !game; p25 = !a15 && !a14 && a13;
p28 = a15 && a14 && !a13 && !a12 && exrom && !game; p26 = !a15 && a14;
p30 = cas; p27 = a15 && !a14 && a13;
if (!(p24 || p25 || p26 || p27 || p28 || p30)) p28 = a15 && a14 && !a13 && !a12;
if (!(p24 || p25 || p26 || p27 || p28))
return PLABank.RAM;
}
else
{
return PLABank.RAM; return PLABank.RAM;
}
//p31 = !cas && a15 && a14 && !a13 && a12 && !aec && !read;
//grw = p31;
return PLABank.None; return PLABank.None;
} }
@ -335,8 +326,6 @@ namespace BizHawk.Emulation.Computers.Commodore64.MOS
{ {
switch (Bank(addr, false)) switch (Bank(addr, false))
{ {
case PLABank.BasicROM:
break;
case PLABank.CartridgeHi: case PLABank.CartridgeHi:
WriteCartridgeHi(addr, val); WriteCartridgeHi(addr, val);
WriteMemory(addr, val); WriteMemory(addr, val);

View File

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