]> Shamusworld >> Repos - virtualjaguar/commitdiff
Added switch to disable untuned tank circuit, for slower computers.
authorShamus Hammons <jlhamm@acm.org>
Sun, 8 Apr 2012 16:26:53 +0000 (16:26 +0000)
committerShamus Hammons <jlhamm@acm.org>
Sun, 8 Apr 2012 16:26:53 +0000 (16:26 +0000)
src/dac.cpp
src/dsp.cpp
src/event.h
src/gui/app.cpp
src/gui/app.h
src/gui/mainwin.cpp
src/gui/mainwin.h
src/op.cpp

index 617918a13f725f248f9403a5bf6741706a77e4a8..983680791fccefe73613246120633f4bf8543e95 100644 (file)
 //       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
+// interrupt is not enabled/running on the DSP, then there is no audio. Also,
+// audio can be muted by clearing bit 8 of JOYSTICK (JOY1).
+//
+// Approach: We can run the DSP in the host system's audio IRQ, by running the
+// DSP for the alloted time (depending on the host buffer size & sample rate)
+// by simply reading the L/R_I2S (L/RTXD) registers at regular intervals. We
+// would also have to time the I2S/TIMER0/TIMER1 interrupts in the DSP as well.
+// This way, we can run the host audio IRQ at, say, 48 KHz and not have to care
+// so much about SCLK and running a separate buffer and all the attendant
+// garbage that comes with that awful approach.
+//
+// There would still be potential gotchas, as the SCLK can theoretically drive
+// the I2S at 26590906 / 2 (for SCLK == 0) = 13.3 MHz which corresponds to an
+// audio rate 416 KHz (dividing the I2S rate by 32, for 16-bit stereo). It
+// seems doubtful that anything useful could come of such a high rate, and we
+// can probably safely ignore any such ridiculously high audio rates. It won't
+// sound the same as on a real Jaguar, but who cares? :-)
+
 #include "dac.h"
 
 #include "SDL.h"
@@ -127,6 +148,16 @@ void DACDone(void)
        WriteLog("DAC: Done.\n");
 }
 
+
+// Approach: Run the DSP for however many cycles needed to correspond to whatever sample rate
+// we've set the audio to run at. So, e.g., if we run it at 48 KHz, then we would run the DSP
+// for however much time it takes to fill the buffer. So with a 2K buffer, this would correspond
+// to running the DSP for 0.042666... seconds. At 26590906 Hz, this would correspond to
+// running the DSP for 1134545 cycles. You would then sample the L/RTXD registers every
+// 1134545 / 2048 = 554 cycles to fill the buffer. You would also have to manage interrupt
+// timing as well (generating them at the proper times), but that shouldn't be too difficult...
+// If the DSP isn't running, then fill the buffer with L/RTXD and exit.
+
 //
 // SDL callback routine to fill audio buffer
 //
index aa12cf504457a1d08a1b8dbeb705b5c3d64a6c9e..a620775cea2c5945b7c3af8f998f4f342f33adf2 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <SDL.h>                                                               // Used only for SDL_GetTicks...
 #include <stdlib.h>
+#include <time.h>
 #include "dac.h"
 #include "gpu.h"
 #include "jagdasm.h"
