]> Shamusworld >> Repos - virtualjaguar/blob - src/dac.cpp
be6c3aed9e314853a679c13ba1ddc6720fcf2047
[virtualjaguar] / src / dac.cpp
1 //
2 // DAC (really, Synchronous Serial Interface) Handler
3 //
4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Rewritten by James Hammons
7 // (C) 2010 Underground Software
8 //
9 // JLH = James Hammons <jlhamm@acm.org>
10 //
11 // Who  When        What
12 // ---  ----------  -------------------------------------------------------------
13 // JLH  01/16/2010  Created this log ;-)
14 //
15
16 // Need to set up defaults that the BIOS sets for the SSI here in DACInit()... !!! FIX !!!
17 // or something like that... Seems like it already does, but it doesn't seem to
18 // work correctly...! Perhaps just need to set up SSI stuff so BUTCH doesn't get
19 // confused...
20
21 // ALSO: Need to implement some form of proper locking to replace the clusterfuck
22 //       that is the current spinlock implementation. Since the DSP is a separate
23 //       entity, could we get away with running it in the sound IRQ?
24
25 // ALSO: It may be a good idea to physically separate the left and right buffers
26 //       to prevent things like the DSP filling only one side and such. Do such
27 //       mono modes exist on the Jag? Seems to according to Super Burnout.
28
29 // After testing on a real Jaguar, it seems clear that the I2S interrupt drives
30 // the audio subsystem. So while you can drive the audio at a *slower* rate than
31 // set by SCLK, you can't drive it any *faster*. Also note, that if the I2S
32 // interrupt is not enabled/running on the DSP, then there is no audio. Also,
33 // audio can be muted by clearing bit 8 of JOYSTICK (JOY1).
34 //
35 // Approach: We can run the DSP in the host system's audio IRQ, by running the
36 // DSP for the alloted time (depending on the host buffer size & sample rate)
37 // by simply reading the L/R_I2S (L/RTXD) registers at regular intervals. We
38 // would also have to time the I2S/TIMER0/TIMER1 interrupts in the DSP as well.
39 // This way, we can run the host audio IRQ at, say, 48 KHz and not have to care
40 // so much about SCLK and running a separate buffer and all the attendant
41 // garbage that comes with that awful approach.
42 //
43 // There would still be potential gotchas, as the SCLK can theoretically drive
44 // the I2S at 26590906 / 2 (for SCLK == 0) = 13.3 MHz which corresponds to an
45 // audio rate 416 KHz (dividing the I2S rate by 32, for 16-bit stereo). It
46 // seems doubtful that anything useful could come of such a high rate, and we
47 // can probably safely ignore any such ridiculously high audio rates. It won't
48 // sound the same as on a real Jaguar, but who cares? :-)
49
50 #include "dac.h"
51
52 #include "SDL.h"
53 #include "cdrom.h"
54 #include "dsp.h"
55 #include "event.h"
56 #include "jerry.h"
57 #include "jaguar.h"
58 #include "log.h"
59 #include "m68k.h"
60 //#include "memory.h"
61 #include "settings.h"
62
63
64 //#define DEBUG_DAC
65
66 #define BUFFER_SIZE                     0x10000                         // Make the DAC buffers 64K x 16 bits
67 #define DAC_AUDIO_RATE          48000                           // Set the audio rate to 48 KHz
68
69 // Jaguar memory locations
70
71 #define LTXD                    0xF1A148
72 #define RTXD                    0xF1A14C
73 #define LRXD                    0xF1A148
74 #define RRXD                    0xF1A14C
75 #define SCLK                    0xF1A150
76 #define SMODE                   0xF1A154
77
78 // Global variables
79
80 //uint16 lrxd, rrxd;                                                    // I2S ports (into Jaguar)
81
82 // Local variables
83
84 static uint32 LeftFIFOHeadPtr, LeftFIFOTailPtr, RightFIFOHeadPtr, RightFIFOTailPtr;
85 static SDL_AudioSpec desired;
86 static bool SDLSoundInitialized;
87
88 // We can get away with using native endian here because we can tell SDL to use the native
89 // endian when looking at the sample buffer, i.e., no need to worry about it.
90
91 static uint16 DACBuffer[BUFFER_SIZE];
92 static uint8 SCLKFrequencyDivider = 19;                 // Default is roughly 22 KHz (20774 Hz in NTSC mode)
93 /*static*/ uint16 serialMode = 0;
94
95 // Private function prototypes
96
97 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
98 void SDLSoundCallbackNew(void * userdata, Uint8 * buffer, int length);
99 void DSPSampleCallback(void);
100
101
102 //
103 // Initialize the SDL sound system
104 //
105 void DACInit(void)
106 {
107         SDLSoundInitialized = false;
108
109         if (!vjs.audioEnabled)
110         {
111                 WriteLog("DAC: Host audio playback disabled.\n");
112                 return;
113         }
114
115 #ifdef NEW_DAC_CODE
116         desired.freq = DAC_AUDIO_RATE;
117         desired.format = AUDIO_S16SYS;
118         desired.channels = 2;
119         desired.samples = 2048;
120         desired.callback = SDLSoundCallbackNew;
121 #else
122 //      memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
123 //      DACBuffer = (uint16 *)memory_malloc(BUFFER_SIZE * sizeof(uint16), "DAC buffer");
124
125         desired.freq = GetCalculatedFrequency();                // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
126         desired.format = AUDIO_S16SYS;                                  // This uses the native endian (for portability)...
127         desired.channels = 2;
128 //      desired.samples = 4096;                                                 // Let's try a 4K buffer (can always go lower)
129         desired.samples = 2048;                                                 // Let's try a 2K buffer (can always go lower)
130         desired.callback = SDLSoundCallback;
131 #endif
132
133         if (SDL_OpenAudio(&desired, NULL) < 0)                  // NULL means SDL guarantees what we want
134                 WriteLog("DAC: Failed to initialize SDL sound...\n");
135         else
136         {
137                 SDLSoundInitialized = true;
138                 DACReset();
139                 SDL_PauseAudio(false);                                          // Start playback!
140                 WriteLog("DAC: Successfully initialized. Sample rate: %u\n", desired.freq);
141         }
142
143         ltxd = lrxd = desired.silence;
144
145         uint32_t riscClockRate = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL);
146         uint32_t cyclesPerSample = riscClockRate / DAC_AUDIO_RATE;
147         WriteLog("DAC: RISC clock = %u, cyclesPerSample = %u\n", riscClockRate, cyclesPerSample);
148 }
149
150
151 //
152 // Reset the sound buffer FIFOs
153 //
154 void DACReset(void)
155 {
156         LeftFIFOHeadPtr = LeftFIFOTailPtr = 0, RightFIFOHeadPtr = RightFIFOTailPtr = 1;
157         ltxd = lrxd = desired.silence;
158 }
159
160
161 //
162 // Close down the SDL sound subsystem
163 //
164 void DACDone(void)
165 {
166         if (SDLSoundInitialized)
167         {
168                 SDL_PauseAudio(true);
169                 SDL_CloseAudio();
170         }
171
172 //      memory_free(DACBuffer);
173         WriteLog("DAC: Done.\n");
174 }
175
176
177 // Approach: Run the DSP for however many cycles needed to correspond to whatever sample rate
178 // we've set the audio to run at. So, e.g., if we run it at 48 KHz, then we would run the DSP
179 // for however much time it takes to fill the buffer. So with a 2K buffer, this would correspond
180 // to running the DSP for 0.042666... seconds. At 26590906 Hz, this would correspond to
181 // running the DSP for 1134545 cycles. You would then sample the L/RTXD registers every
182 // 1134545 / 2048 = 554 cycles to fill the buffer. You would also have to manage interrupt
183 // timing as well (generating them at the proper times), but that shouldn't be too difficult...
184 // If the DSP isn't running, then fill the buffer with L/RTXD and exit.
185
186 //
187 // SDL callback routine to fill audio buffer
188 //
189 // Note: The samples are packed in the buffer in 16 bit left/16 bit right pairs.
190 //       Also, length is the length of the buffer in BYTES
191 //
192 //static double timePerSample = 0;
193 static Uint8 * sampleBuffer;
194 static int bufferIndex = 0;
195 static int numberOfSamples = 0;
196 static bool bufferDone = false;
197 void SDLSoundCallbackNew(void * userdata, Uint8 * buffer, int length)
198 {
199         // 1st, check to see if the DSP is running. If not, fill the buffer with L/RXTD and exit.
200
201         if (!DSPIsRunning())
202         {
203                 for(int i=0; i<(length/2); i+=2)
204                 {
205                         ((uint16_t *)buffer)[i + 0] = ltxd;
206                         ((uint16_t *)buffer)[i + 1] = rtxd;
207                 }
208
209                 return;
210         }
211
212         // The length of time we're dealing with here is 1/48000 s, so we multiply this
213         // by the number of cycles per second to get the number of cycles for one sample.
214         uint32_t riscClockRate = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL);
215         uint32_t cyclesPerSample = riscClockRate / DAC_AUDIO_RATE;
216         // This is the length of time
217 //      timePerSample = (1000000.0 / (double)riscClockRate) * ();
218
219         // Now, run the DSP for that length of time for each sample we need to make
220
221 #if 0
222         for(int i=0; i<(length/2); i+=2)
223         {
224 //This stuff is from the old Jaguar execute loop. New stuff is timer based...
225 //which means we need to figure that crap out, and how to make it work here.
226 //Seems like we need two separate timing queues. Tho not sure how to make that work here...
227 //Maybe like the "frameDone" in JaguarExecuteNew() in jaguar.cpp?
228 //              JERRYExecPIT(cyclesPerSample);
229 //              JERRYI2SExec(cyclesPerSample);
230 //              BUTCHExec(cyclesPerSample);
231
232                 if (vjs.DSPEnabled)
233                 {
234                         if (vjs.usePipelinedDSP)
235                                 DSPExecP2(cyclesPerSample);
236                         else
237                                 DSPExec(cyclesPerSample);
238                 }
239
240                 ((uint16_t *)buffer)[i + 0] = ltxd;
241                 ((uint16_t *)buffer)[i + 1] = rtxd;
242         }
243 #else
244         bufferIndex = 0;
245         sampleBuffer = buffer;
246         numberOfSamples = length / 2;
247         bufferDone = false;
248
249         SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY);
250
251         // These timings are tied to NTSC, need to fix that in event.cpp/h!
252         do
253         {
254                 double timeToNextEvent = GetTimeToNextEvent(EVENT_JERRY);
255
256                 if (vjs.DSPEnabled)
257                 {
258                         if (vjs.usePipelinedDSP)
259                                 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent));
260                         else
261                                 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
262                 }
263
264                 HandleNextEvent(EVENT_JERRY);
265         }
266         while (!bufferDone);
267
268         // We do this to prevent problems with trying to write past the end of the buffer...
269 //      RemoveCallback(DSPSampleCallback);
270 #endif
271 }
272
273
274 void DSPSampleCallback(void)
275 {
276         ((uint16_t *)sampleBuffer)[bufferIndex + 0] = ltxd;
277         ((uint16_t *)sampleBuffer)[bufferIndex + 1] = rtxd;
278         bufferIndex += 2;
279
280         if (bufferIndex == numberOfSamples)
281         {
282                 bufferDone = true;
283                 return;
284         }
285
286         SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY);
287 }
288 #if 0
289         frameDone = false;
290
291         do
292         {
293                 double timeToNextEvent = GetTimeToNextEvent();
294 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
295
296                 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
297
298                 if (vjs.GPUEnabled)
299                         GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
300
301 #ifndef NEW_DAC_CODE
302                 if (vjs.DSPEnabled)
303                 {
304                         if (vjs.usePipelinedDSP)
305                                 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent));        // Pipelined DSP execution (3 stage)...
306                         else
307                                 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));          // Ordinary non-pipelined DSP
308                 }
309 #endif
310
311                 HandleNextEvent();
312         }
313         while (!frameDone);
314 #endif
315
316
317 //
318 // SDL callback routine to fill audio buffer
319 //
320 // Note: The samples are packed in the buffer in 16 bit left/16 bit right pairs.
321 //       Also, length is the length of the buffer in BYTES
322 //
323 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
324 {
325         // Clear the buffer to silence, in case the DAC buffer is empty (or short)
326 //This causes choppy sound... Ick.
327         memset(buffer, desired.silence, length);
328 //WriteLog("DAC: Inside callback...\n");
329         if (LeftFIFOHeadPtr != LeftFIFOTailPtr)
330         {
331 //WriteLog("DAC: About to write some data!\n");
332                 int numLeftSamplesReady
333                         = (LeftFIFOTailPtr + (LeftFIFOTailPtr < LeftFIFOHeadPtr ? BUFFER_SIZE : 0))
334                                 - LeftFIFOHeadPtr;
335                 int numRightSamplesReady
336                         = (RightFIFOTailPtr + (RightFIFOTailPtr < RightFIFOHeadPtr ? BUFFER_SIZE : 0))
337                                 - RightFIFOHeadPtr;
338 //This waits for the slower side to catch up. If writing only one side, then this
339 //causes the buffer not to drain...
340                 int numSamplesReady
341                         = (numLeftSamplesReady < numRightSamplesReady
342                                 ? numLeftSamplesReady : numRightSamplesReady);//Hmm. * 2;
343
344 //Kludge, until I can figure out WTF is going on WRT Super Burnout.
345 if (numLeftSamplesReady == 0 || numRightSamplesReady == 0)
346         numSamplesReady = numLeftSamplesReady + numRightSamplesReady;
347
348 //The numbers look good--it's just that the DSP can't get enough samples in the DAC buffer!
349 //WriteLog("DAC: Left/RightFIFOHeadPtr: %u/%u, Left/RightFIFOTailPtr: %u/%u\n", LeftFIFOHeadPtr, RightFIFOHeadPtr, LeftFIFOTailPtr, RightFIFOTailPtr);
350 //WriteLog("     numLeft/RightSamplesReady: %i/%i, numSamplesReady: %i, length of buffer: %i\n", numLeftSamplesReady, numRightSamplesReady, numSamplesReady, length);
351
352 /*              if (numSamplesReady > length)
353                         numSamplesReady = length;//*/
354                 if (numSamplesReady > length / 2)       // length / 2 because we're comparing 16-bit lengths
355                         numSamplesReady = length / 2;
356 //else
357 //      WriteLog("     Not enough samples to fill the buffer (short by %u L/R samples)...\n", (length / 2) - numSamplesReady);
358 //WriteLog("DAC: %u samples ready.\n", numSamplesReady);
359
360                 // Actually, it's a bit more involved than this, but this is the general idea:
361 //              memcpy(buffer, DACBuffer, length);
362                 for(int i=0; i<numSamplesReady; i++)
363                         ((uint16 *)buffer)[i] = DACBuffer[(LeftFIFOHeadPtr + i) % BUFFER_SIZE];
364                         // Could also use (as long as BUFFER_SIZE is a multiple of 2):
365 //                      buffer[i] = DACBuffer[(LeftFIFOHeadPtr + i) & (BUFFER_SIZE - 1)];
366
367                 LeftFIFOHeadPtr = (LeftFIFOHeadPtr + numSamplesReady) % BUFFER_SIZE;
368                 RightFIFOHeadPtr = (RightFIFOHeadPtr + numSamplesReady) % BUFFER_SIZE;
369                 // Could also use (as long as BUFFER_SIZE is a multiple of 2):
370 //              LeftFIFOHeadPtr = (LeftFIFOHeadPtr + numSamplesReady) & (BUFFER_SIZE - 1);
371 //              RightFIFOHeadPtr = (RightFIFOHeadPtr + numSamplesReady) & (BUFFER_SIZE - 1);
372 //WriteLog("  -> Left/RightFIFOHeadPtr: %04X/%04X, Left/RightFIFOTailPtr: %04X/%04X\n", LeftFIFOHeadPtr, RightFIFOHeadPtr, LeftFIFOTailPtr, RightFIFOTailPtr);
373         }
374 //Hmm. Seems that the SDL buffer isn't being starved by the DAC buffer...
375 //      else
376 //              WriteLog("DAC: Silence...!\n");
377 }
378
379
380 //
381 // Calculate the frequency of SCLK * 32 using the divider
382 //
383 int GetCalculatedFrequency(void)
384 {
385         int systemClockFrequency = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL);
386
387         // We divide by 32 here in order to find the frequency of 32 SCLKs in a row (transferring
388         // 16 bits of left data + 16 bits of right data = 32 bits, 1 SCLK = 1 bit transferred).
389         return systemClockFrequency / (32 * (2 * (SCLKFrequencyDivider + 1)));
390 }
391
392
393 static int oldFreq = 0;
394
395 void DACSetNewFrequency(int freq)
396 {
397 #ifdef NEW_DAC_CODE
398 #else
399         if (freq == oldFreq)
400                 return;
401
402         oldFreq = freq;
403
404         // Should do some sanity checking on the frequency...
405
406         if (SDLSoundInitialized)
407                 SDL_CloseAudio();
408
409         desired.freq = freq;// SDL will do conversion on the fly, if it can't get the exact rate. Nice!
410         WriteLog("DAC: Changing sample rate to %u Hz!\n", desired.freq);
411
412         if (SDLSoundInitialized)
413         {
414                 if (SDL_OpenAudio(&desired, NULL) < 0)  // NULL means SDL guarantees what we want
415                 {
416 // This is bad, Bad, BAD !!! DON'T ABORT BECAUSE WE DIDN'T GET OUR FREQ! !!! FIX !!!
417 #warning !!! FIX !!! Aborting because of SDL audio problem is bad!
418                         WriteLog("DAC: Failed to initialize SDL sound: %s.\nDesired freq: %u\nShutting down!\n", SDL_GetError(), desired.freq);
419 //                                              LogDone();
420 //                                              exit(1);
421 #warning "Reimplement GUICrashGracefully!"
422 //                                              GUICrashGracefully("Failed to initialize SDL sound!");
423                         return;
424                 }
425         }
426
427         DACReset();
428
429         if (SDLSoundInitialized)
430                 SDL_PauseAudio(false);                  // Start playback!
431 #endif
432 }
433
434
435 //
436 // LTXD/RTXD/SCLK/SMODE ($F1A148/4C/50/54)
437 //
438 void DACWriteByte(uint32 offset, uint8 data, uint32 who/*= UNKNOWN*/)
439 {
440         WriteLog("DAC: %s writing BYTE %02X at %08X\n", whoName[who], data, offset);
441         if (offset == SCLK + 3)
442                 DACWriteWord(offset - 3, (uint16)data);
443 }
444
445
446 void DACWriteWord(uint32 offset, uint16 data, uint32 who/*= UNKNOWN*/)
447 {
448         if (offset == LTXD + 2)
449         {
450                 if (!SDLSoundInitialized)
451                         return;
452
453 #ifdef NEW_DAC_CODE
454                 ltxd = data;
455 #else
456                 // Spin until buffer has been drained (for too fast processors!)...
457 //Small problem--if Head == 0 and Tail == buffer end, then this will fail... !!! FIX !!!
458 //[DONE]
459                 // Also, we're taking advantage of the fact that the buffer is a multiple of two
460                 // in this check...
461 uint32 spin = 0;
462                 while (((LeftFIFOTailPtr + 2) & (BUFFER_SIZE - 1)) == LeftFIFOHeadPtr)//;
463                 {
464 spin++;
465 //if ((spin & 0x0FFFFFFF) == 0)
466 //      WriteLog("Tail=%X, Head=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
467
468 if (spin == 0xFFFF0000)
469 {
470 uint32 ltail = LeftFIFOTailPtr, lhead = LeftFIFOHeadPtr;
471 WriteLog("Tail=%X, Head=%X", ltail, lhead);
472
473         WriteLog("\nStuck in left DAC spinlock! Aborting!\n");
474         WriteLog("LTail=%X, LHead=%X, BUFFER_SIZE-1=%X\n", LeftFIFOTailPtr, LeftFIFOHeadPtr, BUFFER_SIZE - 1);
475         WriteLog("RTail=%X, RHead=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
476         WriteLog("From while: Tail=%X, Head=%X", (LeftFIFOTailPtr + 2) & (BUFFER_SIZE - 1), LeftFIFOHeadPtr);
477 //      LogDone();
478 //      exit(0);
479 #warning "Reimplement GUICrashGracefully!"
480 //      GUICrashGracefully("Stuck in left DAC spinlock!");
481         return;
482 }
483                 }//*/
484
485                 SDL_LockAudio();                                                        // Is it necessary to do this? Mebbe.
486                 // We use a circular buffer 'cause it's easy. Note that the callback function
487                 // takes care of dumping audio to the soundcard...! Also note that we're writing
488                 // the samples in the buffer in an interleaved L/R format.
489                 LeftFIFOTailPtr = (LeftFIFOTailPtr + 2) % BUFFER_SIZE;
490                 DACBuffer[LeftFIFOTailPtr] = data;
491                 SDL_UnlockAudio();
492 #endif
493         }
494         else if (offset == RTXD + 2)
495         {
496                 if (!SDLSoundInitialized)
497                         return;
498 /*
499 Here's what's happening now:
500
501 Stuck in right DAC spinlock!
502 Aborting!
503
504 Tail=681, Head=681, BUFFER_SIZE-1=FFFF
505 From while: Tail=683, Head=681
506
507 ????? What the FUCK ?????
508
509 & when I uncomment the lines below spin++; it *doesn't* lock here... WTF?????
510
511 I think it was missing parentheses causing the fuckup... Seems to work now...
512
513 Except for Super Burnout now...! Aarrrgggghhhhh!
514
515 Tail=AC, Head=AE
516 Stuck in left DAC spinlock! Aborting!
517 Tail=AC, Head=AE, BUFFER_SIZE-1=FFFF
518 From while: Tail=AE, Head=AE
519
520 So it's *really* stuck here in the left FIFO. Figure out why!!!
521
522 Prolly 'cause it doesn't set the sample rate right away--betcha it works with the BIOS...
523 It gets farther, but then locks here (weird!):
524
525 Tail=2564, Head=2566
526 Stuck in left DAC spinlock! Aborting!
527 Tail=2564, Head=2566, BUFFER_SIZE-1=FFFF
528 From while: Tail=2566, Head=2566
529
530 Weird--recompile with more WriteLog() entries and it *doesn't* lock...
531 Yeah, because there was no DSP running. Duh!
532
533 Tail=AC, Head=AE
534 Stuck in left DAC spinlock! Aborting!
535 LTail=AC, LHead=AE, BUFFER_SIZE-1=FFFF
536 RTail=AF, RHead=AF, BUFFER_SIZE-1=FFFF
537 From while: Tail=AE, Head=AE
538
539 Odd: The right FIFO is empty, but the left FIFO is full!
540 And this is what is causing the lockup--the DAC callback waits for the side with
541 less samples ready and in this case it's the right channel (that never fills up)
542 that it's waiting for...!
543
544 Okay, with the kludge in place for the right channel not being filled, we select
545 a track and then it locks here:
546
547 Tail=60D8, Head=60DA
548 Stuck in left DAC spinlock! Aborting!
549 LTail=60D8, LHead=60D8, BUFFER_SIZE-1=FFFF
550 RTail=DB, RHead=60D9, BUFFER_SIZE-1=FFFF
551 From while: Tail=60DA, Head=60D8
552 */
553 #ifdef NEW_DAC_CODE
554                 rtxd = data;
555 #else
556 #warning Spinlock problem--!!! FIX !!!
557 #warning Odd: The right FIFO is empty, but the left FIFO is full!
558                 // Spin until buffer has been drained (for too fast processors!)...
559 uint32 spin = 0;
560                 while (((RightFIFOTailPtr + 2) & (BUFFER_SIZE - 1)) == RightFIFOHeadPtr)//;
561                 {
562 spin++;
563 //if ((spin & 0x0FFFFFFF) == 0)
564 //      WriteLog("Tail=%X, Head=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
565
566 if (spin == 0xFFFF0000)
567 {
568 uint32 rtail = RightFIFOTailPtr, rhead = RightFIFOHeadPtr;
569 WriteLog("Tail=%X, Head=%X", rtail, rhead);
570
571         WriteLog("\nStuck in right DAC spinlock! Aborting!\n");
572         WriteLog("LTail=%X, LHead=%X, BUFFER_SIZE-1=%X\n", LeftFIFOTailPtr, LeftFIFOHeadPtr, BUFFER_SIZE - 1);
573         WriteLog("RTail=%X, RHead=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
574         WriteLog("From while: Tail=%X, Head=%X", (RightFIFOTailPtr + 2) & (BUFFER_SIZE - 1), RightFIFOHeadPtr);
575 //      LogDone();
576 //      exit(0);
577 #warning "Reimplement GUICrashGracefully!"
578 //      GUICrashGracefully("Stuck in right DAC spinlock!");
579         return;
580 }
581                 }//*/
582
583                 SDL_LockAudio();
584                 RightFIFOTailPtr = (RightFIFOTailPtr + 2) % BUFFER_SIZE;
585                 DACBuffer[RightFIFOTailPtr] = data;
586                 SDL_UnlockAudio();
587 /*#ifdef DEBUG_DAC
588                 else
589                         WriteLog("DAC: Ran into FIFO's right tail pointer!\n");
590 #endif*/
591 #endif
592         }
593         else if (offset == SCLK + 2)                                    // Sample rate
594         {
595                 WriteLog("DAC: Writing %u to SCLK...\n", data);
596                 if ((uint8)data != SCLKFrequencyDivider)
597                 {
598                         SCLKFrequencyDivider = (uint8)data;
599 #ifdef NEW_DAC_CODE
600 #else
601 //Of course a better way would be to query the hardware to find the upper limit...
602                         if (data > 7)   // Anything less than 8 is too high!
603                         {
604                                 if (SDLSoundInitialized)
605                                         SDL_CloseAudio();
606
607                                 desired.freq = GetCalculatedFrequency();// SDL will do conversion on the fly, if it can't get the exact rate. Nice!
608                                 WriteLog("DAC: Changing sample rate to %u Hz!\n", desired.freq);
609
610                                 if (SDLSoundInitialized)
611                                 {
612                                         if (SDL_OpenAudio(&desired, NULL) < 0)  // NULL means SDL guarantees what we want
613                                         {
614 // This is bad, Bad, BAD !!! DON'T ABORT BECAUSE WE DIDN'T GET OUR FREQ! !!! FIX !!!
615 #warning !!! FIX !!! Aborting because of SDL audio problem is bad!
616                                                 WriteLog("DAC: Failed to initialize SDL sound: %s.\nDesired freq: %u\nShutting down!\n", SDL_GetError(), desired.freq);
617 //                                              LogDone();
618 //                                              exit(1);
619 #warning "Reimplement GUICrashGracefully!"
620 //                                              GUICrashGracefully("Failed to initialize SDL sound!");
621                                                 return;
622                                         }
623                                 }
624
625                                 DACReset();
626
627                                 if (SDLSoundInitialized)
628                                         SDL_PauseAudio(false);                  // Start playback!
629                         }
630 #endif
631                 }
632         }
633         else if (offset == SMODE + 2)
634         {
635                 serialMode = data;
636                 WriteLog("DAC: %s writing to SMODE. Bits: %s%s%s%s%s%s [68K PC=%08X]\n", whoName[who],
637                         (data & 0x01 ? "INTERNAL " : ""), (data & 0x02 ? "MODE " : ""),
638                         (data & 0x04 ? "WSEN " : ""), (data & 0x08 ? "RISING " : ""),
639                         (data & 0x10 ? "FALLING " : ""), (data & 0x20 ? "EVERYWORD" : ""),
640                         m68k_get_reg(NULL, M68K_REG_PC));
641         }
642 }
643
644
645 //
646 // LRXD/RRXD/SSTAT ($F1A148/4C/50)
647 //
648 uint8 DACReadByte(uint32 offset, uint32 who/*= UNKNOWN*/)
649 {
650 //      WriteLog("DAC: %s reading byte from %08X\n", whoName[who], offset);
651         return 0xFF;
652 }
653
654
655 //static uint16 fakeWord = 0;
656 uint16 DACReadWord(uint32 offset, uint32 who/*= UNKNOWN*/)
657 {
658 //      WriteLog("DAC: %s reading word from %08X\n", whoName[who], offset);
659 //      return 0xFFFF;
660 //      WriteLog("DAC: %s reading WORD %04X from %08X\n", whoName[who], fakeWord, offset);
661 //      return fakeWord++;
662 //NOTE: This only works if a bunch of things are set in BUTCH which we currently don't
663 //      check for. !!! FIX !!!
664 // Partially fixed: We check for I2SCNTRL in the JERRY I2S routine...
665 //      return GetWordFromButchSSI(offset, who);
666         if (offset == LRXD || offset == RRXD)
667                 return 0x0000;
668         else if (offset == LRXD + 2)
669                 return lrxd;
670         else if (offset == RRXD + 2)
671                 return rrxd;
672
673         return 0xFFFF;  // May need SSTAT as well... (but may be a Jaguar II only feature)
674 }