2 // DAC (really, Synchronous Serial Interface) Handler
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
9 // JLH = James Hammons <jlhamm@acm.org>
12 // --- ---------- -------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
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
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?
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.
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).
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.
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? :-)
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
69 // Jaguar memory locations
76 #define SMODE 0xF1A154
80 //uint16 lrxd, rrxd; // I2S ports (into Jaguar)
84 static uint32 LeftFIFOHeadPtr, LeftFIFOTailPtr, RightFIFOHeadPtr, RightFIFOTailPtr;
85 static SDL_AudioSpec desired;
86 static bool SDLSoundInitialized;
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.
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;
95 // Private function prototypes
97 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
98 void SDLSoundCallbackNew(void * userdata, Uint8 * buffer, int length);
99 void DSPSampleCallback(void);
103 // Initialize the SDL sound system
107 SDLSoundInitialized = false;
109 if (!vjs.audioEnabled)
111 WriteLog("DAC: Host audio playback disabled.\n");
116 desired.freq = DAC_AUDIO_RATE;
117 desired.format = AUDIO_S16SYS;
118 desired.channels = 2;
119 desired.samples = 2048;
120 desired.callback = SDLSoundCallbackNew;
122 // memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
123 // DACBuffer = (uint16 *)memory_malloc(BUFFER_SIZE * sizeof(uint16), "DAC buffer");
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;
133 if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
134 WriteLog("DAC: Failed to initialize SDL sound...\n");
137 SDLSoundInitialized = true;
139 SDL_PauseAudio(false); // Start playback!
140 WriteLog("DAC: Successfully initialized. Sample rate: %u\n", desired.freq);
143 ltxd = lrxd = desired.silence;
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);
152 // Reset the sound buffer FIFOs
156 LeftFIFOHeadPtr = LeftFIFOTailPtr = 0, RightFIFOHeadPtr = RightFIFOTailPtr = 1;
157 ltxd = lrxd = desired.silence;
162 // Close down the SDL sound subsystem
166 if (SDLSoundInitialized)
168 SDL_PauseAudio(true);
172 // memory_free(DACBuffer);
173 WriteLog("DAC: Done.\n");
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.
187 // SDL callback routine to fill audio buffer
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
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)
199 // 1st, check to see if the DSP is running. If not, fill the buffer with L/RXTD and exit.
203 for(int i=0; i<(length/2); i+=2)
205 ((uint16_t *)buffer)[i + 0] = ltxd;
206 ((uint16_t *)buffer)[i + 1] = rtxd;
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) * ();
219 // Now, run the DSP for that length of time for each sample we need to make
222 for(int i=0; i<(length/2); i+=2)
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);
234 if (vjs.usePipelinedDSP)
235 DSPExecP2(cyclesPerSample);
237 DSPExec(cyclesPerSample);
240 ((uint16_t *)buffer)[i + 0] = ltxd;
241 ((uint16_t *)buffer)[i + 1] = rtxd;
245 sampleBuffer = buffer;
246 numberOfSamples = length / 2;
249 SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY);
251 // These timings are tied to NTSC, need to fix that in event.cpp/h!
254 double timeToNextEvent = GetTimeToNextEvent(EVENT_JERRY);
258 if (vjs.usePipelinedDSP)
259 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent));
261 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
264 HandleNextEvent(EVENT_JERRY);
268 // We do this to prevent problems with trying to write past the end of the buffer...
269 // RemoveCallback(DSPSampleCallback);
274 void DSPSampleCallback(void)
276 ((uint16_t *)sampleBuffer)[bufferIndex + 0] = ltxd;
277 ((uint16_t *)sampleBuffer)[bufferIndex + 1] = rtxd;
280 if (bufferIndex == numberOfSamples)
286 SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY);
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));
296 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
299 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
304 if (vjs.usePipelinedDSP)
305 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
307 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
318 // SDL callback routine to fill audio buffer
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
323 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
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)
331 //WriteLog("DAC: About to write some data!\n");
332 int numLeftSamplesReady
333 = (LeftFIFOTailPtr + (LeftFIFOTailPtr < LeftFIFOHeadPtr ? BUFFER_SIZE : 0))
335 int numRightSamplesReady
336 = (RightFIFOTailPtr + (RightFIFOTailPtr < RightFIFOHeadPtr ? BUFFER_SIZE : 0))
338 //This waits for the slower side to catch up. If writing only one side, then this
339 //causes the buffer not to drain...
341 = (numLeftSamplesReady < numRightSamplesReady
342 ? numLeftSamplesReady : numRightSamplesReady);//Hmm. * 2;
344 //Kludge, until I can figure out WTF is going on WRT Super Burnout.
345 if (numLeftSamplesReady == 0 || numRightSamplesReady == 0)
346 numSamplesReady = numLeftSamplesReady + numRightSamplesReady;
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);
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;
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);
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)];
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);
374 //Hmm. Seems that the SDL buffer isn't being starved by the DAC buffer...
376 // WriteLog("DAC: Silence...!\n");
381 // Calculate the frequency of SCLK * 32 using the divider
383 int GetCalculatedFrequency(void)
385 int systemClockFrequency = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL);
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)));
393 static int oldFreq = 0;
395 void DACSetNewFrequency(int freq)
404 // Should do some sanity checking on the frequency...
406 if (SDLSoundInitialized)
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);
412 if (SDLSoundInitialized)
414 if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
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);
421 #warning "Reimplement GUICrashGracefully!"
422 // GUICrashGracefully("Failed to initialize SDL sound!");
429 if (SDLSoundInitialized)
430 SDL_PauseAudio(false); // Start playback!
436 // LTXD/RTXD/SCLK/SMODE ($F1A148/4C/50/54)
438 void DACWriteByte(uint32 offset, uint8 data, uint32 who/*= UNKNOWN*/)
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);
446 void DACWriteWord(uint32 offset, uint16 data, uint32 who/*= UNKNOWN*/)
448 if (offset == LTXD + 2)
450 if (!SDLSoundInitialized)
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 !!!
459 // Also, we're taking advantage of the fact that the buffer is a multiple of two
462 while (((LeftFIFOTailPtr + 2) & (BUFFER_SIZE - 1)) == LeftFIFOHeadPtr)//;
465 //if ((spin & 0x0FFFFFFF) == 0)
466 // WriteLog("Tail=%X, Head=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
468 if (spin == 0xFFFF0000)
470 uint32 ltail = LeftFIFOTailPtr, lhead = LeftFIFOHeadPtr;
471 WriteLog("Tail=%X, Head=%X", ltail, lhead);
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);
479 #warning "Reimplement GUICrashGracefully!"
480 // GUICrashGracefully("Stuck in left DAC spinlock!");
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;
494 else if (offset == RTXD + 2)
496 if (!SDLSoundInitialized)
499 Here's what's happening now:
501 Stuck in right DAC spinlock!
504 Tail=681, Head=681, BUFFER_SIZE-1=FFFF
505 From while: Tail=683, Head=681
507 ????? What the FUCK ?????
509 & when I uncomment the lines below spin++; it *doesn't* lock here... WTF?????
511 I think it was missing parentheses causing the fuckup... Seems to work now...
513 Except for Super Burnout now...! Aarrrgggghhhhh!
516 Stuck in left DAC spinlock! Aborting!
517 Tail=AC, Head=AE, BUFFER_SIZE-1=FFFF
518 From while: Tail=AE, Head=AE
520 So it's *really* stuck here in the left FIFO. Figure out why!!!
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!):
526 Stuck in left DAC spinlock! Aborting!
527 Tail=2564, Head=2566, BUFFER_SIZE-1=FFFF
528 From while: Tail=2566, Head=2566
530 Weird--recompile with more WriteLog() entries and it *doesn't* lock...
531 Yeah, because there was no DSP running. Duh!
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
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...!
544 Okay, with the kludge in place for the right channel not being filled, we select
545 a track and then it locks here:
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
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!)...
560 while (((RightFIFOTailPtr + 2) & (BUFFER_SIZE - 1)) == RightFIFOHeadPtr)//;
563 //if ((spin & 0x0FFFFFFF) == 0)
564 // WriteLog("Tail=%X, Head=%X, BUFFER_SIZE-1=%X\n", RightFIFOTailPtr, RightFIFOHeadPtr, BUFFER_SIZE - 1);
566 if (spin == 0xFFFF0000)
568 uint32 rtail = RightFIFOTailPtr, rhead = RightFIFOHeadPtr;
569 WriteLog("Tail=%X, Head=%X", rtail, rhead);
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);
577 #warning "Reimplement GUICrashGracefully!"
578 // GUICrashGracefully("Stuck in right DAC spinlock!");
584 RightFIFOTailPtr = (RightFIFOTailPtr + 2) % BUFFER_SIZE;
585 DACBuffer[RightFIFOTailPtr] = data;
589 WriteLog("DAC: Ran into FIFO's right tail pointer!\n");
593 else if (offset == SCLK + 2) // Sample rate
595 WriteLog("DAC: Writing %u to SCLK...\n", data);
596 if ((uint8)data != SCLKFrequencyDivider)
598 SCLKFrequencyDivider = (uint8)data;
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!
604 if (SDLSoundInitialized)
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);
610 if (SDLSoundInitialized)
612 if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
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);
619 #warning "Reimplement GUICrashGracefully!"
620 // GUICrashGracefully("Failed to initialize SDL sound!");
627 if (SDLSoundInitialized)
628 SDL_PauseAudio(false); // Start playback!
633 else if (offset == SMODE + 2)
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));
646 // LRXD/RRXD/SSTAT ($F1A148/4C/50)
648 uint8 DACReadByte(uint32 offset, uint32 who/*= UNKNOWN*/)
650 // WriteLog("DAC: %s reading byte from %08X\n", whoName[who], offset);
655 //static uint16 fakeWord = 0;
656 uint16 DACReadWord(uint32 offset, uint32 who/*= UNKNOWN*/)
658 // WriteLog("DAC: %s reading word from %08X\n", whoName[who], offset);
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)
668 else if (offset == LRXD + 2)
670 else if (offset == RRXD + 2)
673 return 0xFFFF; // May need SSTAT as well... (but may be a Jaguar II only feature)