From b2f84b05826e7ae1c857ef0dc5f34800506f7eca Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Fri, 6 Feb 2009 04:25:53 +0000 Subject: [PATCH] Changed clock on v65C02 to 64-bit, more GUI refactoring --- apple2.cfg | 12 ++++----- src/apple2.cpp | 40 ++++++++++++++++++++++++--- src/floppy.cpp | 4 +++ src/gui/diskwindow.cpp | 12 ++++----- src/gui/element.cpp | 15 +++++++++++ src/gui/gui.cpp | 3 +++ src/sound.cpp | 61 ++++++++++++++++++++++++++++++++++++++---- src/sound.h | 7 +++-- src/timing.h | 2 +- src/v65c02.cpp | 8 +++--- src/v65c02.h | 5 ++-- 11 files changed, 139 insertions(+), 30 deletions(-) diff --git a/apple2.cfg b/apple2.cfg index bd3016b..9e2b2c1 100755 --- a/apple2.cfg +++ b/apple2.cfg @@ -21,7 +21,7 @@ autoSaveState = 1 #floppyImage1 = ./disks/temp.nib #floppyImage1 = ./disks/temp.dsk # Yes -#floppyImage1 = ./disks/bt1_boot.dsk +floppyImage1 = ./disks/bt1_boot.dsk # Yes #floppyImage1 = ./disks/bt2_boot.dsk # Yes (but segfaults in the timer routine in the title screen--NB: Not anymore...) @@ -45,11 +45,11 @@ autoSaveState = 1 #floppyImage1 = ./disks/MoebiusI-1.dsk #floppyImage2 = ./disks/MoebiusI-2.dsk # Yes, but crashes on the attract mode (does the same in AppleWin) -# Also, has keyboard troubles... no, write problems +# Also, write problems #floppyImage1 = ./disks/moebiusiia.dsk -floppyImage1 = ./disks/MoebiusIIA.dsk -floppyImage2 = ./disks/MoebiusIIB.dsk -# Yes, but segfaults on title screen +#floppyImage1 = ./disks/MoebiusIIA.dsk +#floppyImage2 = ./disks/MoebiusIIB.dsk +# Yes #floppyImage1 = ./disks/wind_walker_1.dsk # Yes #floppyImage1 = ./disks/dino_eggs.dsk @@ -68,7 +68,7 @@ floppyImage2 = ./disks/MoebiusIIB.dsk # OpenGL options: 1 - use OpenGL rendering, 0 - use old style rendering -useOpenGL = 0 +useOpenGL = 1 # OpenGL filtering type: 1 - blurry, 0 - sharp diff --git a/src/apple2.cpp b/src/apple2.cpp index fa7323a..42f59e4 100755 --- a/src/apple2.cpp +++ b/src/apple2.cpp @@ -754,6 +754,11 @@ static bool LoadApple2State(const char * filename) return false; } +//#define CPU_CLOCK_CHECKING +#ifdef CPU_CLOCK_CHECKING +uint8 counter = 0; +uint32 totalCPU = 0; +#endif // // Main loop // @@ -877,8 +882,12 @@ memcpy(ram + 0xD000, ram + 0xC000, 0x1000); //(Fix so that this is not a requirement!) //Fixed, but mainCPU.clock is destroyed in the bargain. Oh well. // mainCPU.clock -= USEC_TO_M6502_CYCLES(timeToNextEvent); +#ifdef CPU_CLOCK_CHECKING +totalCPU += USEC_TO_M6502_CYCLES(timeToNextEvent); +#endif // Handle CPU time delta for sound... - AddToSoundTimeBase(USEC_TO_M6502_CYCLES(timeToNextEvent)); +//Don't need this anymore now that we use absolute time... +// AddToSoundTimeBase(USEC_TO_M6502_CYCLES(timeToNextEvent)); HandleNextEvent(); } @@ -995,8 +1004,8 @@ static void FrameCallback(void) if (event.key.keysym.sym == SDLK_F12) dumpDis = !dumpDis; // Toggle the disassembly process - else if (event.key.keysym.sym == SDLK_F11) - floppyDrive.LoadImage("./disks/bt1_char.dsk");//Kludge to load char disk... +// else if (event.key.keysym.sym == SDLK_F11) +// floppyDrive.LoadImage("./disks/bt1_char.dsk");//Kludge to load char disk... else if (event.key.keysym.sym == SDLK_F9) { floppyDrive.CreateBlankImage(); @@ -1019,16 +1028,39 @@ else if (event.key.keysym.sym == SDLK_F10) // to quit completely... !!! FIX !!! gui->Run(); + if (event.key.keysym.sym == SDLK_F5) + { + VolumeDown(); + char volStr[10] = "*********"; + volStr[GetVolume()] = 0; + SpawnMessage("Volume: %s", volStr); + } + else if (event.key.keysym.sym == SDLK_F6) + { + VolumeUp(); + char volStr[10] = "*********"; + volStr[GetVolume()] = 0; + SpawnMessage("Volume: %s", volStr); + } + break; case SDL_QUIT: running = false; } } -//ick. HandleSoundAtFrameEdge(); // Sound stuff... (ick) RenderVideoFrame(); SetCallbackTime(FrameCallback, 16666.66666667); +#ifdef CPU_CLOCK_CHECKING +counter++; +if (counter == 60) +{ + printf("Executed %u cycles...\n", totalCPU); + totalCPU = 0; + counter = 0; +} +#endif //Instead of this, we should yield remaining time to other processes... !!! FIX !!! //lessee... //nope. SDL_Delay(10); diff --git a/src/floppy.cpp b/src/floppy.cpp index d403714..8109604 100755 --- a/src/floppy.cpp +++ b/src/floppy.cpp @@ -106,6 +106,7 @@ bool FloppyDrive::LoadImage(const char * filename, uint8 driveNum/*= 0*/) fclose(fp2); } #endif +//writeProtected[driveNum] = true; WriteLog("FLOPPY: Loaded image '%s' for drive #%u.\n", filename, driveNum); return true; @@ -638,6 +639,9 @@ Which we now do. :-) nybblizedImage[activeDrive][(track * 6656) + currentPos] = latchValue; imageDirty[activeDrive] = true; } + else +//doesn't seem to do anything + return 0;//is this more like it? } uint8 diskByte = nybblizedImage[activeDrive][(track * 6656) + currentPos]; diff --git a/src/gui/diskwindow.cpp b/src/gui/diskwindow.cpp index 25e7537..7b33dbc 100644 --- a/src/gui/diskwindow.cpp +++ b/src/gui/diskwindow.cpp @@ -78,11 +78,9 @@ DiskWindow::DiskWindow(FloppyDrive * fdp, uint32 x/*= 0*/, uint32 y/*= 0*/): Win writeProtect1 = new Button(4, 176, "WriteProt1", this); writeProtect2 = new Button(4, 196, "WriteProt2", this); swap = new Button(4, 220, "Swap Disks", this); -//Weird... It's showing an initial state of write-protected even though -//the constructor of FloppyDrive sets it to false! -#warning "Write protection state is wrong. !!! FIX !!!" - writeProtect1->SetText((floppyDrive->DiskIsWriteProtected(0) ? "write" : "no write")); - writeProtect2->SetText((floppyDrive->DiskIsWriteProtected(1) ? "write" : "no write")); + + writeProtect1->SetText((floppyDrive->DiskIsWriteProtected(0) ? "no write" : "write")); + writeProtect2->SetText((floppyDrive->DiskIsWriteProtected(1) ? "no write" : "write")); AddElement(newDisk1); AddElement(newDisk2); @@ -266,7 +264,7 @@ what you could do is like this way: // floppyDrive->SetWriteProtect(true, 0); // Housekeeping - writeProtect1->SetText((floppyDrive->DiskIsWriteProtected(0) ? "write" : "no write")); + writeProtect1->SetText((floppyDrive->DiskIsWriteProtected(0) ? "no write" : "write")); Draw(); } else if (e == writeProtect2) @@ -274,7 +272,7 @@ what you could do is like this way: floppyDrive->SetWriteProtect((floppyDrive->DiskIsWriteProtected(1) ? false : true), 1); // Housekeeping - writeProtect2->SetText((floppyDrive->DiskIsWriteProtected(1) ? "write" : "no write")); + writeProtect2->SetText((floppyDrive->DiskIsWriteProtected(1) ? "no write" : "write")); Draw(); } else if (e == swap) diff --git a/src/gui/element.cpp b/src/gui/element.cpp index cf60ac3..1c65b2d 100755 --- a/src/gui/element.cpp +++ b/src/gui/element.cpp @@ -137,11 +137,26 @@ SDL_Rect Element::GetExtents(void) return extents; } +//kludge +#include "settings.h" void Element::CreateBackstore(void) { backstore = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32, MASK_R, MASK_G, MASK_B, 0x00); +//#define TEST_GL +#ifdef TEST_GL +printf("Element: About to do SDL_BlitSurface...\n"); +#endif +//kludge +if (settings.useOpenGL) + return; + +//Since screen is the main screen surface, OpenGL doesn't like it being touched. +//How to fix? Dunno. SDL_BlitSurface(screen, &extents, backstore, NULL); +#ifdef TEST_GL +printf("Element: SDL_BlitSurface...Done.\n"); +#endif } void Element::RestoreScreenFromBackstore(void) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 7c6e219..5bbd85e 100755 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -113,6 +113,9 @@ void GUI::Run(void) SDL_EnableKeyRepeat(150, 75); + // Also: Need to pick up backbuffer (for those windows that have them) + // BEFORE drawing... + // Initial update... [Now handled correctly in the constructor] // Uh, still needed here, though... Only makes sense that it should for(i=windowList.begin(); i!=windowList.end(); i++) diff --git a/src/sound.cpp b/src/sound.cpp index b39fb82..b708b2d 100755 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -26,7 +26,8 @@ #include "log.h" -#define SAMPLE_RATE (44100.0) +//#define SAMPLE_RATE (44100.0) +#define SAMPLE_RATE (48000.0) #define SAMPLES_PER_FRAME (SAMPLE_RATE / 60.0) #define CYCLES_PER_SAMPLE (1024000.0 / SAMPLE_RATE) #define SOUND_BUFFER_SIZE (8192) @@ -43,6 +44,8 @@ static bool speakerState = false; static uint8 soundBuffer[SOUND_BUFFER_SIZE]; static uint32 soundBufferPos; static uint32 sampleBase; +static uint64 lastToggleCycles; +static uint64 samplePosition; static SDL_cond * conditional = NULL; static SDL_mutex * mutex = NULL; static SDL_mutex * mutex2 = NULL; @@ -85,6 +88,8 @@ return; SDL_mutexP(mutex); // Must lock the mutex for the cond to work properly... soundBufferPos = 0; sampleBase = 0; + lastToggleCycles = 0; + samplePosition = 0; SDL_PauseAudio(false); // Start playback! soundInitialized = true; @@ -149,10 +154,12 @@ static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length) soundBuffer[i] = soundBuffer[length + i]; } + // Update our sample position + samplePosition += length; // Free the mutex... SDL_mutexV(mutex2); // Wake up any threads waiting for the buffer to drain... -// SDL_CondSignal(conditional); + SDL_CondSignal(conditional); } // Need some interface functions here to take care of flipping the @@ -171,11 +178,13 @@ So... I guess what we could do is this: the time position back (or copies data down from what it took out) */ -void ToggleSpeaker(uint32 time) +void ToggleSpeaker(uint64 elapsedCycles) { if (!soundInitialized) return; + uint64 deltaCycles = elapsedCycles - lastToggleCycles; + #if 0 if (time > 95085)//(time & 0x80000000) { @@ -190,7 +199,26 @@ if (time > 95085)//(time & 0x80000000) // SDL_LockAudio(); SDL_mutexP(mutex2); - uint32 currentPos = sampleBase + (uint32)((double)time / CYCLES_PER_SAMPLE); +// uint32 currentPos = sampleBase + (uint32)((double)elapsedCycles / CYCLES_PER_SAMPLE); + uint32 currentPos = (uint32)((double)deltaCycles / CYCLES_PER_SAMPLE); + +/* +The problem: + + ______ | ______________ | ______ +____| | | |_______ + +Speaker is toggled, then not toggled for a while. How to find buffer position in the +last frame? + +IRQ buffer len is 1024. + +Could check current CPU clock, take delta. If delta > 1024, then ... + +Could add # of cycles in IRQ to lastToggleCycles, then currentPos will be guaranteed +to fall within acceptable limits. +*/ + if (currentPos > SOUND_BUFFER_SIZE - 1) { @@ -212,7 +240,12 @@ Seems like it's OK now that I've fixed the buffer-less-than-length bug... // SDL_UnlockAudio(); // SDL_CondWait(conditional, mutex); // SDL_LockAudio(); - currentPos = sampleBase + (uint32)((double)time / CYCLES_PER_SAMPLE); +// Hm. +SDL_mutexV(mutex2);//Release it so sound thread can get it, +SDL_CondWait(conditional, mutex);//Sleep/wait for the sound thread +SDL_mutexP(mutex2);//Re-lock it until we're done with it... + + currentPos = sampleBase + (uint32)((double)elapsedCycles / CYCLES_PER_SAMPLE); #if 0 WriteLog("--> after spinlock (sampleBase=%u)...\n", sampleBase); #endif @@ -241,6 +274,24 @@ void AddToSoundTimeBase(uint32 cycles) // SDL_UnlockAudio(); } +void VolumeUp(void) +{ + // Currently set for 8-bit samples + if (ampPtr < 8) + ampPtr++; +} + +void VolumeDown(void) +{ + if (ampPtr > 0) + ampPtr--; +} + +uint8 GetVolume(void) +{ + return ampPtr; +} + /* HOW IT WORKS diff --git a/src/sound.h b/src/sound.h index 3d3c442..9983eaa 100755 --- a/src/sound.h +++ b/src/sound.h @@ -17,7 +17,10 @@ void SoundInit(void); void SoundDone(void); -void ToggleSpeaker(uint32 time); -void AddToSoundTimeBase(uint32 cycles); +void ToggleSpeaker(uint64 elapsedCycles); +void AddToSoundTimeBase(uint64 cycles); +void VolumeUp(void); +void VolumeDown(void); +uint8 GetVolume(void); #endif // __SOUND_H__ diff --git a/src/timing.h b/src/timing.h index 352583b..1213947 100755 --- a/src/timing.h +++ b/src/timing.h @@ -19,7 +19,7 @@ //#define USEC_TO_RISC_CYCLES(u) (uint32)(((u) / RISC_CYCLE_IN_USEC) + 0.5) //#define USEC_TO_M68K_CYCLES(u) (uint32)(((u) / M68K_CYCLE_IN_USEC) + 0.5) -#define USEC_TO_M6502_CYCLES(u) (uint32)(((u) / M6502_CYCLE_IN_USEC) + 0.5) +#define USEC_TO_M6502_CYCLES(u) ((uint32)(((u) / M6502_CYCLE_IN_USEC) + 0.5)) void InitializeEventList(void); void SetCallbackTime(void (* callback)(void), double time); diff --git a/src/v65c02.cpp b/src/v65c02.cpp index 59cc415..6f2c969 100755 --- a/src/v65c02.cpp +++ b/src/v65c02.cpp @@ -2256,8 +2256,9 @@ Let's see... if (regs.clock + cycles > 0xFFFFFFFF) wraparound = true; */ + uint64 endCycles = regs.clock + (uint64)cycles; - while (regs.clock < cycles) + while (regs.clock < endCycles) { #if 0 /*if (regs.pc == 0x4007) @@ -2402,7 +2403,8 @@ WriteLog("\n*** IRQ ***\n\n"); //This is a lame way of doing it, but in the end the simplest--however, it destroys any //record of elasped CPU time. Not sure that it's important to keep track, but there it is. - regs.clock -= cycles; +// Now we use a 64-bit integer, so it won't wrap for about 500 millenia. ;-) +// regs.clock -= cycles; myMemcpy(context, ®s, sizeof(V65C02REGS)); } @@ -2410,7 +2412,7 @@ WriteLog("\n*** IRQ ***\n\n"); // // Get the clock of the currently executing CPU // -uint32 GetCurrentV65C02Clock(void) +uint64 GetCurrentV65C02Clock(void) { return regs.clock; } diff --git a/src/v65c02.h b/src/v65c02.h index 7a557ab..c880331 100755 --- a/src/v65c02.h +++ b/src/v65c02.h @@ -37,7 +37,8 @@ struct V65C02REGS uint8 a; // 65C02 A register uint8 x; // 65C02 X index register uint8 y; // 65C02 Y register - uint32 clock; // 65C02 clock (@ 1 MHz, wraps at 71.5 minutes) +// uint32 clock; // 65C02 clock (@ 1 MHz, wraps at 71.5 minutes) + uint64 clock; // 65C02 clock (@ 1 MHz, wraps at 570842 years) uint8 (* RdMem)(uint16); // Address of BYTE read routine void (* WrMem)(uint16, uint8); // Address of BYTE write routine uint16 cpuFlags; // v65C02 IRQ/RESET flags @@ -50,6 +51,6 @@ extern bool dumpDis; // Function prototypes void Execute65C02(V65C02REGS *, uint32); // Function to execute 65C02 instructions -uint32 GetCurrentV65C02Clock(void); // Get the clock of the currently executing CPU +uint64 GetCurrentV65C02Clock(void); // Get the clock of the currently executing CPU #endif // __V65C02_H__ -- 2.37.2