Fixed misc. bugs preventing certain games from working, added pause mode.

There was one bug that went undetected in the v65C02 core (in STX ZP,Y)
and another in the 80STORE handling (80STORE doesn't affect reading).
Also added a pause mode (bound to the Pause key), for those times when
you need to walk away from the emulation for a bit.
This commit is contained in:
Shamus Hammons 2013-09-23 11:05:10 -05:00
parent 3107275cfe
commit c0001155bc
9 changed files with 155 additions and 116 deletions

View File

@ -25,12 +25,12 @@ autoSaveState = 1
# Yes
#floppyImage1 = ./disks/bt2_boot.dsk
# Yes (but segfaults in the timer routine in the title screen--NB: Not anymore...)
#floppyImage1 = ./disks/bt3_boot_fixed.dsk
#floppyImage2 = ./disks/bt3_character_fixed.dsk
floppyImage1 = ./disks/bt3_boot_fixed.dsk
floppyImage2 = ./disks/bt3_character_fixed.dsk
# Yes
#floppyImage1 = ./disks/Sabotage.dsk
# ??? (//c or //e w/128K required) (dumps to monitor)
floppyImage1 = ./disks/airheart.dsk
#floppyImage1 = ./disks/airheart.dsk
# Yes
#floppyImage1 = ./disks/drol.dsk
# Yes

View File

@ -98,6 +98,7 @@ static bool writeRAM = false;
static bool running = true; // Machine running state flag...
static uint32_t startTicks;
static bool pauseMode = false;
static GUI * gui = NULL;
@ -372,6 +373,8 @@ WriteLog("80STORE (read)\n");
#ifdef SOFT_SWITCH_DEBUGGING
WriteLog("VBL (read)\n");
#endif
// NB: The doco suggests that this signal goes LOW when in the VBI.
// Which means that we need to control this by counting lines somewhere.
return (vbl ? 0x80 : 0x00);
}
else if (addr == 0xC01A)
@ -782,6 +785,8 @@ if (showpath)
}
else
{
// 80STORE only works for WRITING, not READING!
#if 0
// Check for 80STORE mode (STORE80 takes precedence over RAMRD/WRT)...
if ((((addr >= 0x0400) && (addr <= 0x07FF)) || ((addr >= 0x2000) && (addr <= 0x3FFF))) && store80Mode)
{
@ -792,6 +797,7 @@ if (showpath)
return b;
}
#endif
// Finally, check for auxillary/altzp write switches
if (addr < 0x0200)
@ -1304,6 +1310,12 @@ if (addr >= 0xD000 && addr <= 0xD00F)
if (addr < 0x0200)
// if (addr < 0x0200 || addr >= 0xD000)
{
#if 0
if (addr == 0x38)
WriteLog("Write $38: $%02X\n", b);
else if (addr == 0x39)
WriteLog("Write $39: $%02X\n", b);
#endif
if (altzp)
ram2[addr] = b;
else
@ -1363,7 +1375,6 @@ int main(int /*argc*/, char * /*argv*/[])
srand(time(NULL)); // Initialize RNG
// Zero out memory
//Need to bankify this stuff for the IIe emulation...
memset(ram, 0, 0x10000);
memset(rom, 0, 0x10000);
memset(ram2, 0, 0x10000);
@ -1671,6 +1682,22 @@ static void FrameCallback(void)
if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_ALT))
running = false;
if (event.key.keysym.sym == SDLK_PAUSE)
{
pauseMode = !pauseMode;
if (pauseMode)
{
SoundPause();
SpawnMessage("*** PAUSED ***");
}
else
{
SoundResume();
SpawnMessage("*** RESUME ***");
}
}
// Paddle buttons 0 & 1
if (event.key.keysym.sym == SDLK_INSERT)
openAppleDown = true;
@ -1801,7 +1828,8 @@ if (counter == 60)
//let's wait, then signal...
//works longer, but then still falls behind...
#ifdef THREADED_65C02
SDL_CondSignal(cpuCond);//OK, let the CPU go another frame...
if (!pauseMode)
SDL_CondSignal(cpuCond);//OK, let the CPU go another frame...
#endif
}

View File

@ -416,7 +416,8 @@ static void DrawString2(uint32_t x, uint32_t y, uint32_t color)
uint32_t bBlue = (eBlue * invTrans + nBlue * trans) / 255;
//THIS IS NOT ENDIAN SAFE
*(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
//NB: Setting the alpha channel here does nothing.
*(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = 0x7F000000 | (bBlue << 16) | (bGreen << 8) | bRed;
}
}
}

View File