@@ -779,7 +780,7 @@ SET32(ram2, offset, data);
                case 0x00:
                {
 #ifdef DSP_DEBUG
-                       WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
+                       WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
 #endif
 //                     bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
                        IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
@@ -797,6 +798,19 @@ SET32(ram2, offset, data);
 //     interrupt, so that's what we check for here. Just know that this approach
 //     can be easily fooled!
 //     Note also that if both interrupts are enabled, the I2S freq will win. :-P
+
+// Further Note:
+// The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
+// audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
+// So, while this works, it's a by-product of the lame way in which audio is currently
+// handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
+// go away of its own accord. :-P
+// Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
+// weird is going on here...
+// Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
+// So subsequent interrupts come into the chip, but they're never serviced but the
+// I2S subsystem keeps going.
+
                        if (data & INT_ENA1) // I2S interrupt
                        {
                                int freq = GetCalculatedFrequency();
@@ -872,7 +886,7 @@ if (who != DSP)
                case 0x14:
                {
 //#ifdef DSP_DEBUG
-WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
+WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
 //#endif
                        bool wasRunning = DSP_RUNNING;
 //                     uint32 dsp_was_running = DSP_RUNNING;
@@ -1271,6 +1285,7 @@ void DSPInit(void)
 
        dsp_build_branch_condition_table();
        DSPReset();
+       srandom(time(NULL));                                                    // For randomizing local RAM
 }
 
 void DSPReset(void)
@@ -1297,7 +1312,12 @@ void DSPReset(void)
        IMASKCleared = false;
        FlushDSPPipeline();
        dsp_reset_stats();
-       memset(dsp_ram_8, 0xFF, 0x2000);
+//     memset(dsp_ram_8, 0xFF, 0x2000);
+       // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
+       for(uint32 i=0; i<8192; i+=4)
+       {
+               *((uint32 *)(&dsp_ram_8[i])) = random();
+       }
 }
 
 void DSPDumpDisassembly(void)
@@ -1377,13 +1397,14 @@ void DSPDone(void)
                                                  (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
                                                  (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
                                                  (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
-
        }
 
+       WriteLog("\n");
+
        static char buffer[512];
        j = DSP_WORK_RAM_BASE;
 
-       while (j <= 0xF1BFFF)
+       while (j <= 0xF1CFFF)
        {
                uint32 oldj = j;
                j += dasmjag(JAGUAR_DSP, buffer, j);
index 9014dfb4e3f6f72df8e0395fea0841292c4d96ef..5565bec85af9a324134c2a6d2a7f6b6c2997da52 100644 (file)
@@ -1,7 +1,7 @@
 //
 // EVENT.H: System timing support functionality
 //
-// by James L. Hammons
+// by James Hammons
 //
 
 #ifndef __EVENT_H__
index 7c2037f3a81273eb34e9ec6ddce8ac4cde59fc03..6abfe15cddce199d28d6f4f2ec2ce1000c6e849b 100644 (file)
 #undef main
 #endif
 
+//hm. :-/
+// This is stuff we pass into the mainWindow...
+bool noUntunedTankPlease = false;
+
 // Here's the main application loop--short and simple...
 int main(int argc, char * argv[])
 {
        // Normally, this would be read in from the settings module... :-P
        vjs.hardwareTypeAlpine = false;
+       // This is stuff we pass into the mainWindow...
+//     noUntunedTankPlease = false;
 
        if (argc > 1)
        {
@@ -44,6 +50,7 @@ int main(int argc, char * argv[])
                                "there is enough demand for it. :-)\n");
                        return 0;
                }
+
                if (strcmp(argv[1], "--yarrr") == 0)
                {
                        printf("\n");
@@ -51,11 +58,17 @@ int main(int argc, char * argv[])
                        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;
+               }
        }
 
        Q_INIT_RESOURCE(virtualjaguar); // This must the same name as the exe filename
@@ -94,5 +107,6 @@ int main(int argc, char * argv[])
 App::App(int argc, char * argv[]): QApplication(argc, argv)
 {
        mainWindow = new MainWin();
+       mainWindow->plzDontKillMyComputer = noUntunedTankPlease;
        mainWindow->show();
 }
index 2b57845e5b1687c065f9fdc29e84d1815f97e2eb..9de170a7736900a177fea4351729369f3a6361cc 100644 (file)
@@ -21,6 +21,7 @@ class App: public QApplication
 
        private:
                MainWin * mainWindow;
+//             bool noUntunedTankPlease;
 
        // Globally accessible stuff goes here...
        // Although... Globally accessible stuff should go into settings.cpp...
index 56299f3a5d13d58a25459a5d7bc7a22542b663b2..ba0b21ebe09bc94f7e5db84ba6cc2a1ebe760a3b 100644 (file)
@@ -72,7 +72,7 @@
 
 MainWin::MainWin(): running(true), powerButtonOn(false), showUntunedTankCircuit(true),
        cartridgeLoaded(false), CDActive(false),//, alpineLoadSuccessful(false),
-       pauseForFileSelector(false)
+       pauseForFileSelector(false), plzDontKillMyComputer(false)
 {
        videoWidget = new GLWidget(this);
        setCentralWidget(videoWidget);
@@ -442,6 +442,9 @@ void MainWin::Timer(void)
 
        if (showUntunedTankCircuit)
        {
+               // Some machines can't handle this, so we give them the option to disable it. :-)
+               if (!plzDontKillMyComputer)
+               {
                // Random hash & trash
                // We try to simulate an untuned tank circuit here... :-)
                for(uint32_t x=0; x<videoWidget->rasterWidth; x++)
@@ -452,6 +455,7 @@ void MainWin::Timer(void)
                                        = (rand() & 0xFF) << 8 | (rand() & 0xFF) << 16 | (rand() & 0xFF) << 24;
                        }
                }
+               }
        }
        else
        {
index 30d9eb2b3183a01ebdb7d7a6cb66be94c8a2933c..37902b2f8929e4b173df5cac086f3bb30b7394cb 100644 (file)
@@ -71,7 +71,9 @@ class MainWin: public QMainWindow
                bool CDActive;
 //             bool alpineLoadSuccessful;
                bool pauseForFileSelector;
-
+       public:
+               bool plzDontKillMyComputer;
+       private:
                QMenu * fileMenu;
                QMenu * helpMenu;
                QToolBar * toolbar;
index 682c023edbdbe6d2b8b15c160d453d0cba627700..f9264c50a69d34e65a0f38bb70dae90731c4c452 100644 (file)
@@ -36,9 +36,9 @@
 #define OBJECT_TYPE_BRANCH     3                                       // 011
 #define OBJECT_TYPE_STOP       4                                       // 100
 
-#define CONDITION_EQUAL                                0
-#define CONDITION_LESS_THAN                    1
-#define CONDITION_GREATER_THAN         2
+#define CONDITION_EQUAL                                0                       // VC == YPOS
+#define CONDITION_LESS_THAN                    1                       // VC < YPOS
+#define CONDITION_GREATER_THAN         2                       // VC > YPOS
 #define CONDITION_OP_FLAG_SET          3
 #define CONDITION_SECOND_HALF_LINE     4