|
|
1.1 root 1: /*
2: Hatari - dmaSnd.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: STE DMA sound emulation. Does not seem to be very hard at first glance,
8: but since the DMA sound has to be mixed together with the PSG sound and
9: the output frequency of the host computer differs from the DMA sound
10: frequency, the copy function is a little bit complicated.
11: For reducing copy latency, we set a "interrupt" with Int_AddRelativeInterrupt
12: to occur just after a sound frame should be finished. There we update the
13: sound. The update function also triggers the ST interrupts (Timer A and
14: MFP-i7) which are often used in ST programs for setting a new sound frame
15: after the old one has finished.
16:
17: The microwire interface is not emulated (yet).
18:
19: Hardware I/O registers:
20:
21: $FF8900 (word) : DMA sound control register
22: $FF8903 (byte) : Frame Start Hi
23: $FF8905 (byte) : Frame Start Mi
24: $FF8907 (byte) : Frame Start Lo
25: $FF8909 (byte) : Frame Count Hi
26: $FF890B (byte) : Frame Count Mi
27: $FF890D (byte) : Frame Count Lo
28: $FF890F (byte) : Frame End Hi
29: $FF8911 (byte) : Frame End Mi
30: $FF8913 (byte) : Frame End Lo
31: $FF8920 (word) : Sound Mode Control (frequency, mono/stereo)
32: $FF8922 (byte) : Microwire Data Register
33: $FF8924 (byte) : Microwire Mask Register
34: */
1.1.1.5 root 35: const char DmaSnd_fileid[] = "Hatari dmaSnd.c : " __DATE__ " " __TIME__;
1.1 root 36:
37: #include "main.h"
38: #include "audio.h"
1.1.1.3 root 39: #include "configuration.h"
1.1 root 40: #include "dmaSnd.h"
41: #include "int.h"
42: #include "ioMem.h"
1.1.1.6 ! root 43: #include "log.h"
1.1 root 44: #include "memorySnapShot.h"
45: #include "mfp.h"
46: #include "sound.h"
1.1.1.3 root 47: #include "stMemory.h"
1.1.1.6 ! root 48: #include "falcon/dsp.h"
! 49: #include "falcon/dsp_core.h"
1.1 root 50:
51:
52: Uint16 nDmaSoundControl; /* Sound control register */
53:
1.1.1.6 ! root 54: static Sint16 DspOutBuffer[MIXBUFFER_SIZE*2];
! 55: static int nDspOutRdPos, nDspOutWrPos, nDspBufSamples;
! 56:
1.1.1.2 root 57: static Uint16 nDmaSoundMode; /* Sound mode register */
1.1 root 58: static Uint16 nMicrowireData; /* Microwire Data register */
59: static Uint16 nMicrowireMask; /* Microwire Mask register */
60: static int nMwTransferSteps;
61:
62: static Uint32 nFrameStartAddr; /* Sound frame start */
63: static Uint32 nFrameEndAddr; /* Sound frame end */
64: static double FrameCounter; /* Counter in current sound frame */
65: static int nFrameLen; /* Length of the frame */
66:
1.1.1.3 root 67: static const double DmaSndSampleRates[4] =
1.1 root 68: {
69: 6258,
70: 12517,
71: 25033,
72: 50066
73: };
74:
75:
1.1.1.3 root 76: static const double DmaSndFalcSampleRates[] =
77: {
78: 49170,
79: 32780,
80: 24585,
81: 19668,
82: 16390,
83: 14049,
84: 12292,
85: 10927,
86: 9834,
87: 8940,
88: 8195,
89: 7565,
90: 7024,
91: 6556,
92: 6146,
93: };
94:
95:
1.1 root 96: /*-----------------------------------------------------------------------*/
1.1.1.3 root 97: /**
98: * Reset DMA sound variables.
99: */
1.1.1.4 root 100: void DmaSnd_Reset(bool bCold)
1.1 root 101: {
102: nDmaSoundControl = 0;
103:
104: if (bCold)
105: {
106: nDmaSoundMode = 0;
107: }
1.1.1.4 root 108:
109: nMwTransferSteps = 0;
1.1.1.6 ! root 110:
! 111: nDspOutRdPos = nDspOutWrPos = 0;
1.1 root 112: }
113:
114:
115: /*-----------------------------------------------------------------------*/
1.1.1.3 root 116: /**
117: * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
118: */
1.1.1.4 root 119: void DmaSnd_MemorySnapShot_Capture(bool bSave)
1.1 root 120: {
121: /* Save/Restore details */
122: MemorySnapShot_Store(&nDmaSoundControl, sizeof(nDmaSoundControl));
123: MemorySnapShot_Store(&nDmaSoundMode, sizeof(nDmaSoundMode));
124: MemorySnapShot_Store(&nFrameStartAddr, sizeof(nFrameStartAddr));
125: MemorySnapShot_Store(&nFrameEndAddr, sizeof(nFrameEndAddr));
126: MemorySnapShot_Store(&FrameCounter, sizeof(FrameCounter));
127: MemorySnapShot_Store(&nFrameLen, sizeof(nFrameLen));
128: MemorySnapShot_Store(&nMicrowireData, sizeof(nMicrowireData));
129: MemorySnapShot_Store(&nMicrowireMask, sizeof(nMicrowireMask));
130: MemorySnapShot_Store(&nMwTransferSteps, sizeof(nMwTransferSteps));
131: }
132:
133:
1.1.1.3 root 134: static double DmaSnd_DetectSampleRate(void)
135: {
136: int nFalcClk = IoMem[0xff8935] & 0x0f;
137:
138: if (ConfigureParams.System.nMachineType == MACHINE_FALCON && nFalcClk != 0)
139: {
140: return DmaSndFalcSampleRates[nFalcClk-1];
141: }
142: else
143: {
144: return DmaSndSampleRates[nDmaSoundMode & 3];
145: }
146: }
147:
148:
1.1 root 149: /*-----------------------------------------------------------------------*/
1.1.1.3 root 150: /**
151: * This function is called when a new sound frame is started.
152: * It copies the start and end address from the I/O registers, calculates
153: * the sample length, etc.
154: */
1.1 root 155: static void DmaSnd_StartNewFrame(void)
156: {
157: int nCyclesForFrame;
1.1.1.4 root 158:
1.1 root 159: nFrameStartAddr = (IoMem[0xff8903] << 16) | (IoMem[0xff8905] << 8) | (IoMem[0xff8907] & ~1);
160: nFrameEndAddr = (IoMem[0xff890f] << 16) | (IoMem[0xff8911] << 8) | (IoMem[0xff8913] & ~1);
161:
162: FrameCounter = 0;
163: nFrameLen = nFrameEndAddr - nFrameStartAddr;
164:
1.1.1.6 ! root 165: if (nFrameLen <= 0)
! 166: {
! 167: Log_Printf(LOG_WARN, "DMA snd: Illegal buffer size (from 0x%x to 0x%x)\n",
! 168: nFrameStartAddr, nFrameEndAddr);
! 169: return;
! 170: }
! 171:
1.1 root 172: /* To get smooth sound, set an "interrupt" for the end of the frame that
173: * updates the sound mix buffer. */
1.1.1.3 root 174: nCyclesForFrame = nFrameLen * (8013000.0 / DmaSnd_DetectSampleRate());
1.1 root 175: if (!(nDmaSoundMode & DMASNDMODE_MONO)) /* Is it stereo? */
176: nCyclesForFrame = nCyclesForFrame / 2;
1.1.1.4 root 177: Int_AddRelativeInterrupt(nCyclesForFrame, INT_CPU_CYCLE, INTERRUPT_DMASOUND);
1.1 root 178: }
179:
180:
181: /*-----------------------------------------------------------------------*/
1.1.1.3 root 182: /**
183: * Check if end-of-frame has been reached and raise interrupts if needed.
1.1.1.6 ! root 184: * Returns true if DMA sound processing should be stopped now and false
1.1.1.3 root 185: * if it continues.
186: */
1.1 root 187: static inline int DmaSnd_CheckForEndOfFrame(int nFrameCounter)
188: {
189: if (nFrameCounter >= nFrameLen)
190: {
191: /* Raise end-of-frame interrupts (MFP-i7 and Time-A) */
1.1.1.6 ! root 192: MFP_InputOnChannel(MFP_TIMER_GPIP7_BIT, MFP_IERA, &MFP_IPRA);
1.1 root 193: if (MFP_TACR == 0x08) /* Is timer A in Event Count mode? */
194: MFP_TimerA_EventCount_Interrupt();
195:
196: if (nDmaSoundControl & DMASNDCTRL_PLAYLOOP)
197: {
198: DmaSnd_StartNewFrame();
199: }
200: else
201: {
202: nDmaSoundControl &= ~DMASNDCTRL_PLAY;
1.1.1.6 ! root 203: return true;
1.1 root 204: }
205: }
206:
1.1.1.6 ! root 207: return false;
! 208: }
! 209:
! 210:
! 211: /**
! 212: * Mix DSP sound sample with the normal PSG sound samples.
! 213: */
! 214: static void DmaSnd_GenerateDspSamples(int nMixBufIdx, int nSamplesToGenerate)
! 215: {
! 216: double FreqRatio, fDspBufSamples, fDspBufRdPos;
! 217: int i;
! 218: int nBufIdx;
! 219:
! 220: FreqRatio = DmaSnd_DetectSampleRate() / (double)nAudioFrequency;
! 221: FreqRatio *= 2.0; /* Stereo */
! 222:
! 223: fDspBufSamples = (double)nDspBufSamples;
! 224: fDspBufRdPos = (double)nDspOutRdPos;
! 225:
! 226: for (i = 0; i < nSamplesToGenerate && fDspBufSamples > 0.0; i++)
! 227: {
! 228: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
! 229: nDspOutRdPos = (((int)fDspBufRdPos) & -2) % (MIXBUFFER_SIZE*2);
! 230:
! 231: MixBuffer[nBufIdx][0] = ((int)MixBuffer[nBufIdx][0]
! 232: + (int)(DspOutBuffer[nDspOutRdPos+0])) / 2;
! 233: MixBuffer[nBufIdx][1] = ((int)MixBuffer[nBufIdx][1]
! 234: + (int)(DspOutBuffer[nDspOutRdPos+1])) / 2;
! 235:
! 236: fDspBufRdPos += FreqRatio;
! 237: fDspBufSamples -= FreqRatio;
! 238: }
! 239:
! 240: if (fDspBufSamples > 0.0)
! 241: nDspBufSamples = (int)fDspBufSamples;
! 242: else
! 243: nDspBufSamples = 0;
1.1 root 244: }
245:
246:
247: /*-----------------------------------------------------------------------*/
1.1.1.3 root 248: /**
249: * Mix DMA sound sample with the normal PSG sound samples.
1.1.1.6 ! root 250: * Note: We adjust the volume level of the 8-bit DMA samples to factor
! 251: * 0.5 compared to the PSG sound samples, this seems to be quite similar
! 252: * to a real STE (and since we got to divide it by 2 again for adding them
! 253: * to the YM samples and multiply by 256 to get to 16-bit, we simply multiply
! 254: * them by 64 in total).
1.1.1.3 root 255: */
1.1 root 256: void DmaSnd_GenerateSamples(int nMixBufIdx, int nSamplesToGenerate)
257: {
258: double FreqRatio;
259: int i;
1.1.1.6 ! root 260: int nBufIdx, nFramePos;
1.1 root 261: Sint8 *pFrameStart;
262:
1.1.1.6 ! root 263: if (ConfigureParams.System.nMachineType == MACHINE_FALCON
! 264: && (IoMem_ReadWord(0xff8932) & 0x6000) == 0x2000)
! 265: {
! 266: DmaSnd_GenerateDspSamples(nMixBufIdx, nSamplesToGenerate);
! 267: return;
! 268: }
! 269:
1.1 root 270: if (!(nDmaSoundControl & DMASNDCTRL_PLAY))
271: return;
272:
273: pFrameStart = (Sint8 *)&STRam[nFrameStartAddr];
1.1.1.6 ! root 274: FreqRatio = DmaSnd_DetectSampleRate() / (double)nAudioFrequency;
1.1 root 275:
1.1.1.3 root 276: if (ConfigureParams.System.nMachineType == MACHINE_FALCON
277: && (nDmaSoundMode & DMASNDMODE_16BITSTEREO))
1.1 root 278: {
1.1.1.3 root 279: /* Stereo 16-bit */
280: FreqRatio *= 4.0;
281: for (i = 0; i < nSamplesToGenerate; i++)
282: {
283: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.6 ! root 284: nFramePos = ((int)FrameCounter) & ~3;
! 285: MixBuffer[nBufIdx][0] = (int)MixBuffer[nBufIdx][0]
! 286: + ((int)(Sint16)do_get_mem_word(&pFrameStart[nFramePos]))/2;
! 287: MixBuffer[nBufIdx][1] = (int)MixBuffer[nBufIdx][1]
! 288: + ((int)(Sint16)do_get_mem_word(&pFrameStart[nFramePos+2]))/2;
1.1.1.3 root 289: FrameCounter += FreqRatio;
290: if (DmaSnd_CheckForEndOfFrame(FrameCounter))
291: break;
292: }
293: }
294: else if (nDmaSoundMode & DMASNDMODE_MONO) /* 8-bit stereo or mono? */
295: {
296: /* Mono 8-bit */
1.1 root 297: for (i = 0; i < nSamplesToGenerate; i++)
298: {
299: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.4 root 300: MixBuffer[nBufIdx][0] = MixBuffer[nBufIdx][1] =
1.1.1.6 ! root 301: (int)MixBuffer[nBufIdx][0]
! 302: + 64 * (int)pFrameStart[(int)FrameCounter];
1.1 root 303: FrameCounter += FreqRatio;
304: if (DmaSnd_CheckForEndOfFrame(FrameCounter))
305: break;
306: }
307: }
308: else
309: {
1.1.1.3 root 310: /* Stereo 8-bit */
1.1 root 311: FreqRatio *= 2.0;
312: for (i = 0; i < nSamplesToGenerate; i++)
313: {
314: nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.6 ! root 315: nFramePos = ((int)FrameCounter) & ~1;
! 316: MixBuffer[nBufIdx][0] = (int)MixBuffer[nBufIdx][0]
! 317: + 64 * (int)pFrameStart[nFramePos];
! 318: MixBuffer[nBufIdx][1] = (int)MixBuffer[nBufIdx][1]
! 319: + 64 * (int)pFrameStart[nFramePos+1];
1.1 root 320: FrameCounter += FreqRatio;
321: if (DmaSnd_CheckForEndOfFrame(FrameCounter))
322: break;
323: }
324: }
325: }
326:
327:
328: /*-----------------------------------------------------------------------*/
1.1.1.3 root 329: /**
330: * DMA sound end of frame "interrupt". Used for updating the sound after
331: * a frame has been finished.
332: */
1.1 root 333: void DmaSnd_InterruptHandler(void)
334: {
335: /* Remove this interrupt from list and re-order */
336: Int_AcknowledgeInterrupt();
337:
338: /* Update sound */
339: Sound_Update();
340: }
341:
342:
343: /*-----------------------------------------------------------------------*/
1.1.1.3 root 344: /**
345: * Create actual position for frame count registers.
346: */
1.1 root 347: static Uint32 DmaSnd_GetFrameCount(void)
348: {
349: Uint32 nActCount;
350:
351: if (nDmaSoundControl & DMASNDCTRL_PLAY)
352: nActCount = nFrameStartAddr + (int)FrameCounter;
353: else
354: nActCount = (IoMem[0xff8903] << 16) | (IoMem[0xff8905] << 8) | IoMem[0xff8907];
355:
356: nActCount &= ~1;
357:
358: return nActCount;
359: }
360:
361:
362: /*-----------------------------------------------------------------------*/
1.1.1.3 root 363: /**
364: * Read word from sound control register (0xff8900).
365: */
1.1 root 366: void DmaSnd_SoundControl_ReadWord(void)
367: {
368: IoMem_WriteWord(0xff8900, nDmaSoundControl);
1.1.1.6 ! root 369:
! 370: LOG_TRACE(TRACE_DMASND, "DMA snd control write: 0x%04x\n", nDmaSoundControl);
1.1 root 371: }
372:
373:
374: /*-----------------------------------------------------------------------*/
1.1.1.3 root 375: /**
376: * Write word to sound control register (0xff8900).
1.1.1.4 root 377: *
378: * FIXME: add Falcon specific handler here...
1.1.1.3 root 379: */
1.1 root 380: void DmaSnd_SoundControl_WriteWord(void)
381: {
382: Uint16 nNewSndCtrl;
383:
1.1.1.6 ! root 384: LOG_TRACE(TRACE_DMASND, "DMA snd control write: 0x%04x\n", IoMem_ReadWord(0xff8900));
! 385:
1.1 root 386: nNewSndCtrl = IoMem_ReadWord(0xff8900) & 3;
387:
388: if (!(nDmaSoundControl & DMASNDCTRL_PLAY) && (nNewSndCtrl & DMASNDCTRL_PLAY))
389: {
390: //fprintf(stderr, "Turning on DMA sound emulation.\n");
391: DmaSnd_StartNewFrame();
392: }
393: else if ((nDmaSoundControl & DMASNDCTRL_PLAY) && !(nNewSndCtrl & DMASNDCTRL_PLAY))
394: {
395: //fprintf(stderr, "Turning off DMA sound emulation.\n");
396: }
397:
398: nDmaSoundControl = nNewSndCtrl;
399: }
400:
401:
402: /*-----------------------------------------------------------------------*/
1.1.1.3 root 403: /**
404: * Read word from sound frame count high register (0xff8909).
405: */
1.1 root 406: void DmaSnd_FrameCountHigh_ReadByte(void)
407: {
408: IoMem_WriteByte(0xff8909, DmaSnd_GetFrameCount() >> 16);
409: }
410:
411:
412: /*-----------------------------------------------------------------------*/
1.1.1.3 root 413: /**
414: * Read word from sound frame count medium register (0xff890b).
415: */
1.1 root 416: void DmaSnd_FrameCountMed_ReadByte(void)
417: {
418: IoMem_WriteByte(0xff890b, DmaSnd_GetFrameCount() >> 8);
419: }
420:
421:
422: /*-----------------------------------------------------------------------*/
1.1.1.3 root 423: /**
424: * Read word from sound frame count low register (0xff890d).
425: */
1.1 root 426: void DmaSnd_FrameCountLow_ReadByte(void)
427: {
428: IoMem_WriteByte(0xff890d, DmaSnd_GetFrameCount());
429: }
430:
431:
432: /*-----------------------------------------------------------------------*/
1.1.1.3 root 433: /**
434: * Read word from sound mode register (0xff8920).
435: */
1.1 root 436: void DmaSnd_SoundMode_ReadWord(void)
437: {
438: IoMem_WriteWord(0xff8920, nDmaSoundMode);
1.1.1.6 ! root 439:
! 440: LOG_TRACE(TRACE_DMASND, "DMA snd mode read: 0x%04x\n", nDmaSoundMode);
1.1 root 441: }
442:
443:
444: /*-----------------------------------------------------------------------*/
1.1.1.3 root 445: /**
446: * Write word to sound mode register (0xff8920).
447: */
1.1 root 448: void DmaSnd_SoundMode_WriteWord(void)
449: {
1.1.1.6 ! root 450: LOG_TRACE(TRACE_DMASND, "DMA snd mode write: 0x%04x\n", IoMem_ReadWord(0xff8920));
1.1.1.3 root 451:
452: /* Falcon has meaning in almost all bits of SND_SMC */
453: if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
454: {
455: nDmaSoundMode = IoMem_ReadWord(0xff8920);
456: /* FIXME: add code here to evaluate Falcon specific settings */
1.1.1.4 root 457:
458:
1.1.1.3 root 459: } else {
460: /* STE or TT - hopefully STFM emulation never gets here :)
461: * we maskout the Falcon only bits so we only hit bits that exist on a real STE
462: */
463: nDmaSoundMode = (IoMem_ReadWord(0xff8920)&0x008F);
464: /* we also write the masked value back into the emulated hw registers so we have a correct value there */
465: IoMem_WriteWord(0xff8920,nDmaSoundMode);
466: }
1.1 root 467: }
468:
469:
1.1.1.6 ! root 470: /* ---------------------- Microwire / LMC 1992 ---------------------- */
! 471:
1.1.1.3 root 472: /**
1.1.1.4 root 473: * Handle the shifting/rotating of the microwire registers
474: * The microwire regs should be done after 16 usec = 32 NOPs = 128 cycles.
475: * That means we have to shift 16 times with a delay of 8 cycles.
1.1.1.3 root 476: */
1.1.1.4 root 477: void DmaSnd_InterruptHandler_Microwire(void)
1.1 root 478: {
1.1.1.4 root 479: /* Remove this interrupt from list and re-order */
480: Int_AcknowledgeInterrupt();
481:
482: --nMwTransferSteps;
483:
484: /* Shift data register until it becomes zero. */
485: if (nMwTransferSteps > 1)
1.1 root 486: {
1.1.1.4 root 487: IoMem_WriteWord(0xff8922, nMicrowireData<<(16-nMwTransferSteps));
1.1 root 488: }
489: else
490: {
1.1.1.4 root 491: /* Paradox XMAS 2004 demo continuesly writes to the data
492: * register, but still expects to read a zero inbetween,
493: * so we have to output a zero before we're really done
494: * with the transfer. */
1.1 root 495: IoMem_WriteWord(0xff8922, 0);
496: }
1.1.1.4 root 497:
498: /* Rotate mask register */
499: IoMem_WriteWord(0xff8924, (nMicrowireMask<<(16-nMwTransferSteps))
500: |(nMicrowireMask>>nMwTransferSteps));
501:
502: if (nMwTransferSteps > 0)
503: {
504: Int_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE);
505: }
506: }
507:
508:
509: /**
510: * Read word from microwire data register (0xff8922).
511: */
512: void DmaSnd_MicrowireData_ReadWord(void)
513: {
514: /* Shifting is done in DmaSnd_InterruptHandler_Microwire! */
1.1.1.6 ! root 515: LOG_TRACE(TRACE_DMASND, "Microwire data read: 0x%x\n", IoMem_ReadWord(0xff8922));
1.1 root 516: }
517:
518:
1.1.1.3 root 519: /**
520: * Write word to microwire data register (0xff8922).
521: */
1.1 root 522: void DmaSnd_MicrowireData_WriteWord(void)
523: {
1.1.1.4 root 524: /* Only update, if no shift is in progress */
525: if (!nMwTransferSteps)
526: {
527: nMicrowireData = IoMem_ReadWord(0xff8922);
528: /* Start shifting events to simulate a microwire transfer */
529: nMwTransferSteps = 16;
530: Int_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE);
531: }
532:
1.1.1.6 ! root 533: LOG_TRACE(TRACE_DMASND, "Microwire data write: 0x%x\n", IoMem_ReadWord(0xff8922));
1.1 root 534: }
535:
536:
1.1.1.3 root 537: /**
538: * Read word from microwire mask register (0xff8924).
539: */
1.1 root 540: void DmaSnd_MicrowireMask_ReadWord(void)
541: {
1.1.1.4 root 542: /* Same as with data register, but mask is rotated, not shifted. */
1.1.1.6 ! root 543: LOG_TRACE(TRACE_DMASND, "Microwire mask read: 0x%x\n", IoMem_ReadWord(0xff8924));
1.1 root 544: }
545:
546:
1.1.1.3 root 547: /**
548: * Write word to microwire mask register (0xff8924).
549: */
1.1 root 550: void DmaSnd_MicrowireMask_WriteWord(void)
551: {
1.1.1.4 root 552: /* Only update, if no shift is in progress */
553: if (!nMwTransferSteps)
554: {
555: nMicrowireMask = IoMem_ReadWord(0xff8924);
556: }
557:
1.1.1.6 ! root 558: LOG_TRACE(TRACE_DMASND, "Microwire mask write: 0x%x\n", IoMem_ReadWord(0xff8924));
! 559: }
! 560:
! 561:
! 562: /* ---------------------- Falcon sound subsystem ---------------------- */
! 563:
! 564:
! 565: static void DmaSnd_StartDspXmitHandler(void)
! 566: {
! 567: Uint16 nCbSrc = IoMem_ReadWord(0xff8930);
! 568: int nFreq;
! 569: int nClkDiv;
! 570:
! 571: /* Ignore when DSP XMIT is connected to external port */
! 572: if ((nCbSrc & 0x80) == 0x00)
! 573: return;
! 574:
! 575: nClkDiv = 256 * ((IoMem_ReadByte(0xff8935) & 0x0f) + 1);
! 576:
! 577: if ((nCbSrc & 0x60) == 0x00)
! 578: {
! 579: /* Internal 25.175 MHz clock */
! 580: nFreq = 25175000 / nClkDiv;
! 581: Int_AddRelativeInterrupt((8013000+nFreq/2)/nFreq/2, INT_CPU_CYCLE, INTERRUPT_DSPXMIT);
! 582: }
! 583: else if ((nCbSrc & 0x60) == 0x20)
! 584: {
! 585: /* Internal 32 MHz clock */
! 586: nFreq = 32000000 / nClkDiv;
! 587: Int_AddRelativeInterrupt((8013000+nFreq/2)/nFreq/2, INT_CPU_CYCLE, INTERRUPT_DSPXMIT);
! 588: }
! 589:
! 590: /* Put last sample into buffer */
! 591: DspOutBuffer[nDspOutWrPos] = DSP_SsiReadTxValue();
! 592:
! 593: nDspOutWrPos = (nDspOutWrPos + 1) % (MIXBUFFER_SIZE*2);
! 594: nDspBufSamples += 1;
! 595: }
! 596:
! 597:
! 598: void DmaSnd_InterruptHandler_DspXmit(void)
! 599: {
! 600: /* Remove this interrupt from list and re-order */
! 601: Int_AcknowledgeInterrupt();
! 602:
! 603: /* TODO: Trigger SSI transmit interrupt in the DSP and fetch the data,
! 604: * then distribute the data to the destinations */
! 605:
! 606: DSP_SsiReceive_SC2(FrameCounter);
! 607: DSP_SsiReceiveSerialClock();
! 608:
! 609: /* Restart the Int event handler */
! 610: DmaSnd_StartDspXmitHandler();
! 611:
! 612: }
! 613:
! 614:
! 615: /**
! 616: * Read word from Falcon crossbar source register (0xff8930).
! 617: */
! 618: void DmaSnd_CrossbarSrc_ReadWord(void)
! 619: {
! 620: LOG_TRACE(TRACE_DMASND, "Falcon snd crossbar src read: 0x%04x\n", IoMem_ReadWord(0xff8930));
! 621: }
! 622:
! 623: /**
! 624: * Write word to Falcon crossbar source register (0xff8930).
! 625: */
! 626: void DmaSnd_CrossbarSrc_WriteWord(void)
! 627: {
! 628: Uint16 nCbSrc = IoMem_ReadWord(0xff8930);
! 629:
! 630: LOG_TRACE(TRACE_DMASND, "Falcon snd crossbar src write: 0x%04x\n", nCbSrc);
! 631:
! 632: DmaSnd_StartDspXmitHandler();
! 633: }
! 634:
! 635: /**
! 636: * Read word from Falcon crossbar destination register (0xff8932).
! 637: */
! 638: void DmaSnd_CrossbarDst_ReadWord(void)
! 639: {
! 640: LOG_TRACE(TRACE_DMASND, "Falcon snd crossbar dst read: 0x%04x\n", IoMem_ReadWord(0xff8932));
! 641: }
! 642:
! 643: /**
! 644: * Write word to Falcon crossbar destination register (0xff8932).
! 645: */
! 646: void DmaSnd_CrossbarDst_WriteWord(void)
! 647: {
! 648: LOG_TRACE(TRACE_DMASND, "Falcon snd crossbar dst write: 0x%04x\n", IoMem_ReadWord(0xff8932));
! 649: }
! 650:
! 651: /**
! 652: * Read byte from external clock divider register (0xff8934).
! 653: */
! 654: void DmaSnd_FreqDivExt_ReadByte(void)
! 655: {
! 656: LOG_TRACE(TRACE_DMASND, "Falcon snd ext. clock divider read: 0x%02x\n", IoMem_ReadByte(0xff8934));
! 657: }
! 658:
! 659: /**
! 660: * Write byte to external clock divider register (0xff8934).
! 661: */
! 662: void DmaSnd_FreqDivExt_WriteByte(void)
! 663: {
! 664: LOG_TRACE(TRACE_DMASND, "Falcon snd ext. clock divider write: 0x%02x\n", IoMem_ReadByte(0xff8934));
! 665: }
! 666:
! 667: /**
! 668: * Write byte to internal clock divider register (0xff8935).
! 669: */
! 670: void DmaSnd_FreqDivInt_ReadByte(void)
! 671: {
! 672: LOG_TRACE(TRACE_DMASND, "Falcon snd int. clock divider read: 0x%02x\n", IoMem_ReadByte(0xff8935));
! 673: }
! 674:
! 675: /**
! 676: * Write byte to internal clock divider register (0xff8935).
! 677: */
! 678: void DmaSnd_FreqDivInt_WriteByte(void)
! 679: {
! 680: LOG_TRACE(TRACE_DMASND, "Falcon snd int. clock divider write: 0x%02x\n", IoMem_ReadByte(0xff8935));
! 681: }
! 682:
! 683: /**
! 684: * Read byte from track record control register (0xff8936).
! 685: */
! 686: void DmaSnd_TrackRecCtrl_ReadByte(void)
! 687: {
! 688: LOG_TRACE(TRACE_DMASND, "Falcon snd track record control read: 0x%02x\n", IoMem_ReadByte(0xff8936));
! 689: }
! 690:
! 691: /**
! 692: * Write byte to track record control register (0xff8936).
! 693: */
! 694: void DmaSnd_TrackRecCtrl_WriteByte(void)
! 695: {
! 696: LOG_TRACE(TRACE_DMASND, "Falcon snd track record control write: 0x%02x\n", IoMem_ReadByte(0xff8936));
! 697: }
! 698:
! 699: /**
! 700: * Read byte from CODEC input register (0xff8937).
! 701: */
! 702: void DmaSnd_CodecInput_ReadByte(void)
! 703: {
! 704: LOG_TRACE(TRACE_DMASND, "Falcon snd CODEC input read: 0x%02x\n", IoMem_ReadByte(0xff8937));
! 705: }
! 706:
! 707: /**
! 708: * Write byte to CODEC input register (0xff8937).
! 709: */
! 710: void DmaSnd_CodecInput_WriteByte(void)
! 711: {
! 712: LOG_TRACE(TRACE_DMASND, "Falcon snd CODEC input write: 0x%02x\n", IoMem_ReadByte(0xff8937));
! 713: }
! 714:
! 715: /**
! 716: * Read byte from A/D converter input register (0xff8938).
! 717: */
! 718: void DmaSnd_AdcInput_ReadByte(void)
! 719: {
! 720: LOG_TRACE(TRACE_DMASND, "Falcon snd ADC input read: 0x%02x\n", IoMem_ReadByte(0xff8938));
! 721: }
! 722:
! 723: /**
! 724: * Write byte to A/D converter input register (0xff8938).
! 725: */
! 726: void DmaSnd_AdcInput_WriteByte(void)
! 727: {
! 728: LOG_TRACE(TRACE_DMASND, "Falcon snd ADC input write: 0x%02x\n", IoMem_ReadByte(0xff8938));
! 729: }
! 730:
! 731: /**
! 732: * Read byte from input amplifier register (0xff8939).
! 733: */
! 734: void DmaSnd_InputAmp_ReadByte(void)
! 735: {
! 736: }
! 737:
! 738: /**
! 739: * Write byte to input amplifier register (0xff8939).
! 740: */
! 741: void DmaSnd_InputAmp_WriteByte(void)
! 742: {
! 743: }
! 744:
! 745: /**
! 746: * Read word from output reduction register (0xff893a).
! 747: */
! 748: void DmaSnd_OutputReduct_ReadWord(void)
! 749: {
! 750: }
! 751:
! 752: /**
! 753: * Write word to output reduction register (0xff893a).
! 754: */
! 755: void DmaSnd_OutputReduct_WriteWord(void)
! 756: {
! 757: }
! 758:
! 759: /**
! 760: * Read word from CODEC status register (0xff893c).
! 761: */
! 762: void DmaSnd_CodecStatus_ReadWord(void)
! 763: {
! 764: LOG_TRACE(TRACE_DMASND, "Falcon snd CODEC status read: 0x%04x\n", IoMem_ReadWord(0xff893c));
! 765: }
! 766:
! 767: /**
! 768: * Write word to CODEC status register (0xff893c).
! 769: */
! 770: void DmaSnd_CodecStatus_WriteWord(void)
! 771: {
! 772: LOG_TRACE(TRACE_DMASND, "Falcon snd CODEC status write: 0x%04x\n", IoMem_ReadWord(0xff893c));
1.1 root 773: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.