@ -6,13 +6,11 @@
//
#include "dis65c02.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include "v65c02.h"
#include "log.h"
using namespace std;
// External shit
@ -36,86 +34,83 @@ static uint8_t op_mat[256] = {
1, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 0, 3, 3, 2, 14, 10, 14, 0, 0, 9, 9, 13,
1, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 0, 3, 3, 2, 14, 10, 14, 0, 0, 9, 9, 13 };
13, 7, 5, 0, 0, 3, 3, 2, 14, 10, 14, 0, 0, 9, 9, 13
};
static uint8_t mnemonics[256][5] = {
"BRK ","ORA ","??? ","??? ","TSB ","ORA ","ASL ","RMB0",
"PHP ","ORA ","ASL ","??? ","TSB ","ORA ","ASL ","BBR0",
"BPL ","ORA ","ORA ","??? ","TRB ","ORA ","ASL ","RMB1",
"CLC ","ORA ","INC ","??? ","TRB ","ORA ","ASL ","BBR1",
"JSR ","AND ","??? ","??? ","BIT ","AND ","ROL ","RMB2",
"PLP ","AND ","ROL ","??? ","BIT ","AND ","ROL ","BBR2",
"BMI ","AND ","AND ","??? ","BIT ","AND ","ROL ","RMB3",
"SEC ","AND ","DEC ","??? ","BIT ","AND ","ROL ","BBR3",
"RTI ","EOR ","??? ","??? ","??? ","EOR ","LSR ","RMB4",
"PHA ","EOR ","LSR ","??? ","JMP ","EOR ","LSR ","BBR4",
"BVC ","EOR ","EOR ","??? ","??? ","EOR ","LSR ","RMB5",
"CLI ","EOR ","PHY ","??? ","??? ","EOR ","LSR ","BBR5",
"RTS ","ADC ","??? ","??? ","STZ ","ADC ","ROR ","RMB6",
"PLA ","ADC ","ROR ","??? ","JMP ","ADC ","ROR ","BBR6",
"BVS ","ADC ","ADC ","??? ","STZ ","ADC ","ROR ","RMB7",
"SEI ","ADC ","PLY ","??? ","JMP ","ADC ","ROR ","BBR7",
"BRA ","STA ","??? ","??? ","STY ","STA ","STX ","SMB0",
"DEY ","BIT ","TXA ","??? ","STY ","STA ","STX ","BBS0",
"BCC ","STA ","STA ","??? ","STY ","STA ","STX ","SMB1",
"TYA ","STA ","TXS ","??? ","STZ ","STA ","STZ ","BBS1",
"LDY ","LDA ","LDX ","??? ","LDY ","LDA ","LDX ","SMB2",
"TAY ","LDA ","TAX ","??? ","LDY ","LDA ","LDX ","BBS2",
"BCS ","LDA ","LDA ","??? ","LDY ","LDA ","LDX ","SMB3",
"CLV ","LDA ","TSX ","??? ","LDY ","LDA ","LDX ","BBS3",
"CPY ","CMP ","??? ","??? ","CPY ","CMP ","DEC ","SMB4",
"INY ","CMP ","DEX ","??? ","CPY ","CMP ","DEC ","BBS4",
"BNE ","CMP ","CMP ","??? ","??? ","CMP ","DEC ","SMB5",
"CLD ","CMP ","PHX ","??? ","??? ","CMP ","DEC ","BBS5",
"CPX ","SBC ","??? ","??? ","CPX ","SBC ","INC ","SMB6",
"INX ","SBC ","NOP ","??? ","CPX ","SBC ","INC ","BBS6",
"BEQ ","SBC ","SBC ","??? ","??? ","SBC ","INC ","SMB7",
"SED ","SBC ","PLX ","??? ","??? ","SBC ","INC ","BBS7"
};
static uint8_t mnemonics[256][6] = {
"BRK ","ORA ","??? ","??? ","TSB ","ORA ","ASL ","RMB0 ",
"PHP ","ORA ","ASL ","??? ","TSB ","ORA ","ASL ","BBR0 ",
"BPL ","ORA ","ORA ","??? ","TRB ","ORA ","ASL ","RMB1 ",
"CLC ","ORA ","INC ","??? ","TRB ","ORA ","ASL ","BBR1 ",
"JSR ","AND ","??? ","??? ","BIT ","AND ","ROL ","RMB2 ",
"PLP ","AND ","ROL ","??? ","BIT ","AND ","ROL ","BBR2 ",
"BMI ","AND ","AND ","??? ","BIT ","AND ","ROL ","RMB3 ",
"SEC ","AND ","DEC ","??? ","BIT ","AND ","ROL ","BBR3 ",
"RTI ","EOR ","??? ","??? ","??? ","EOR ","LSR ","RMB4 ",
"PHA ","EOR ","LSR ","??? ","JMP ","EOR ","LSR ","BBR4 ",
"BVC ","EOR ","EOR ","??? ","??? ","EOR ","LSR ","RMB5 ",
"CLI ","EOR ","PHY ","??? ","??? ","EOR ","LSR ","BBR5 ",
"RTS ","ADC ","??? ","??? ","STZ ","ADC ","ROR ","RMB6 ",
"PLA ","ADC ","ROR ","??? ","JMP ","ADC ","ROR ","BBR6 ",
"BVS ","ADC ","ADC ","??? ","STZ ","ADC ","ROR ","RMB7 ",
"SEI ","ADC ","PLY ","??? ","JMP ","ADC ","ROR ","BBR7 ",
"BRA ","STA ","??? ","??? ","STY ","STA ","STX ","SMB0 ",
"DEY ","BIT ","TXA ","??? ","STY ","STA ","STX ","BBS0 ",
"BCC ","STA ","STA ","??? ","STY ","STA ","STX ","SMB1 ",
"TYA ","STA ","TXS ","??? ","STZ ","STA ","STZ ","BBS1 ",
"LDY ","LDA ","LDX ","??? ","LDY ","LDA ","LDX ","SMB2 ",
"TAY ","LDA ","TAX ","??? ","LDY ","LDA ","LDX ","BBS2 ",
"BCS ","LDA ","LDA ","??? ","LDY ","LDA ","LDX ","SMB3 ",
"CLV ","LDA ","TSX ","??? ","LDY ","LDA ","LDX ","BBS3 ",
"CPY ","CMP ","??? ","??? ","CPY ","CMP ","DEC ","SMB4 ",
"INY ","CMP ","DEX ","??? ","CPY ","CMP ","DEC ","BBS4 ",
"BNE ","CMP ","CMP ","??? ","??? ","CMP ","DEC ","SMB5 ",
"CLD ","CMP ","PHX ","??? ","??? ","CMP ","DEC ","BBS5 ",
"CPX ","SBC ","??? ","??? ","CPX ","SBC ","INC ","SMB6 ",
"INX ","SBC ","NOP ","??? ","CPX ","SBC ","INC ","BBS6 ",
"BEQ ","SBC ","SBC ","??? ","??? ","SBC ","INC ","SMB7 ",
"SED ","SBC ","PLX ","??? ","??? ","SBC ","INC ","BBS7 " };
//
// Display bytes in mem in hex
//
static void DisplayBytes(uint16_t src, uint32_t dst)
static void DisplayBytes(char * outbuf, uint16_t src, uint32_t dst)
{
WriteLog("%04X: ", src);
uint8_t cnt = 0; // Init counter...
char buf[32];
// WriteLog("%04X: ", src);
sprintf(outbuf, "%04X: ", src);
uint8_t cnt = 0;
// That should fix the $FFFF bug...
if (src > dst)
dst += 0x10000; // That should fix the FFFF bug...
dst += 0x10000;
for(uint32_t i=src; i<dst; i++)
{
WriteLog("%02X ", mainCPU.RdMem(i));
cnt++; // Bump counter...
// WriteLog("%02X ", mainCPU.RdMem(i));
sprintf(buf, "%02X ", mainCPU.RdMem(i));
strcat(outbuf, buf);
cnt++;
}
for(int i=cnt; i<5; i++) // Pad the leftover spaces...
WriteLog(" ");
// Pad the leftover spaces...
for(int i=cnt; i<3; i++)
// WriteLog(" ");
{
sprintf(buf, " ");
strcat(outbuf, buf);
}
}
//
// Decode a 65C02 instruction
//
int Decode65C02(uint16_t pc)
int Decode65C02(char * outbuf, uint16_t pc)
{
/*
0) illegal
1) imm = #$00
2) zp = $00
3) zpx = $00,X
4) zpy = $00,Y
5) izp = ($00)
6) izx = ($00,X)
7) izy = ($00),Y
8) abs = $0000
9) abx = $0000,X
10) aby = $0000,Y
11) ind = ($0000)
12) iax = ($0000,X)
13) rel = $0000 (PC-relative)
14) inherent
*/
char outbuf[80];
char buf[32], buf2[32];
uint16_t addr = pc;
uint8_t opcode = mainCPU.RdMem(addr++); // Get the opcode
@ -123,56 +118,57 @@ int Decode65C02(uint16_t pc)
switch (op_mat[opcode]) // Decode the addressing mode...
{
case 0: // Illegal
sprintf(outbuf, "???");
sprintf(buf, "???");
break;
case 1: // Immediate
sprintf(outbuf, "%s #$%02X", mnemonics[opcode], mainCPU.RdMem(addr++));
sprintf(buf, "%s #$%02X", mnemonics[opcode], mainCPU.RdMem(addr++));
break;
case 2: // Zero page
sprintf(outbuf, "%s $%02X", mnemonics[opcode], mainCPU.RdMem(addr++));
sprintf(buf, "%s $%02X", mnemonics[opcode], mainCPU.RdMem(addr++));
break;
case 3: // Zero page, X
sprintf(outbuf, "%s $%02X,X", mnemonics[opcode], mainCPU.RdMem(addr++));
sprintf(buf, "%s $%02X,X", mnemonics[opcode], mainCPU.RdMem(addr++));
break;
case 4: // Zero page, Y
sprintf(outbuf, "%s $%02X,Y", mnemonics[opcode], mainCPU.RdMem(addr++));
sprintf(buf, "%s $%02X,Y", mnemonics[opcode], mainCPU.RdMem(addr++));
break;
case 5: // Zero page indirect
sprintf(outbuf, "%s ($%02X)", mnemonics[opcode], mainCPU.RdMem(addr++));
sprintf(buf, "%s ($%02X)", mnemonics[opcode], mainCPU.RdMem(addr++));
break;
case 6: // Zero page, X indirect
sprintf(outbuf, "%s ($%02X,X)", mnemonics[opcode], mainCPU.RdMem(addr++));
sprintf(buf, "%s ($%02X,X)", mnemonics[opcode], mainCPU.RdMem(addr++));
break;
case 7: // Zero page, Y indirect
sprintf(outbuf, "%s ($%02X),Y", mnemonics[opcode], mainCPU.RdMem(addr++));
sprintf(buf, "%s ($%02X),Y", mnemonics[opcode], mainCPU.RdMem(addr++));
break;
case 8: // Absolute
sprintf(outbuf, "%s $%04X", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
sprintf(buf, "%s $%04X", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
break;
case 9: // Absolute, X
sprintf(outbuf, "%s $%04X,X", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
sprintf(buf, "%s $%04X,X", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
break;
case 10: // Absolute, Y
sprintf(outbuf, "%s $%04X,Y", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
sprintf(buf, "%s $%04X,Y", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
break;
case 11: // Indirect
sprintf(outbuf, "%s ($%04X)", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
sprintf(buf, "%s ($%04X)", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
break;
case 12: // Indirect, X
sprintf(outbuf, "%s ($%04X,X)", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
sprintf(buf, "%s ($%04X,X)", mnemonics[opcode], mainCPU.RdMem(addr++) | (mainCPU.RdMem(addr++) << 8));
break;
case 13: // Relative
// sprintf(outbuf, "%s $%04X", mnemonics[opcode], ++addr + (int16_t)(int8_t)mainCPU.RdMem(addr));
sprintf(outbuf, "%s $%04X", mnemonics[opcode], addr + (int16_t)((int8_t)mainCPU.RdMem(addr)) + 1);
sprintf(buf, "%s $%04X", mnemonics[opcode], addr + (int16_t)((int8_t)mainCPU.RdMem(addr)) + 1);
addr++;
break;
case 14: // Inherent
sprintf(outbuf, "%s ", mnemonics[opcode]);
sprintf(buf, "%s ", mnemonics[opcode]);
break;
}
DisplayBytes(pc, addr); // Show bytes
WriteLog("%-16s", outbuf); // Display opcode & addressing, etc.
DisplayBytes(buf2, pc, addr); // Show bytes
// WriteLog("%-16s", outbuf); // Display opcode & addressing, etc.
sprintf(outbuf, "%s %-14s", buf2, buf); // Display opcode & addressing, etc.
return addr - pc;
}

View File

@ -10,6 +10,7 @@
#include <stdint.h>
int Decode65C02(uint16_t pc);
int Decode65C02(char * outbuf, uint16_t pc);
#endif // __DIS65C02_H__

View File

@ -147,6 +147,20 @@ void SoundDone(void)
}
void SoundPause(void)
{
if (soundInitialized)
SDL_PauseAudioDevice(device, 1);
}
void SoundResume(void)
{
if (soundInitialized)
SDL_PauseAudioDevice(device, 0);
}
//
// Sound card callback handler
//

View File

@ -17,6 +17,8 @@
void SoundInit(void);
void SoundDone(void);
void SoundPause(void);
void SoundResume(void);
void ToggleSpeaker(uint64_t elapsedCycles);
void WriteSampleToBuffer(void);
//void AddToSoundTimeBase(uint64_t cycles);

View File

@ -1142,7 +1142,6 @@ static void Op90(void) // BCC
if (!(regs.cc & FLAG_C))
HANDLE_BRANCH_TAKEN(m)
// regs.pc += m;
}
static void OpB0(void) // BCS
@ -1151,7 +1150,6 @@ static void OpB0(void) // BCS
if (regs.cc & FLAG_C)
HANDLE_BRANCH_TAKEN(m)
// regs.pc += m;
}
static void OpF0(void) // BEQ
@ -1160,7 +1158,6 @@ static void OpF0(void) // BEQ
if (regs.cc & FLAG_Z)
HANDLE_BRANCH_TAKEN(m)
// regs.pc += m;
}
/*
@ -2606,7 +2603,9 @@ static void Op86(void)
static void Op96(void)
{
regs.WrMem(EA_ZP_X, regs.x);
// BUG!!! [FIXED]
//WAS: regs.WrMem(EA_ZP_X, regs.x);
regs.WrMem(EA_ZP_Y, regs.x);
}
static void Op8E(void)
@ -2855,10 +2854,16 @@ On //e, $FCAA is the delay routine. (seems to not have changed from ][+)
//Note: could enforce regs.clock to zero on starting the CPU with an Init() function...
//bleh.
//static uint32_t limit = 0;
// Or, we could just say that initializing the CPU struct is the responsibility
// of the caller. :-)
// This should be in the regs struct, in case we have multiple CPUs...
#warning "!!! Move overflow into regs struct !!!"
static uint64_t overflow = 0;
#define DO_BACKTRACE
#ifdef DO_BACKTRACE
#define BACKTRACE_SIZE 16384
uint32_t btQueuePtr = 0;
V65C02REGS btQueue[BACKTRACE_SIZE];
uint8_t btQueueInst[BACKTRACE_SIZE][4];
#endif
//
// Function to execute 65C02 for "cycles" cycles
//
@ -2867,24 +2872,7 @@ void Execute65C02(V65C02REGS * context, uint32_t cycles)
myMemcpy(&regs, context, sizeof(V65C02REGS));
// Execute here...
// NOTE: There *must* be some way of doing this without requiring the caller to subtract out
// the previous run's cycles. !!! FIX !!!
// Could try:
// while (regs.clock < regs.clock + cycles) <-- won't work
/*
// This isn't as accurate as subtracting out cycles from regs.clock...
// Unless limit is a static variable, adding cycles to it each time through...
uint32_t limit = regs.clock + cycles;
while (regs.clock < limit)
*/
// but have wraparound to deal with. :-/
/*
Let's see...
if (regs.clock + cycles > 0xFFFFFFFF)
wraparound = true;
*/
uint64_t endCycles = regs.clock + (uint64_t)cycles - overflow;
uint64_t endCycles = regs.clock + (uint64_t)cycles - regs.overflow;
while (regs.clock < endCycles)
{
@ -2904,6 +2892,10 @@ if (regs.pc == 0x444E)
dumpDis = false;
}//*/
#endif
/*if (regs.pc == 0xBF4C)
{
dumpDis = true;
}//*/
#if 0
/*if (regs.pc == 0x0801)
@ -2991,8 +2983,12 @@ if (regs.pc == 0x2000)
#endif
#ifdef __DEBUG__
static char disbuf[80];
if (dumpDis)
Decode65C02(regs.pc);
{
Decode65C02(disbuf, regs.pc);
WriteLog("%s", disbuf);
}
#endif
uint8_t opcode = regs.RdMem(regs.pc++);
@ -3089,7 +3085,7 @@ WriteLog("\n*** IRQ ***\n\n");
// subtract it out from a subsequent run. It's guaranteed to be positive,
// because the condition that exits the main loop above is written such
// that regs.clock has to be larger than endCycles to exit from it.
overflow = regs.clock - endCycles;
regs.overflow = regs.clock - endCycles;
myMemcpy(context, &regs, sizeof(V65C02REGS));
}

View File

@ -42,6 +42,7 @@ struct V65C02REGS
uint8_t (* RdMem)(uint16_t); // Address of BYTE read routine
void (* WrMem)(uint16_t, uint8_t); // Address of BYTE write routine
uint16_t cpuFlags; // v65C02 IRQ/RESET flags
uint64_t overflow; // # of cycles we went over last time through
};
// Global variables (exported)