QMAKE_EXTRA := -spec macx-g++
endif
+# Eh?
+CFLAGS ?= ""
+CPPFLAGS ?= ""
+CXXFLAGS ?= ""
+LDFLAGS ?= ""
+
+QMAKE_EXTRA += "QMAKE_CFLAGS_RELEASE=$(CFLAGS)"
+QMAKE_EXTRA += "QMAKE_CXXFLAGS_RELEASE=$(CXXFLAGS)"
+QMAKE_EXTRA += "QMAKE_LFLAGS_RELEASE=$(LDFLAGS)"
+
+QMAKE_EXTRA += "QMAKE_CFLAGS_DEBUG=$(CFLAGS)"
+QMAKE_EXTRA += "QMAKE_CXXFLAGS_DEBUG=$(CXXFLAGS)"
+QMAKE_EXTRA += "QMAKE_LFLAGS_DEBUG=$(LDFLAGS)"
+
all: prepare virtualjaguar
@echo -e "\033[01;33m***\033[00;32m Success!\033[00m"
prepare: obj
@echo -e "\033[01;33m***\033[00;32m Preparing to compile Virtual Jaguar...\033[00m"
-# @echo "#define VJ_RELEASE_VERSION \"v2.0.3\"" > src/version.h
+# @echo "#define VJ_RELEASE_VERSION \"v2.1.0\"" > src/version.h
# @echo "#define VJ_RELEASE_SUBVERSION \"Final\"" >> src/version.h
@echo "#define VJ_RELEASE_VERSION \"SVN `svn info | grep -i revision`\"" > src/version.h
- @echo "#define VJ_RELEASE_SUBVERSION \"2.0.3 Prerelease\"" >> src/version.h
+ @echo "#define VJ_RELEASE_SUBVERSION \"2.1.0 Prerelease\"" >> src/version.h
virtualjaguar: sources libs makefile-qt
@echo -e "\033[01;33m***\033[00;32m Making Virtual Jaguar GUI...\033[00m"
obj/libm68k.a: src/m68000/Makefile sources
@echo -e "\033[01;33m***\033[00;32m Making Customized UAE 68K Core...\033[00m"
- @$(MAKE) -C src/m68000
+# @$(MAKE) -C src/m68000
+ @$(MAKE) -C src/m68000 CFLAGS="$(CFLAGS)"
@cp src/m68000/obj/libm68k.a obj/
obj/libmusashi.a: musashi.mak sources
obj/libjaguarcore.a: jaguarcore.mak sources
@echo -e "\033[01;33m***\033[00;32m Making Virtual Jaguar core...\033[00m"
- $(MAKE) -f jaguarcore.mak
+# $(MAKE) -f jaguarcore.mak
+ $(MAKE) -f jaguarcore.mak CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)"
sources: src/*.h src/*.cpp src/*.c src/m68000/*.c src/m68000/*.h
OSTYPE := $(shell uname -a)
-ifeq "$(findstring Msys,$(OSTYPE))" "Msys" # Win32
+# Win32
+ifeq "$(findstring Msys,$(OSTYPE))" "Msys"
SYSTYPE := __GCCWIN32__
SDLLIBTYPE := --libs
-else ifeq "$(findstring Darwin,$(OSTYPE))" "Darwin" # Should catch both 'darwin' and 'darwin7.0'
+# Apple. Should catch both 'darwin' and 'darwin7.0'
+else ifeq "$(findstring Darwin,$(OSTYPE))" "Darwin"
SYSTYPE := __GCCUNIX__ -D__THINK_STUPID__
SDLLIBTYPE := --static-libs
-else ifeq "$(findstring Linux,$(OSTYPE))" "Linux" # Linux
+# Linux
+else ifeq "$(findstring Linux,$(OSTYPE))" "Linux"
SYSTYPE := __GCCUNIX__
SDLLIBTYPE := --libs
-else # ???
+# ??? Throw error, unknown OS
+else
$(error OS TYPE UNDETECTED)
CDIOLIB :=
endif
-CC := gcc
-LD := gcc
-AR := ar
-ARFLAGS := -rs
+CC := gcc
+LD := gcc
+AR := ar
+ARFLAGS := -rs
# Note that we use optimization level 2 instead of 3--3 doesn't seem to gain much over 2
-CFLAGS := -MMD -O2 -ffast-math -fomit-frame-pointer `sdl-config --cflags` -D$(SYSTYPE)
-CXXFLAGS := -MMD -O2 -ffast-math -fomit-frame-pointer `sdl-config --cflags` -D$(SYSTYPE)
+#CFLAGS := -MMD -O2 -ffast-math -fomit-frame-pointer `sdl-config --cflags` -D$(SYSTYPE)
+#CXXFLAGS := -MMD -O2 -ffast-math -fomit-frame-pointer `sdl-config --cflags` -D$(SYSTYPE)
+CFLAGS ?= -O2 -ffast-math -fomit-frame-pointer
+CXXFLAGS ?= -O2 -ffast-math -fomit-frame-pointer
+
+SDL_CFLAGS = `sdl-config --cflags`
+DEFINES = -D$(SYSTYPE)
+GCC_DEPS = "-MMD"
INCS := -I./src
obj/%.o: src/%.c
@echo -e "\033[01;33m***\033[00;32m Compiling $<...\033[00m"
- @$(CC) $(CFLAGS) $(INCS) -c $< -o $@
+# @$(CC) $(CFLAGS) $(INCS) -c $< -o $@
+ @$(CC) $(GCC_DEPS) $(CFLAGS) $(SDL_CFLAGS) $(DEFINES) $(INCS) -c $< -o $@
obj/%.o: src/%.cpp
@echo -e "\033[01;33m***\033[00;32m Compiling $<...\033[00m"
- @$(CC) $(CXXFLAGS) $(INCS) -c $< -o $@
+# @$(CC) $(CXXFLAGS) $(INCS) -c $< -o $@
+ @$(CC) $(GCC_DEPS) $(CXXFLAGS) $(SDL_CFLAGS) $(DEFINES) $(INCS) -c $< -o $@
-include obj/*.d
<p>Trademarks used in <i>Virtual Jaguar</i> and/or this documentation are the property of their respective owners. The user(s) of <i>Virtual Jaguar</i> assumes all risk associated with using the software; the authors are not responsible for anything the user(s) does with said software or what happens to the user(s) as a result of using this software.</p>
-<p><i>Virtual Jaguar</i> is Free (as in Libre) software and is licensed under the GPL version 3. You should have recieved a copy of the license with this software; if you did not, you may view a copy at <a href="http://www.gnu.org/licenses">http://www.gnu.org/licenses</a>. A copy of the source code is available at <a href="http://icculus.org/virtualjaguar">http://icculus.org/virtualjaguar</a>.</p>
+<p><i>Virtual Jaguar</i> is Free (as in Libre) software and is licensed under the GPL version 3. You should have received a copy of the license with this software; if you did not, you may view a copy at <a href="http://www.gnu.org/licenses">http://www.gnu.org/licenses</a>. A copy of the source code is available at <a href="http://icculus.org/virtualjaguar">http://icculus.org/virtualjaguar</a>.</p>
<p><i>Downfall</i> is © 2011 <b>Reboot</b>, All Rights Reserved. Distribution of <i>Downfall</i> with <i>Virtual Jaguar</i> has been graciously authorized by <b>Reboot</b>, and may not be distributed as part of any other package.</p>
// Who When What
// --- ---------- -------------------------------------------------------------
// JLH 01/16/2010 Created this log ;-)
+// JLH 04/30/2012 Changed SDL audio handler to run JERRY
//
// Need to set up defaults that the BIOS sets for the SSI here in DACInit()... !!! FIX !!!
// that is the current spinlock implementation. Since the DSP is a separate
// entity, could we get away with running it in the sound IRQ?
-// ALSO: It may be a good idea to physically separate the left and right buffers
-// to prevent things like the DSP filling only one side and such. Do such
-// mono modes exist on the Jag? Seems to according to Super Burnout.
-
// After testing on a real Jaguar, it seems clear that the I2S interrupt drives
// the audio subsystem. So while you can drive the audio at a *slower* rate than
// set by SCLK, you can't drive it any *faster*. Also note, that if the I2S
// Global variables
+// These are defined in memory.h/cpp
//uint16 lrxd, rrxd; // I2S ports (into Jaguar)
// Local variables
-static uint32 LeftFIFOHeadPtr, LeftFIFOTailPtr, RightFIFOHeadPtr, RightFIFOTailPtr;
static SDL_AudioSpec desired;
static bool SDLSoundInitialized;
-
-// We can get away with using native endian here because we can tell SDL to use the native
-// endian when looking at the sample buffer, i.e., no need to worry about it.
-
-static uint16 DACBuffer[BUFFER_SIZE];
static uint8 SCLKFrequencyDivider = 19; // Default is roughly 22 KHz (20774 Hz in NTSC mode)
/*static*/ uint16 serialMode = 0;
// Private function prototypes
void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
-void SDLSoundCallbackNew(void * userdata, Uint8 * buffer, int length);
void DSPSampleCallback(void);
return;
}
-#ifdef NEW_DAC_CODE
desired.freq = DAC_AUDIO_RATE;
desired.format = AUDIO_S16SYS;
desired.channels = 2;
- desired.samples = 2048;
- desired.callback = SDLSoundCallbackNew;
-#else
-// memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
-// DACBuffer = (uint16 *)memory_malloc(BUFFER_SIZE * sizeof(uint16), "DAC buffer");
-
- desired.freq = GetCalculatedFrequency(); // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
- desired.format = AUDIO_S16SYS; // This uses the native endian (for portability)...
- desired.channels = 2;
-// desired.samples = 4096; // Let's try a 4K buffer (can always go lower)
- desired.samples = 2048; // Let's try a 2K buffer (can always go lower)
+ desired.samples = 2048; // 2K buffer = audio delay of 42.67 ms (@ 48 KHz)
desired.callback = SDLSoundCallback;
-#endif
- if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
+ if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
WriteLog("DAC: Failed to initialize SDL sound...\n");
else
{
SDLSoundInitialized = true;
DACReset();
- SDL_PauseAudio(false); // Start playback!
+ SDL_PauseAudio(false); // Start playback!
WriteLog("DAC: Successfully initialized. Sample rate: %u\n", desired.freq);
}
//
void DACReset(void)
{
- LeftFIFOHeadPtr = LeftFIFOTailPtr = 0, RightFIFOHeadPtr = RightFIFOTailPtr = 1;
+// LeftFIFOHeadPtr = LeftFIFOTailPtr = 0, RightFIFOHeadPtr = RightFIFOTailPtr = 1;
ltxd = lrxd = desired.silence;
}
SDL_CloseAudio();
}
-// memory_free(DACBuffer);
WriteLog("DAC: Done.\n");
}
// Note: The samples are packed in the buffer in 16 bit left/16 bit right pairs.
// Also, length is the length of the buffer in BYTES
//
-//static double timePerSample = 0;
static Uint8 * sampleBuffer;
static int bufferIndex = 0;
static int numberOfSamples = 0;
static bool bufferDone = false;
-void SDLSoundCallbackNew(void * userdata, Uint8 * buffer, int length)
+void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
{
// 1st, check to see if the DSP is running. If not, fill the buffer with L/RXTD and exit.
// Now, run the DSP for that length of time for each sample we need to make
-#if 0
- for(int i=0; i<(length/2); i+=2)
- {
-//This stuff is from the old Jaguar execute loop. New stuff is timer based...
-//which means we need to figure that crap out, and how to make it work here.
-//Seems like we need two separate timing queues. Tho not sure how to make that work here...
-//Maybe like the "frameDone" in JaguarExecuteNew() in jaguar.cpp?
-// JERRYExecPIT(cyclesPerSample);
-// JERRYI2SExec(cyclesPerSample);
-// BUTCHExec(cyclesPerSample);
-
- if (vjs.DSPEnabled)
- {
- if (vjs.usePipelinedDSP)
- DSPExecP2(cyclesPerSample);
- else
- DSPExec(cyclesPerSample);
- }
-
- ((uint16_t *)buffer)[i + 0] = ltxd;
- ((uint16_t *)buffer)[i + 1] = rtxd;
- }
-#else
bufferIndex = 0;
sampleBuffer = buffer;
numberOfSamples = length / 2;
HandleNextEvent(EVENT_JERRY);
}
while (!bufferDone);
-
- // We do this to prevent problems with trying to write past the end of the buffer...
-// RemoveCallback(DSPSampleCallback);
-#endif
}
SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY);
}
-#if 0
- frameDone = false;
-
- do
- {
- double timeToNextEvent = GetTimeToNextEvent();
-//WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
-
- m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
-
- if (vjs.GPUEnabled)
- GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
-
-#ifndef NEW_DAC_CODE
- if (vjs.DSPEnabled)
- {
- if (vjs.usePipelinedDSP)
- DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
- else
- DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
- }
-#endif
-
- HandleNextEvent();
- }
- while (!frameDone);
-#endif
-
-
-//
-// SDL callback routine to fill audio buffer
-//
-// Note: The samples are packed in the buffer in 16 bit left/16 bit right pairs.
-// Also, length is the length of the buffer in BYTES
-//
-void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
-{
- // Clear the buffer to silence, in case the DAC buffer is empty (or short)
-//This causes choppy sound... Ick.
- memset(buffer, desired.silence, length);
-//WriteLog("DAC: Inside callback...\n");
- if (LeftFIFOHeadPtr != LeftFIFOTailPtr)
- {
-//WriteLog("DAC: About to write some data!\n");
- int numLeftSamplesReady
- = (LeftFIFOTailPtr + (LeftFIFOTailPtr < LeftFIFOHeadPtr ? BUFFER_SIZE : 0))
- - LeftFIFOHeadPtr;
- int numRightSamplesReady
- = (RightFIFOTailPtr + (RightFIFOTailPtr < RightFIFOHeadPtr ? BUFFER_SIZE : 0))
- - RightFIFOHeadPtr;
-//This waits for the slower side to catch up. If writing only one side, then this
-//causes the buffer not to drain...
- int numSamplesReady
- = (numLeftSamplesReady < numRightSamplesReady
- ? numLeftSamplesReady : numRightSamplesReady);//Hmm. * 2;
-
-//Kludge, until I can figure out WTF is going on WRT Super Burnout.
-if (numLeftSamplesReady == 0 || numRightSamplesReady == 0)
- numSamplesReady = numLeftSamplesReady + numRightSamplesReady;
-
-//The numbers look good--it's just that the DSP can't get enough samples in the DAC buffer!
-//WriteLog("DAC: Left/RightFIFOHeadPtr: %u/%u, Left/RightFIFOTailPtr: %u/%u\n", LeftFIFOHeadPtr, RightFIFOHeadPtr, LeftFIFOTailPtr, RightFIFOTailPtr);
-//WriteLog(" numLeft/RightSamplesReady: %i/%i, numSamplesReady: %i, length of buffer: %i\n", numLeftSamplesReady, numRightSamplesReady, numSamplesReady, length);
-
-/* if (numSamplesReady > length)
- numSamplesReady = length;//*/
- if (numSamplesReady > length / 2) // length / 2 because we're comparing 16-bit lengths
- numSamplesReady = length / 2;
-//else
-// WriteLog(" Not enough samples to fill the buffer (short by %u L/R samples)...\n", (length / 2) - numSamplesReady);
-//WriteLog("DAC: %u samples ready.\n", numSamplesReady);
-
- // Actually, it's a bit more involved than this, but this is the general idea:
-// memcpy(buffer, DACBuffer, length);
- for(int i=0; i<numSamplesReady; i++)
- ((uint16 *)buffer)[i] = DACBuffer[(LeftFIFOHeadPtr + i) % BUFFER_SIZE];
- // Could also use (as long as BUFFER_SIZE is a multiple of 2):
-// buffer[i] = DACBuffer[(LeftFIFOHeadPtr + i) & (BUFFER_SIZE - 1)];
-
- LeftFIFOHeadPtr = (LeftFIFOHeadPtr + numSamplesReady) % BUFFER_SIZE;
- RightFIFOHeadPtr = (RightFIFOHeadPtr + numSamplesReady) % BUFFER_SIZE;
- // Could also use (as long as BUFFER_SIZE is a multiple of 2):
-// LeftFIFOHeadPtr = (LeftFIFOHeadPtr + numSamplesReady) & (BUFFER_SIZE - 1);
-// RightFIFOHeadPtr = (RightFIFOHeadPtr + numSamplesReady) & (BUFFER_SIZE - 1);
-//WriteLog(" -> Left/RightFIFOHeadPtr: %04X/%04X, Left/RightFIFOTailPtr: %04X/%04X\n", LeftFIFOHeadPtr, RightFIFOHeadPtr, LeftFIFOTailPtr, RightFIFOTailPtr);
- }
-//Hmm. Seems that the SDL buffer isn't being starved by the DAC buffer...
-// else
-// WriteLog("DAC: Silence...!\n");
-}
+#if 0
//
// Calculate the frequency of SCLK * 32 using the divider
//
// 16 bits of left data + 16 bits of right data = 32 bits, 1 SCLK = 1 bit transferred).
return systemClockFrequency / (32 * (2 * (SCLKFrequencyDivider + 1)));
}
-
-
-static int oldFreq = 0;
-
-void DACSetNewFrequency(int freq)
-{
-#ifdef NEW_DAC_CODE
-#else
- if (freq == oldFreq)
- return;
-
- oldFreq = freq;
-
- // Should do some sanity checking on the frequency...
-
- if (SDLSoundInitialized)
- SDL_CloseAudio();
-
- desired.freq = freq;// SDL will do conversion on the fly, if it can't get the exact rate. Nice!
- WriteLog("DAC: Changing sample rate to %u Hz!\n", desired.freq);
-
- if (SDLSoundInitialized)
- {
- if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
- {
-// This is bad, Bad, BAD !!! DON'T ABORT BECAUSE WE DIDN'T GET OUR FREQ! !!! FIX !!!
-#warning !!! FIX !!! Aborting because of SDL audio problem is bad!
- WriteLog("DAC: Failed to initialize SDL sound: %s.\nDesired freq: %u\nShutting down!\n", SDL_GetError(), desired.freq);
-// LogDone();
-// exit(1);
-#warning "Reimplement GUICrashGracefully!"
-// GUICrashGracefully("Failed to initialize SDL sound!");
- return;
- }
- }
-
- DACReset();
-
- if (SDLSoundInitialized)
- SDL_PauseAudio(false); // Start playback!
#endif
-}
//
{
if (offset == LTXD + 2)
{
- if (!SDLSoundInitialized)
- return;
-
-#ifdef NEW_DAC_CODE
ltxd = data;
-#else
- // Spin until buffer has been drained (for too fast processors!)...
-//Small problem--if Head == 0 and Tail == buffer end, then this will fail... !!! FIX !!!
-//[DONE]
- // Also, we're taking advantage of the fact that the buffer is a multiple of two
- // in this check...
-uint32 spin = 0;
- while (((LeftFIFOTailPtr + 2) & (BUFFER_SIZE - 1)) == LeftFIFOHeadPtr)//;
- {
-spin++;
-//if ((spin & 0x0FFFFFFF) == 0)
-// WriteLog("Tail=%X, Head=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
-
-if (spin == 0xFFFF0000)
-{
-uint32 ltail = LeftFIFOTailPtr, lhead = LeftFIFOHeadPtr;
-WriteLog("Tail=%X, Head=%X", ltail, lhead);
-
- WriteLog("\nStuck in left DAC spinlock! Aborting!\n");
- WriteLog("LTail=%X, LHead=%X, BUFFER_SIZE-1=%X\n", LeftFIFOTailPtr, LeftFIFOHeadPtr, BUFFER_SIZE - 1);
- WriteLog("RTail=%X, RHead=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
- WriteLog("From while: Tail=%X, Head=%X", (LeftFIFOTailPtr + 2) & (BUFFER_SIZE - 1), LeftFIFOHeadPtr);
-// LogDone();
-// exit(0);
-#warning "Reimplement GUICrashGracefully!"
-// GUICrashGracefully("Stuck in left DAC spinlock!");
- return;
-}
- }//*/
-
- SDL_LockAudio(); // Is it necessary to do this? Mebbe.
- // We use a circular buffer 'cause it's easy. Note that the callback function
- // takes care of dumping audio to the soundcard...! Also note that we're writing
- // the samples in the buffer in an interleaved L/R format.
- LeftFIFOTailPtr = (LeftFIFOTailPtr + 2) % BUFFER_SIZE;
- DACBuffer[LeftFIFOTailPtr] = data;
- SDL_UnlockAudio();
-#endif
}
else if (offset == RTXD + 2)
{
- if (!SDLSoundInitialized)
- return;
-/*
-Here's what's happening now:
-
-Stuck in right DAC spinlock!
-Aborting!
-
-Tail=681, Head=681, BUFFER_SIZE-1=FFFF
-From while: Tail=683, Head=681
-
-????? What the FUCK ?????
-
-& when I uncomment the lines below spin++; it *doesn't* lock here... WTF?????
-
-I think it was missing parentheses causing the fuckup... Seems to work now...
-
-Except for Super Burnout now...! Aarrrgggghhhhh!
-
-Tail=AC, Head=AE
-Stuck in left DAC spinlock! Aborting!
-Tail=AC, Head=AE, BUFFER_SIZE-1=FFFF
-From while: Tail=AE, Head=AE
-
-So it's *really* stuck here in the left FIFO. Figure out why!!!
-
-Prolly 'cause it doesn't set the sample rate right away--betcha it works with the BIOS...
-It gets farther, but then locks here (weird!):
-
-Tail=2564, Head=2566
-Stuck in left DAC spinlock! Aborting!
-Tail=2564, Head=2566, BUFFER_SIZE-1=FFFF
-From while: Tail=2566, Head=2566
-
-Weird--recompile with more WriteLog() entries and it *doesn't* lock...
-Yeah, because there was no DSP running. Duh!
-
-Tail=AC, Head=AE
-Stuck in left DAC spinlock! Aborting!
-LTail=AC, LHead=AE, BUFFER_SIZE-1=FFFF
-RTail=AF, RHead=AF, BUFFER_SIZE-1=FFFF
-From while: Tail=AE, Head=AE
-
-Odd: The right FIFO is empty, but the left FIFO is full!
-And this is what is causing the lockup--the DAC callback waits for the side with
-less samples ready and in this case it's the right channel (that never fills up)
-that it's waiting for...!
-
-Okay, with the kludge in place for the right channel not being filled, we select
-a track and then it locks here:
-
-Tail=60D8, Head=60DA
-Stuck in left DAC spinlock! Aborting!
-LTail=60D8, LHead=60D8, BUFFER_SIZE-1=FFFF
-RTail=DB, RHead=60D9, BUFFER_SIZE-1=FFFF
-From while: Tail=60DA, Head=60D8
-*/
-#ifdef NEW_DAC_CODE
rtxd = data;
-#else
-#warning Spinlock problem--!!! FIX !!!
-#warning Odd: The right FIFO is empty, but the left FIFO is full!
- // Spin until buffer has been drained (for too fast processors!)...
-uint32 spin = 0;
- while (((RightFIFOTailPtr + 2) & (BUFFER_SIZE - 1)) == RightFIFOHeadPtr)//;
- {
-spin++;
-//if ((spin & 0x0FFFFFFF) == 0)
-// WriteLog("Tail=%X, Head=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
-
-if (spin == 0xFFFF0000)
-{
-uint32 rtail = RightFIFOTailPtr, rhead = RightFIFOHeadPtr;
-WriteLog("Tail=%X, Head=%X", rtail, rhead);
-
- WriteLog("\nStuck in right DAC spinlock! Aborting!\n");
- WriteLog("LTail=%X, LHead=%X, BUFFER_SIZE-1=%X\n", LeftFIFOTailPtr, LeftFIFOHeadPtr, BUFFER_SIZE - 1);
- WriteLog("RTail=%X, RHead=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
- WriteLog("From while: Tail=%X, Head=%X", (RightFIFOTailPtr + 2) & (BUFFER_SIZE - 1), RightFIFOHeadPtr);
-// LogDone();
-// exit(0);
-#warning "Reimplement GUICrashGracefully!"
-// GUICrashGracefully("Stuck in right DAC spinlock!");
- return;
-}
- }//*/
-
- SDL_LockAudio();
- RightFIFOTailPtr = (RightFIFOTailPtr + 2) % BUFFER_SIZE;
- DACBuffer[RightFIFOTailPtr] = data;
- SDL_UnlockAudio();
-/*#ifdef DEBUG_DAC
- else
- WriteLog("DAC: Ran into FIFO's right tail pointer!\n");
-#endif*/
-#endif
}
else if (offset == SCLK + 2) // Sample rate
{
WriteLog("DAC: Writing %u to SCLK...\n", data);
+
if ((uint8)data != SCLKFrequencyDivider)
- {
SCLKFrequencyDivider = (uint8)data;
-#ifdef NEW_DAC_CODE
-#else
-//Of course a better way would be to query the hardware to find the upper limit...
- if (data > 7) // Anything less than 8 is too high!
- {
- if (SDLSoundInitialized)
- SDL_CloseAudio();
-
- desired.freq = GetCalculatedFrequency();// SDL will do conversion on the fly, if it can't get the exact rate. Nice!
- WriteLog("DAC: Changing sample rate to %u Hz!\n", desired.freq);
-
- if (SDLSoundInitialized)
- {
- if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
- {
-// This is bad, Bad, BAD !!! DON'T ABORT BECAUSE WE DIDN'T GET OUR FREQ! !!! FIX !!!
-#warning !!! FIX !!! Aborting because of SDL audio problem is bad!
- WriteLog("DAC: Failed to initialize SDL sound: %s.\nDesired freq: %u\nShutting down!\n", SDL_GetError(), desired.freq);
-// LogDone();
-// exit(1);
-#warning "Reimplement GUICrashGracefully!"
-// GUICrashGracefully("Failed to initialize SDL sound!");
- return;
- }
- }
-
- DACReset();
-
- if (SDLSoundInitialized)
- SDL_PauseAudio(false); // Start playback!
- }
-#endif
- }
}
else if (offset == SMODE + 2)
{
#ifndef __DAC_H__
#define __DAC_H__
-//this is here, because we have to compensate in more than just dac.cpp...
-#define NEW_DAC_CODE // New code paths!
-
-//#include "types.h"
#include "memory.h"
void DACInit(void);
void DACReset(void);
void DACDone(void);
-int GetCalculatedFrequency(void);
-void DACSetNewFrequency(int);
+//int GetCalculatedFrequency(void);
// DAC memory access
uint8 DACReadByte(uint32 offset, uint32 who = UNKNOWN);
uint16 DACReadWord(uint32 offset, uint32 who = UNKNOWN);
-// Global variables
-
-//extern uint16 lrxd, rrxd; // I2S ports (into Jaguar)
-
#endif // __DAC_H__
// IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
// It seems that it's only stable for values of SCLK <= 9.
+// All of the preceeding is moot now; we run the DSP in the host audio IRQ. This means
+// that we don't actually need this stuff anymore. :-D
+#if 0
if (data & INT_ENA1) // I2S interrupt
{
int freq = GetCalculatedFrequency();
// WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
DACSetNewFrequency(freq);
}
+#endif
/* if (IMASKCleared) // If IMASK was cleared,
#ifdef DSP_DEBUG_IRQ
// directory, copy the one from the ZIP file, if it exists.
EepromInit();
jaguarRunAddress = 0x802000; // For non-BIOS runs, this is true
- int fileType = ParseFileType(buffer[0], buffer[1], jaguarROMSize);
+ int fileType = ParseFileType(buffer, jaguarROMSize);
jaguarCartInserted = false;
if (fileType == JST_ROM)
jaguarRunAddress = runAddress;
return true;
}
+ // NB: This is *wrong*
+ /*
+ Basically, if there is no "JAG" at position $1C, then the long there is the load/start
+ address in LITTLE ENDIAN.
+ If "JAG" is present, the the next character ("R" or "L") determines the size of the
+ JagServer command (2 bytes vs. 4). Following that are the commands themselves;
+ typically it will either be 2 (load) or 3 (load & run). Command headers go like so:
+ 2:
+ Load address (long)
+ Length (long)
+ payload
+ 3:
+ Load address (long)
+ Length (long)
+ Run address (long)
+ payload
+ 5: (Reset)
+ [command only]
+ 7: (Run at address)
+ Run address (long)
+ [no payload]
+ 9: (Clear memory)
+ Start address (long)
+ End address (long)
+ [no payload]
+ 10: (Poll for commands)
+ [command only]
+ 12: (Load & run user program)
+ filname, terminated with NULL
+ [no payload]
+ $FFFF: (Halt)
+ [no payload]
+ */
else if (fileType == JST_JAGSERVER)
{
- uint32 loadAddress = GET32(buffer, 0x22), runAddress = GET32(buffer, 0x2A);
- WriteLog("FILE: Setting up homebrew (Jag Server)... Run address: %08X, length: %08X\n", runAddress, jaguarROMSize - 0x2E);
- memcpy(jagMemSpace + loadAddress, buffer + 0x2E, jaguarROMSize - 0x2E);
+ // This kind of shiaut should be in the detection code below...
+ // (and now it is! :-)
+// if (buffer[0x1C] == 'J' && buffer[0x1D] == 'A' && buffer[0x1E] == 'G')
+// {
+ // Still need to do some checking here for type 2 vs. type 3. This assumes 3
+ // Also, JAGR vs. JAGL (word command size vs. long command size)
+ uint32 loadAddress = GET32(buffer, 0x22), runAddress = GET32(buffer, 0x2A);
+ WriteLog("FILE: Setting up homebrew (Jag Server)... Run address: $%X, length: $%X\n", runAddress, jaguarROMSize - 0x2E);
+ memcpy(jagMemSpace + loadAddress, buffer + 0x2E, jaguarROMSize - 0x2E);
+ delete[] buffer;
+ jaguarRunAddress = runAddress;
+ return true;
+// }
+// else // Special WTFOMGBBQ type here...
+// {
+// uint32_t loadAddress = (buffer[0x1F] << 24) | (buffer[0x1E] << 16) | (buffer[0x1D] << 8) | buffer[0x1C];
+// WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress, jaguarROMSize - 0x20);
+// memcpy(jagMemSpace + loadAddress, buffer + 0x20, jaguarROMSize - 0x20);
+// delete[] buffer;
+// jaguarRunAddress = loadAddress;
+// return true;
+// }
+ }
+ else if (fileType == JST_WTFOMGBBQ)
+ {
+ uint32_t loadAddress = (buffer[0x1F] << 24) | (buffer[0x1E] << 16) | (buffer[0x1D] << 8) | buffer[0x1C];
+ WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress, jaguarROMSize - 0x20);
+ memcpy(jagMemSpace + loadAddress, buffer + 0x20, jaguarROMSize - 0x20);
delete[] buffer;
- jaguarRunAddress = runAddress;
+ jaguarRunAddress = loadAddress;
return true;
}
//
// Parse the file type based upon file size and/or headers.
//
-uint32 ParseFileType(uint8 header1, uint8 header2, uint32 size)
+uint32 ParseFileType(uint8_t * buffer, uint32 size)
{
// Check headers first...
// ABS/COFF type 1
- if (header1 == 0x60 && header2 == 0x1B)
+ if (buffer[0] == 0x60 && buffer[1] == 0x1B)
return JST_ABS_TYPE1;
// ABS/COFF type 2
- if (header1 == 0x01 && header2 == 0x50)
+ if (buffer[0] == 0x01 && buffer[1] == 0x50)
return JST_ABS_TYPE2;
- // Jag Server
- if (header1 == 0x60 && header2 == 0x1A)
- return JST_JAGSERVER;
+ // Jag Server & other old shite
+ if (buffer[0] == 0x60 && buffer[1] == 0x1A)
+ {
+ if (buffer[0x1C] == 'J' && buffer[0x1D] == 'A' && buffer[0x1E] == 'G')
+ return JST_JAGSERVER;
+ else
+ return JST_WTFOMGBBQ;
+ }
// And if that fails, try file sizes...
enum FileType { FT_SOFTWARE=0, FT_EEPROM, FT_LABEL, FT_BOXART, FT_OVERLAY };
// JST = Jaguar Software Type
-enum { JST_NONE = 0, JST_ROM, JST_ALPINE, JST_ABS_TYPE1, JST_ABS_TYPE2, JST_JAGSERVER };
+enum { JST_NONE = 0, JST_ROM, JST_ALPINE, JST_ABS_TYPE1, JST_ABS_TYPE2, JST_JAGSERVER, JST_WTFOMGBBQ };
uint32 JaguarLoadROM(uint8 * &rom, char * path);
bool JaguarLoadFile(char * path);
bool AlpineLoadFile(char * path);
uint32 GetFileFromZIP(const char * zipFile, FileType type, uint8 * &buffer);
-uint32 ParseFileType(uint8 header1, uint8 header2, uint32 size);
+uint32 ParseFileType(uint8_t * buffer, uint32 size);
bool HasUniversalHeader(uint8 * rom, uint32 romSize);
#ifdef __cplusplus
// JLH 12/23/2009 Created this file
// JLH 01/21/2011 Added SDL initialization
// JLH 06/26/2011 Added fix to keep SDL from hijacking main() on win32
+// JLH 05/24/2012 Added option switches
//
#include "app.h"
#include "mainwin.h"
#include "settings.h"
#include "types.h"
+#include "version.h"
+
-#ifdef __GCCWIN32__
// Apparently on win32, SDL is hijacking main from Qt. So let's do this:
+#ifdef __GCCWIN32__
#undef main
#endif
+// Function prototypes...
+static bool ParseCommandLine(int argc, char * argv[]);
+static void ParseOptions(int argc, char * argv[]);
+
+
//hm. :-/
// This is stuff we pass into the mainWindow...
bool noUntunedTankPlease = false;
bool loadAndGo = false;
+bool useLogfile = true;
QString filename;
// Here's the main application loop--short and simple...
// This is stuff we pass into the mainWindow...
// noUntunedTankPlease = false;
- if (argc > 1)
- {
- if ((strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0)
- || (strcmp(argv[1], "-?") == 0))
- {
- printf("Virtual Jaguar 2.0.0 help\n");
- printf("\n");
- printf("Command line interface is mostly non-functional ATM, but may return if\n"
- "there is enough demand for it. :-)\n");
- return 0;
- }
-
- if (strcmp(argv[1], "--yarrr") == 0)
- {
- printf("\n");
- printf("Shiver me timbers!\n");
- printf("\n");
- return 0;
- }
-
- if ((strcmp(argv[1], "--alpine") == 0) || (strcmp(argv[1], "-a") == 0))
- {
- printf("Alpine Mode enabled.\n");
- vjs.hardwareTypeAlpine = true;
- }
-
- if (strcmp(argv[1], "--please-dont-kill-my-computer") == 0)
- {
- noUntunedTankPlease = true;
- }
-
- // Check for filename
- if (argv[1][0] != '-')
- {
- loadAndGo = true;
- filename = argv[1];
- }
- }
+ // Check for options that must be in place be constructing the App object
+ if (!ParseCommandLine(argc, argv))
+ return 0;
Q_INIT_RESOURCE(virtualjaguar); // This must the same name as the exe filename
//or is it the .qrc filename???
// This is so we can pass this stuff using signal/slot mechanism...
+//this is left here to remind me not to try doing this again :-P
//ick int id = qRegisterMetaType<uint32>();
- bool success = (bool)LogInit("virtualjaguar.log"); // Init logfile
int retVal = -1; // Default is failure
- if (!success)
- printf("Failed to open virtualjaguar.log for writing!\n");
+ if (useLogfile)
+ {
+ bool success = (bool)LogInit("./virtualjaguar.log"); // Init logfile
+
+ if (!success)
+ printf("Failed to open virtualjaguar.log for writing!\n");
+ }
// Set up SDL library
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0)
return retVal;
}
-// Main app constructor--we stick globally accessible stuff here...
-
+//
+// Main app constructor--we stick globally accessible stuff here... (?)
+//
App::App(int argc, char * argv[]): QApplication(argc, argv)
{
- mainWindow = new MainWin(filename);
+ bool loadAndGo = !filename.isEmpty();
+
+ mainWindow = new MainWin(loadAndGo);
mainWindow->plzDontKillMyComputer = noUntunedTankPlease;
+ ParseOptions(argc, argv); // Override defaults with command line (if any)
+ mainWindow->SyncUI();
+
+ if (loadAndGo)
+ mainWindow->LoadFile(filename);
+
mainWindow->show();
}
+
+
+//
+// Here we parse out stuff that needs to be looked at *before* we construct the
+// App object.
+//
+bool ParseCommandLine(int argc, char * argv[])
+{
+ for(int i=1; i<argc; i++)
+ {
+ if ((strcmp(argv[i], "--help") == 0) || (strcmp(argv[i], "-h") == 0)
+ || (strcmp(argv[i], "-?") == 0))
+ {
+ printf(
+ "Virtual Jaguar " VJ_RELEASE_VERSION " (" VJ_RELEASE_SUBVERSION ")\n"
+ "Based upon Virtual Jaguar core v1.0.0 by David Raingeard.\n"
+ "Written by Niels Wagenaar (Linux/WIN32), Carwin Jones (BeOS),\n"
+ "James Hammons (Linux/WIN32) and Adam Green (MacOS)\n"
+ "Contact: http://sdlemu.ngemu.com/ | sdlemu@ngemu.com\n"
+ "\n"
+ "Usage:\n"
+ " virtualjaguar [<filename>] [switches]\n"
+ "\n"
+ " Option Description\n"
+ " ---------------- -----------------------------------\n"
+ " <filename> Name of file to autoload\n"
+ " --alpine -a Put Virtual Jaguar into Alpine mode\n"
+ " --pal -p PAL mode\n"
+ " --ntsc -n NTSC mode\n"
+ " --bios -b Boot using Jagaur BIOS\n"
+ " --no-bios Do not use Jaguar BIOS\n"
+ " --gpu -g Enable GPU\n"
+ " --no-gpu Disable GPU\n"
+ " --dsp -d Enable DSP\n"
+ " --no-dsp Disable DSP\n"
+ " --fullscreen -f Start in full screen mode\n"
+ " --blur -B Enable GL bilinear filter\n"
+ " --no-blur Disable GL bilinear filtering\n"
+ " --log -l Create and use log file\n"
+ " --no-log Do not use log file\n"
+ " --help -h Show this message\n"
+ "\n"
+ "Invoking Virtual Jagaur with no filename will cause it to boot up\n"
+ "with the VJ GUI.\n"
+ "\n");
+ return false;
+ }
+
+ if (strcmp(argv[i], "--yarrr") == 0)
+ {
+ printf("\n");
+ printf("Shiver me timbers!\n");
+ printf("\n");
+ return false;
+ }
+
+ if ((strcmp(argv[i], "--alpine") == 0) || (strcmp(argv[i], "-a") == 0))
+ {
+ printf("Alpine Mode enabled.\n");
+ vjs.hardwareTypeAlpine = true;
+ }
+
+ if (strcmp(argv[i], "--please-dont-kill-my-computer") == 0)
+ {
+ noUntunedTankPlease = true;
+ }
+
+ if ((strcmp(argv[i], "--log") == 0) || (strcmp(argv[i], "-l") == 0))
+ {
+ useLogfile = true;
+ }
+
+ if (strcmp(argv[i], "--no-log") == 0)
+ {
+ useLogfile = false;
+ }
+
+ // Check for filename
+ if (argv[i][0] != '-')
+ {
+ loadAndGo = true;
+ filename = argv[i];
+ }
+ }
+
+ return true;
+}
+
+
+//
+// This is to override settings loaded from the config file.
+// Note that settings set here will become the new defaults!
+//
+void ParseOptions(int argc, char * argv[])
+{
+ for(int i=1; i<argc; i++)
+ {
+ if ((strcmp(argv[i], "--pal") == 0) || (strcmp(argv[i], "-p") == 0))
+ {
+ vjs.hardwareTypeNTSC = false;
+ }
+
+ if ((strcmp(argv[i], "--ntsc") == 0) || (strcmp(argv[i], "-n") == 0))
+ {
+ vjs.hardwareTypeNTSC = true;
+ }
+
+ if ((strcmp(argv[i], "--bios") == 0) || (strcmp(argv[i], "-b") == 0))
+ {
+ vjs.useJaguarBIOS = true;
+ }
+
+ if (strcmp(argv[i], "--no-bios") == 0)
+ {
+ vjs.useJaguarBIOS = false;
+ }
+
+ if ((strcmp(argv[i], "--gpu") == 0) || (strcmp(argv[i], "-g") == 0))
+ {
+ vjs.GPUEnabled = true;
+ }
+
+ if (strcmp(argv[i], "--no-gpu") == 0)
+ {
+ vjs.GPUEnabled = false;
+ }
+
+ if ((strcmp(argv[i], "--dsp") == 0) || (strcmp(argv[i], "-d") == 0))
+ {
+ vjs.DSPEnabled = true;
+ vjs.audioEnabled = true;
+ }
+
+ if (strcmp(argv[i], "--no-dsp") == 0)
+ {
+ vjs.DSPEnabled = false;
+ vjs.audioEnabled = false;
+ }
+
+ if ((strcmp(argv[i], "--fullscreen") == 0) || (strcmp(argv[i], "-f") == 0))
+ {
+ vjs.fullscreen = true;
+ }
+
+ if ((strcmp(argv[i], "--blur") == 0) || (strcmp(argv[i], "-B") == 0))
+ {
+ vjs.glFilter = 1;
+ }
+
+ if (strcmp(argv[i], "--no-blur") == 0)
+ {
+ vjs.glFilter = 0;
+ }
+ }
+}
+
+#if 0
+ bool useJoystick;
+ int32 joyport; // Joystick port
+ bool hardwareTypeNTSC; // Set to false for PAL
+ bool useJaguarBIOS;
+ bool GPUEnabled;
+ bool DSPEnabled;
+ bool usePipelinedDSP;
+ bool fullscreen;
+ bool useOpenGL;
+ uint32 glFilter;
+ bool hardwareTypeAlpine;
+ bool audioEnabled;
+ uint32 frameSkip;
+ uint32 renderType;
+ bool allowWritesToROM;
+
+ // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, *
+
+ uint32 p1KeyBindings[21];
+ uint32 p2KeyBindings[21];
+
+ // Paths
+
+ char ROMPath[MAX_PATH];
+ char jagBootPath[MAX_PATH];
+ char CDBootPath[MAX_PATH];
+ char EEPROMPath[MAX_PATH];
+ char alpineROMPath[MAX_PATH];
+ char absROMPath[MAX_PATH];
+#endif
cart = QImage(":/res/alpine-file.png");
}
else if (haveUnknown && (fileType == JST_ABS_TYPE1 || fileType == JST_ABS_TYPE2
- || fileType == JST_JAGSERVER))
+ || fileType == JST_JAGSERVER) || fileType == JST_WTFOMGBBQ)
{
cart = QImage(":/res/homebrew-file.png");
}
}
// Try to divine the file type by size & header
- int fileType = ParseFileType(buffer[0], buffer[1], fileSize);
+ int fileType = ParseFileType(buffer, fileSize);
// Check for Alpine ROM w/Universal Header
bool foundUniversalHeader = HasUniversalHeader(buffer, fileSize);
#include "jagstub2bios.h"
#include "joystick.h"
-#ifdef __GCCWIN32__
+// According to SebRmv, this header isn't seen on Arch Linux either... :-/
+//#ifdef __GCCWIN32__
// Apparently on win32, usleep() is not pulled in by the usual suspects.
#include <unistd.h>
-#endif
+//#endif
// The way BSNES controls things is by setting a timer with a zero
// timeout, sleeping if not emulating anything. Seems there has to be a
// We'll make the VJ core modular so that it doesn't matter what GUI is in
// use, we can drop it in anywhere and use it as-is.
-MainWin::MainWin(QString filenameToRun): running(true), powerButtonOn(false),
+//MainWin::MainWin(QString filenameToRun): running(true), powerButtonOn(false),
+MainWin::MainWin(bool autoRun): running(true), powerButtonOn(false),
showUntunedTankCircuit(true), cartridgeLoaded(false), CDActive(false),
//, alpineLoadSuccessful(false),
- pauseForFileSelector(false), loadAndGo(false), plzDontKillMyComputer(false)
+// pauseForFileSelector(false), loadAndGo(false), plzDontKillMyComputer(false)
+ pauseForFileSelector(false), loadAndGo(autoRun), plzDontKillMyComputer(false)
{
+ for(int i=0; i<8; i++)
+ keyHeld[i] = false;
+
videoWidget = new GLWidget(this);
setCentralWidget(videoWidget);
setWindowIcon(QIcon(":/res/vj-icon.png"));
ReadSettings();
- // Set toolbar buttons/menus based on settings read in (sync the UI)...
- blurAct->setChecked(vjs.glFilter);
- x1Act->setChecked(zoomLevel == 1);
- x2Act->setChecked(zoomLevel == 2);
- x3Act->setChecked(zoomLevel == 3);
-// running = powerAct->isChecked();
- ntscAct->setChecked(vjs.hardwareTypeNTSC);
- palAct->setChecked(!vjs.hardwareTypeNTSC);
- powerAct->setIcon(vjs.hardwareTypeNTSC ? powerRed : powerGreen);
-
// Do this in case original size isn't correct (mostly for the first-run case)
ResizeMainWindow();
memcpy(jagMemSpace + 0xE00000, jaguarBootROM, 0x20000); // Use the stock BIOS
// Check for filename passed in on the command line...
- if (!filenameToRun.isEmpty())
+// if (!filenameToRun.isEmpty())
+ if (autoRun)
{
- loadAndGo = true;
+// loadAndGo = true;
// Attempt to load/run the file the user passed in...
- LoadSoftware(filenameToRun);
-// memcpy(jagMemSpace + 0xE00000, jaguarBootROM, 0x20000); // Use the stock BIOS
- // Prevent the scanner from running...
+// LoadSoftware(filenameToRun);
+//// memcpy(jagMemSpace + 0xE00000, jaguarBootROM, 0x20000); // Use the stock BIOS
+ // Prevent the file scanner from running...
return;
}
filePickWin->ScanSoftwareFolder(allowUnknownSoftware);
}
+
+void MainWin::LoadFile(QString file)
+{
+ LoadSoftware(file);
+}
+
+
+void MainWin::SyncUI(void)
+{
+ // Set toolbar buttons/menus based on settings read in (sync the UI)...
+ blurAct->setChecked(vjs.glFilter);
+ x1Act->setChecked(zoomLevel == 1);
+ x2Act->setChecked(zoomLevel == 2);
+ x3Act->setChecked(zoomLevel == 3);
+// running = powerAct->isChecked();
+ ntscAct->setChecked(vjs.hardwareTypeNTSC);
+ palAct->setChecked(!vjs.hardwareTypeNTSC);
+ powerAct->setIcon(vjs.hardwareTypeNTSC ? powerRed : powerGreen);
+}
+
+
void MainWin::closeEvent(QCloseEvent * event)
{
JaguarDone();
- WriteSettings();
+// This should only be done by the config dialog
+// WriteSettings();
+ WriteUISettings();
event->accept(); // ignore() if can't close for some reason
}
+
void MainWin::keyPressEvent(QKeyEvent * e)
{
// We ignore the Alt key for now, since it causes problems with the GUI
HandleKeys(e, true);
}
+
void MainWin::keyReleaseEvent(QKeyEvent * e)
{
// We ignore the Alt key for now, since it causes problems with the GUI
HandleKeys(e, false);
}
+
void MainWin::HandleKeys(QKeyEvent * e, bool state)
{
+ enum { P1LEFT = 0, P1RIGHT, P1UP, P1DOWN, P2LEFT, P2RIGHT, P2UP, P2DOWN };
// We kill bad key combos here, before they can get to the emulator...
// This also kills the illegal instruction problem that cropped up in Rayman!
// May want to do this by killing the old one instead of ignoring the new one...
// Seems to work better that way...
+
+// The problem with this approach is that it causes bad results because it doesn't do
+// any checking of previous states. Need to come up with something better because this
+// causes problems where the keyboard acts as if it were unresponsive. :-P
#if 0
if ((e->key() == vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R])
|| (e->key() == vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L])
|| (e->key() == vjs.p1KeyBindings[BUTTON_D] && joypad_0_buttons[BUTTON_U]))
return;
#else
+#if 0
if (e->key() == (int)vjs.p1KeyBindings[BUTTON_L] && joypad_0_buttons[BUTTON_R])
joypad_0_buttons[BUTTON_R] = 0;
if (e->key() == (int)vjs.p1KeyBindings[BUTTON_R] && joypad_0_buttons[BUTTON_L])
joypad_1_buttons[BUTTON_D] = 0;
if (e->key() == (int)vjs.p2KeyBindings[BUTTON_D] && joypad_1_buttons[BUTTON_U])
joypad_1_buttons[BUTTON_U] = 0;
+#else
+//hrm, this still has sticky state problems... Ugh!
+ // First, settle key states...
+ if (e->key() == (int)vjs.p1KeyBindings[BUTTON_L])
+ keyHeld[P1LEFT] = state;
+ else if (e->key() == (int)vjs.p1KeyBindings[BUTTON_R])
+ keyHeld[P1RIGHT] = state;
+ else if (e->key() == (int)vjs.p1KeyBindings[BUTTON_U])
+ keyHeld[P1UP] = state;
+ else if (e->key() == (int)vjs.p1KeyBindings[BUTTON_D])
+ keyHeld[P1DOWN] = state;
+ else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_L])
+ keyHeld[P2LEFT] = state;
+ else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_R])
+ keyHeld[P2RIGHT] = state;
+ else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_U])
+ keyHeld[P2UP] = state;
+ else if (e->key() == (int)vjs.p2KeyBindings[BUTTON_D])
+ keyHeld[P2DOWN] = state;
+
+ // Next, check for conflicts and bail out if there are any...
+ if ((keyHeld[P1LEFT] && keyHeld[P1RIGHT])
+ || (keyHeld[P1UP] && keyHeld[P1DOWN])
+ || (keyHeld[P2LEFT] && keyHeld[P2RIGHT])
+ || (keyHeld[P2UP] && keyHeld[P2DOWN]))
+ return;
+#endif
#endif
// No bad combos exist, let's stuff the emulator key buffers...!
}
}
+
void MainWin::Open(void)
{
}
+
void MainWin::Configure(void)
{
// Call the configuration dialog and update settings
WriteSettings();
}
+
//
// Here's the main emulator loop
//
videoWidget->updateGL();
}
+
void MainWin::TogglePowerState(void)
{
powerButtonOn = !powerButtonOn;
}
}
+
void MainWin::ToggleRunState(void)
{
running = !running;
}
}
+
void MainWin::SetZoom100(void)
{
zoomLevel = 1;
ResizeMainWindow();
}
+
void MainWin::SetZoom200(void)
{
zoomLevel = 2;
ResizeMainWindow();
}
+
void MainWin::SetZoom300(void)
{
zoomLevel = 3;
ResizeMainWindow();
}
+
void MainWin::SetNTSC(void)
{
powerAct->setIcon(powerRed);
timer->setInterval(16);
vjs.hardwareTypeNTSC = true;
ResizeMainWindow();
+ WriteSettings();
}
+
void MainWin::SetPAL(void)
{
powerAct->setIcon(powerGreen);
timer->setInterval(20);
vjs.hardwareTypeNTSC = false;
ResizeMainWindow();
+ WriteSettings();
}
+
void MainWin::ToggleBlur(void)
{
vjs.glFilter = !vjs.glFilter;
+ WriteSettings();
}
+
void MainWin::ShowAboutWin(void)
{
aboutWin->show();
}
+
void MainWin::ShowHelpWin(void)
{
helpWin->show();
}
+
void MainWin::InsertCart(void)
{
// If the emulator is running, we pause it here and unpause it later
filePickWin->show();
}
+
void MainWin::Unpause(void)
{
// Here we unpause the emulator if it was paused when we went into the file selector
}
}
+
void MainWin::LoadSoftware(QString file)
{
running = false; // Prevent bad things(TM) from happening...
}
}
+
void MainWin::ToggleCDUsage(void)
{
CDActive = !CDActive;
#endif
}
+
void MainWin::FrameAdvance(void)
{
//printf("Frame Advance...\n");
videoWidget->updateGL();
}
+
void MainWin::ResizeMainWindow(void)
{
videoWidget->setFixedSize(zoomLevel * 320, zoomLevel * (vjs.hardwareTypeNTSC ? 240 : 256));
}
}
+
#warning "!!! Need to check the window geometry to see if the positions are legal !!!"
// i.e., someone could drag it to another screen, close it, then disconnect that screen
void MainWin::ReadSettings(void)
vjs.p2KeyBindings[BUTTON_s] = settings.value("p2k_star", Qt::Key_Asterisk).toInt();
}
+
void MainWin::WriteSettings(void)
{
QSettings settings("Underground Software", "Virtual Jaguar");
settings.setValue("p2k_pound", vjs.p2KeyBindings[BUTTON_d]);
settings.setValue("p2k_star", vjs.p2KeyBindings[BUTTON_s]);
}
+
+
+void MainWin::WriteUISettings(void)
+{
+ QSettings settings("Underground Software", "Virtual Jaguar");
+ settings.setValue("pos", pos());
+ settings.setValue("size", size());
+ settings.setValue("cartLoadPos", filePickWin->pos());
+
+ settings.setValue("zoom", zoomLevel);
+}
Q_OBJECT
public:
- MainWin(QString);
+// MainWin(QString);
+ MainWin(bool);
+ void LoadFile(QString);
+ void SyncUI(void);
protected:
void closeEvent(QCloseEvent *);
void ResizeMainWindow(void);
void ReadSettings(void);
void WriteSettings(void);
+ void WriteUISettings(void);
// public:
GLWidget * videoWidget;
// bool alpineLoadSuccessful;
bool pauseForFileSelector;
bool loadAndGo;
+ bool keyHeld[8];
public:
bool plzDontKillMyComputer;
private:
JaguarDasm(0x802000, 6000);
WriteLog("\n");//*/
#endif
-/* WriteLog("\n\nM68000 disassembly at $4000...\n");
- JaguarDasm(0x4000, 10000);
+/* WriteLog("\n\nM68000 disassembly at $6004...\n");
+ JaguarDasm(0x6004, 10000);
WriteLog("\n");//*/
// WriteLog("\n\nM68000 disassembly at $802000...\n");
// JaguarDasm(0x802000, 0x1000);
if (vjs.GPUEnabled)
GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
-#ifndef NEW_DAC_CODE
- if (vjs.DSPEnabled)
- {
- if (vjs.usePipelinedDSP)
- DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
- else
- DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
- }
-#endif
-
HandleNextEvent();
}
while (!frameDone);
int LogInit(const char * path)
{
- log_stream = fopen(path, "wrt");
+ log_stream = fopen(path, "w");
if (log_stream == NULL)
return 0;
if (logSize > MAX_LOG_SIZE)
{
+ // Instead of dumping out, we just close the file and ignore any more output.
fflush(log_stream);
fclose(log_stream);
- // Instead of dumping out, we just close the file and ignore any more output.
log_stream = NULL;
-// exit(1);
- }//*/
+ }
va_end(arg);
fflush(log_stream); // Make sure that text is written!
ARFLAGS := -rs
# Note that we use optimization level 2 instead of 3--3 doesn't seem to gain much over 2
-CFLAGS := -MMD -O2 -ffast-math -fomit-frame-pointer -g
+#CFLAGS := -MMD -O2 -ffast-math -fomit-frame-pointer -g
+CFLAGS ?= -O2 -ffast-math -fomit-frame-pointer -g
+GCC_DEPS = -MMD
INCS := -I. -I./obj `sdl-config --cflags`
obj/m68kinterface.o \
obj/m68kdasm.o
-# obj/newcpu.o \
-
# Targets for convenience sake, not "real" targets
.PHONY: clean
obj/%.o: %.c
@echo -e "\033[01;33m***\033[00;32m Compiling $<...\033[00m"
- @$(CC) $(CFLAGS) $(INCS) -c $< -o $@
+# @$(CC) $(CFLAGS) $(INCS) -c $< -o $@
+ @$(CC) $(GCC_DEPS) $(CFLAGS) $(INCS) -c $< -o $@
obj/%.o: obj/%.c
@echo -e "\033[01;33m***\033[00;32m Compiling $<...\033[00m"
- @$(CC) $(CFLAGS) $(INCS) -c $< -o $@
+# @$(CC) $(CFLAGS) $(INCS) -c $< -o $@
+ @$(CC) $(GCC_DEPS) $(CFLAGS) $(INCS) -c $< -o $@
# Generated code
obj/gencpu: obj/cpudefs.c
@echo -e "\033[01;33m***\033[00;32m Generating gencpu...\033[00m"
- @$(CC) $(CFLAGS) gencpu.c readcpu.c obj/cpudefs.c -o obj/gencpu -I. -I./obj
+# @$(CC) $(CFLAGS) gencpu.c readcpu.c obj/cpudefs.c -o obj/gencpu -I. -I./obj
+ @$(CC) $(GCC_DEPS) $(CFLAGS) gencpu.c readcpu.c obj/cpudefs.c -o obj/gencpu -I. -I./obj
obj/cpudefs.c: obj/build68k
@echo -e "\033[01;33m***\033[00;32m Generating cpudefs.c...\033[00m"
obj/build68k: build68k.c
@echo -e "\033[01;33m***\033[00;32m Compiling build68k.c...\033[00m"
- @$(CC) $(CFLAGS) build68k.c -o obj/build68k
+# @$(CC) $(CFLAGS) build68k.c -o obj/build68k
+ @$(CC) $(GCC_DEPS) $(CFLAGS) build68k.c -o obj/build68k
clean:
@echo -ne "\033[01;33m***\033[00;32m Cleaning out the garbage...\033[00m"
printf(" -ntsc : Force VJ to NTSC mode \n");
printf("\nInvoking Virtual Jagaur with no ROM file will cause it to boot up\n");
printf("with the VJ GUI.\n");
- return 1;
+ return 1;
}
}