Annotation of hatari/src/dmaSnd.c, revision 1.1.1.6

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.