Annotation of hatari/src/falcon/crossbar.c, revision 1.1

1.1     ! root        1: /*
        !             2:   Hatari - Crossbar.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:   Falcon Crossbar (Matrice) emulation.
        !             8:   input device:        
        !             9:                - DSP transmit (SSI)
        !            10:                - external DSP connector
        !            11:                - ADC (micro + PSG chip)
        !            12:                - DMA playback
        !            13: 
        !            14:   output device:
        !            15:                - external DSP connector
        !            16:                - DSP receive (SSI)
        !            17:                - DAC (headphone, loudspeaker and monitor sound)
        !            18:                - DMA record
        !            19: 
        !            20:   There are 3 possible clocks :
        !            21:                - internal clock 25,175 MHz (Ste compatible)
        !            22:                - internal clock 32 MHz
        !            23:                - external clock (DSP external port, up to 32 Mhz)
        !            24: 
        !            25:   Transfers between 2 devices can use handshaking or continuous mode 
        !            26: 
        !            27:   Hardware I/O registers:
        !            28:     $FF8900 (byte) : Sound DMA control
        !            29:     $FF8901 (byte) : Sound DMA control
        !            30:     $FF8903 (byte) : Frame Start Hi
        !            31:     $FF8905 (byte) : Frame Start Mi
        !            32:     $FF8907 (byte) : Frame Start Lo
        !            33:     $FF8909 (byte) : Frame Count Hi
        !            34:     $FF890B (byte) : Frame Count Mi
        !            35:     $FF890D (byte) : Frame Count Lo
        !            36:     $FF890F (byte) : Frame End Hi
        !            37:     $FF8911 (byte) : Frame End Mi
        !            38:     $FF8913 (byte) : Frame End Lo
        !            39:     $FF8920 (byte) : Sound Mode Control
        !            40:     $FF8921 (byte) : Sound Mode Control
        !            41:     $FF8930 (word) : DMA Crossbar Input Select Controller
        !            42:     $FF8932 (word) : DMA Crossbar Output Select Controller
        !            43:     $FF8934 (byte) : External Sync Frequency Divider
        !            44:     $FF8935 (byte) : Internal Sync Frequency Divider
        !            45:     $FF8936 (byte) : Record Track select
        !            46:     $FF8937 (byte) : Codec Input Source
        !            47:     $FF8938 (byte) : Codec ADC Input
        !            48:     $FF8939 (byte) : Gain Settings Per Channel
        !            49:     $FF893A (byte) : Attenuation Settings Per Channel
        !            50:     $FF893C (word) : Codec Status
        !            51:     $FF8940 (word) : GPIO Data Direction
        !            52:     $FF8942 (word) : GPIO Data
        !            53: 
        !            54: 
        !            55:     Crossbar schematics:
        !            56:     
        !            57:        - one receiving device can be connected to only one source device
        !            58:        - one source device can be connected to multiple receiving device
        !            59: 
        !            60:                            Source devices
        !            61:                                                CROSSBAR
        !            62:                              EXT INPUT ---O------O------O-----O
        !            63:                               CHANNEL     |      |      |     |
        !            64:                                           |      |      |     |
        !            65:                                  DSP   ---O------O------O-----O
        !            66:                               TRANSMIT    |      |      |     |
        !            67:                                           |      |      |     |
        !            68:    Mic L -----|                  DMA   ---O------O------O-----O
        !            69:           /---|XOR ----|\     PLAYBACK    |      |      |     |      
        !            70:    PSG --|             | \                |      |      |     |
        !            71:           \---|        | /-------X--------O------O------O-----O
        !            72:    Mic R -----|XOR ----|/        |        |      |      |     |
        !            73:                        ADC       |        |      DMA    DSP   EXT OUTPUT      Receiving Devices
        !            74:                                  |        |    RECEIVE CHANNEL
        !            75:                                  |        |
        !            76:                               -----------------
        !            77:                                \      +      /
        !            78:                                 \-----------/
        !            79:                                       |
        !            80:                                       |
        !            81:                                     -----
        !            82:                                     \   / DAC
        !            83:                                      \ /
        !            84:                                       |
        !            85:                                       |
        !            86:                                 Output to:
        !            87:                                    - header, 
        !            88:                                    - internal speaker, 
        !            89:                                    - monitor speaker   
        !            90: */
        !            91: 
        !            92: const char crossbar_fileid[] = "Hatari Crossbar.c : " __DATE__ " " __TIME__;
        !            93: 
        !            94: #include "main.h"
        !            95: #include "audio.h"
        !            96: #include "configuration.h"
        !            97: #include "cycInt.h"
        !            98: #include "ioMem.h"
        !            99: #include "log.h"
        !           100: #include "memorySnapShot.h"
        !           101: #include "mfp.h"
        !           102: #include "sound.h"
        !           103: #include "crossbar.h"
        !           104: #include "microphone.h"
        !           105: #include "stMemory.h"
        !           106: #include "dsp.h"
        !           107: 
        !           108: 
        !           109: #define DACBUFFER_SIZE    2048
        !           110: #define DECIMAL_PRECISION 65536
        !           111: 
        !           112: 
        !           113: /* Crossbar internal functions */
        !           114: static double Crossbar_DetectSampleRate(Uint16 clock);
        !           115: static void Crossbar_Recalculate_Clocks_Cycles(void);
        !           116: static void Crossbar_Start_InterruptHandler_25Mhz(void);
        !           117: static void Crossbar_Start_InterruptHandler_32Mhz(void);
        !           118: 
        !           119: /* Dma_Play sound functions */
        !           120: static void Crossbar_setDmaPlay_Settings(void);
        !           121: static void Crossbar_Process_DMAPlay_Transfer(void);
        !           122: 
        !           123: /* Dma_Record sound functions */
        !           124: static void Crossbar_setDmaRecord_Settings(void);
        !           125: void Crossbar_SendDataToDmaRecord(Sint16 value);
        !           126: static void Crossbar_Process_DMARecord_HandshakeMode(void);
        !           127: 
        !           128: /* Dsp Xmit functions */
        !           129: static void Crossbar_SendDataToDspReceive(Uint32 value, Uint16 frame);
        !           130: static void Crossbar_Process_DSPXmit_Transfer(void);
        !           131: 
        !           132: /* DAC functions */
        !           133: static void Crossbar_SendDataToDAC(Sint16 value, Uint16 sample_pos);
        !           134: 
        !           135: /* ADC functions */
        !           136: static void Crossbar_Process_ADCXmit_Transfer(void);
        !           137: 
        !           138: /* external data used by the MFP */
        !           139: Uint16 nCbar_DmaSoundControl;
        !           140: 
        !           141: /* internal datas */
        !           142: 
        !           143: /* dB = 20log(gain)  :  gain = antilog(dB/20)                                  */
        !           144: /* Table gain values = (int)(powf(10.0, dB/20.0)*65536.0 + 0.5)  1.5dB steps   */
        !           145: 
        !           146: /* Values for Codec's ADC volume control (* DECIMAL_PRECISION) */
        !           147: /* PSG must be amplified by 2.66.. before mixing with crossbar */
        !           148: /* The ADC table values are multiplied by 2'2/3 and divided    */
        !           149: /* by 4 (later multplied by 4) eg 43691 = 65536 * 2.66.. / 4.0 */
        !           150: static const Uint16 Crossbar_ADC_volume_table[16] =
        !           151: {
        !           152:        3276,   3894,   4628,   5500,   6537,   7769,   9234,   10975,
        !           153:        13043,  15502,  18424,  21897,  26025,  30931,  36761,  43691
        !           154: };
        !           155: 
        !           156: /* Values for Codec's DAC volume control (* DECIMAL_PRECISION) */
        !           157: static const Uint16 Crossbar_DAC_volume_table[16] =
        !           158: {
        !           159:        65535,  55142,  46396,  39037,  32846,  27636,  23253,  19565,
        !           160:        16462,  13851,  11654,  9806,   8250,   6942,   5841,   4915
        !           161: };
        !           162: 
        !           163: static const double Ste_SampleRates[4] =
        !           164: {
        !           165:        6258.0,
        !           166:        12517.0,
        !           167:        25033.0,
        !           168:        50066.0
        !           169: };
        !           170: 
        !           171: static const double Falcon_SampleRates_25Mhz[15] =
        !           172: {
        !           173:        49170.0,
        !           174:        32780.0,
        !           175:        24585.0,
        !           176:        19668.0,
        !           177:        16390.0,
        !           178:        14049.0,
        !           179:        12292.0,
        !           180:        10927.0,
        !           181:         9834.0,
        !           182:         8940.0,
        !           183:         8195.0,
        !           184:         7565.0,
        !           185:         7024.0,
        !           186:         6556.0,
        !           187:         6146.0
        !           188: };
        !           189: 
        !           190: static const double Falcon_SampleRates_32Mhz[15] =
        !           191: {
        !           192:        62500.0,
        !           193:        41666.0,
        !           194:        31250.0,
        !           195:        25000.0,
        !           196:        20833.0,
        !           197:        17857.0,
        !           198:        15624.0,
        !           199:        13889.0,
        !           200:        12500.0,
        !           201:        11363.0,
        !           202:        10416.0,
        !           203:        9615.0,
        !           204:        8928.0,
        !           205:        8333.0,
        !           206:        7812.0
        !           207: };
        !           208: 
        !           209: struct dma_s {
        !           210:        Uint32 frameStartAddr;          /* Sound frame start */
        !           211:        Uint32 frameEndAddr;            /* Sound frame end */
        !           212:        Uint32 frameCounter;            /* Counter in current sound frame */
        !           213:        Uint32 frameLen;                /* Length of the frame */
        !           214:        Uint32 isRunning;               /* Is Playing / Recording ? */
        !           215:        Uint32 loopMode;                /* Loop mode enabled ? */
        !           216:        Uint32 currentFrame;            /* Current Frame Played / Recorded (in stereo, 2 frames = 1 track) */
        !           217:        Uint32 timerA_int;              /* Timer A interrupt at end of Play / Record ? */
        !           218:        Uint32 mfp15_int;               /* MFP-15 interrupt at end of Play / Record ? */
        !           219:        Uint32 isConnectedToCodec;
        !           220:        Uint32 isConnectedToDsp;
        !           221:        Uint32 isConnectedToDspInHandShakeMode;
        !           222:        Uint32 isConnectedToDma;
        !           223:        Uint32 handshakeMode_Frame;     /* state of the frame in handshake mode */
        !           224: };
        !           225: 
        !           226: struct crossbar_s {
        !           227:        Uint32 dmaSelected;             /* 1 = DMA Record; 0 = DMA Play */
        !           228:        Uint32 playTracks;              /* number of tracks played */
        !           229:        Uint32 recordTracks;            /* number of tracks recorded */
        !           230:        Uint16 track_monitored;         /* track monitored by the DAC */
        !           231:        Uint32 is16Bits;                /* 0 = 8 bits; 1 = 16 bits */
        !           232:        Uint32 isStereo;                /* 0 = mono; 1 = stereo */
        !           233:        Uint32 steFreq;                 /* from 0 (6258 Hz) to 3 (50066 Hz) */
        !           234:        Uint32 isInSteFreqMode;         /* 0 = Falcon frequency mode ; 1 = Ste frequency mode */
        !           235:        Uint32 int_freq_divider;        /* internal frequency divider */
        !           236:        Uint32 isDacMuted;              /* 0 = DAC is running; 1 = DAC is muted */
        !           237:        Uint32 dspXmit_freq;            /* 0 = 25 Mhz ; 1 = external clock ; 2 = 32 Mhz */
        !           238:        Uint32 dmaPlay_freq;            /* 0 = 25 Mhz ; 1 = external clock ; 2 = 32 Mhz */
        !           239:        Uint16 codecInputSource;        /* codec input source */
        !           240:        Uint16 codecAdcInput;           /* codec ADC input */
        !           241:        Uint16 gainSettingLeft;         /* Left channel gain for ADC */
        !           242:        Uint16 gainSettingRight;        /* Right channel gain for ADC */
        !           243:        Uint16 attenuationSettingLeft;  /* Left channel attenuation for DAC */
        !           244:        Uint16 attenuationSettingRight; /* Right channel attenuation for DAC */
        !           245:        Uint16 microphone_ADC_is_started;
        !           246:        
        !           247:        Uint32 clock25_cycles;          /* cycles for 25 Mzh interrupt */
        !           248:        Uint32 clock25_cycles_decimal;  /* decimal part of cycles counter for 25 Mzh interrupt (*DECIMAL_PRECISION) */
        !           249:        Uint32 clock25_cycles_counter;  /* Cycle counter for 25 Mhz interrupts */
        !           250:        Uint32 pendingCyclesOver25;     /* Number of delayed cycles for the interrupt */
        !           251:        Uint32 clock32_cycles;          /* cycles for 32 Mzh interrupt */
        !           252:        Uint32 clock32_cycles_decimal;  /* decimal part of cycles counter for 32 Mzh interrupt (*DECIMAL_PRECISION) */
        !           253:        Uint32 clock32_cycles_counter;  /* Cycle counter for 32 Mhz interrupts */
        !           254:        Uint32 pendingCyclesOver32;     /* Number of delayed cycles for the interrupt */
        !           255:        Uint32 frequence_ratio;         /* Ratio between host computer's sound frequency and hatari's sound frequency */
        !           256:        Uint32 frequence_ratio2;        /* Ratio between hatari's sound frequency and host computer's sound frequency */
        !           257:        
        !           258:        Uint32 dmaPlay_CurrentFrameStart;   /* current DmaPlay Frame start ($ff8903 $ff8905 $ff8907) */
        !           259:        Uint32 dmaPlay_CurrentFrameCount;   /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */
        !           260:        Uint32 dmaPlay_CurrentFrameEnd;     /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */
        !           261:        Uint32 dmaRecord_CurrentFrameStart; /* current DmaPlay Frame end ($ff890f $ff8911 $ff8913) */
        !           262:        Uint32 dmaRecord_CurrentFrameCount; /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */
        !           263:        Uint32 dmaRecord_CurrentFrameEnd;   /* current DmaRecord Frame end ($ff890f $ff8911 $ff8913) */
        !           264:        Uint32 adc_dac_readBufferPosition;  /* read position for direct adc->dac transfer */
        !           265:        Uint32 adc_dac_readBufferPosition_decimal; /* decimal part of read position for direct adc->dac transfer */
        !           266: };
        !           267: 
        !           268: struct codec_s {
        !           269:        Sint16 buffer_left[DACBUFFER_SIZE];
        !           270:        Sint16 buffer_right[DACBUFFER_SIZE];
        !           271:        Uint32 readPosition;
        !           272:        Uint32 readPosition_decimal;
        !           273:        Uint32 writePosition;
        !           274:        Uint32 isConnectedToCodec;
        !           275:        Uint32 isConnectedToDsp;
        !           276:        Uint32 isConnectedToDma;
        !           277:        Uint32 wordCount;
        !           278: };
        !           279: 
        !           280: struct dsp_s {
        !           281:        Uint32 isTristated;             /* 0 = DSP is not tristated; 1 = DSP is tristated */
        !           282:        Uint32 isInHandshakeMode;       /* 0 = not in hanshake mode; 1 = in hanshake mode */
        !           283:        Uint32 isConnectedToCodec;
        !           284:        Uint32 isConnectedToDsp;
        !           285:        Uint32 isConnectedToDma;
        !           286:        Uint32 wordCount;               /* count number of words received from DSP transmitter (for TX frame computing) */
        !           287: };
        !           288: 
        !           289: static struct crossbar_s crossbar;
        !           290: static struct dma_s dmaPlay;
        !           291: static struct dma_s dmaRecord;
        !           292: static struct codec_s dac;
        !           293: static struct codec_s adc;
        !           294: static struct dsp_s dspXmit;
        !           295: static struct dsp_s dspReceive;
        !           296: 
        !           297: /**
        !           298:  * Reset Crossbar variables.
        !           299:  */
        !           300: void Crossbar_Reset(bool bCold)
        !           301: {
        !           302:        nCbar_DmaSoundControl = 0;
        !           303: 
        !           304:        if (bCold)
        !           305:        {
        !           306:        }
        !           307:        
        !           308:        /* Stop DMA sound playing / record */
        !           309:        IoMem_WriteByte(0xff8901,0);
        !           310:        dmaPlay.isRunning = 0;
        !           311:        dmaPlay.loopMode = 0;
        !           312:        dmaPlay.currentFrame = 0;
        !           313:        dmaPlay.isConnectedToDspInHandShakeMode = 0;
        !           314:        dmaPlay.handshakeMode_Frame = 0;
        !           315:        dmaRecord.isRunning = 0;
        !           316:        dmaRecord.loopMode = 0;
        !           317:        dmaRecord.currentFrame = 0;
        !           318:        dmaRecord.isConnectedToDspInHandShakeMode = 0;
        !           319:        dmaRecord.handshakeMode_Frame = 0;
        !           320: 
        !           321:        /* DAC inits */
        !           322:        memset(dac.buffer_left, 0, sizeof(dac.buffer_left));
        !           323:        memset(dac.buffer_right, 0, sizeof(dac.buffer_right));
        !           324:        dac.readPosition = 0;
        !           325:        dac.readPosition_decimal = 0;
        !           326:        dac.writePosition = 0;
        !           327: 
        !           328:        /* ADC inits */
        !           329:        memset(adc.buffer_left, 0, sizeof(dac.buffer_left));
        !           330:        memset(adc.buffer_right, 0, sizeof(dac.buffer_right));
        !           331:        adc.readPosition = 0;
        !           332:        adc.readPosition_decimal = 0;
        !           333:        adc.writePosition = 0;
        !           334: 
        !           335:        /* DSP inits */
        !           336:        dspXmit.wordCount = 0;
        !           337: 
        !           338:        /* Crossbar inits */
        !           339:        crossbar.clock25_cycles = 160;
        !           340:        crossbar.clock25_cycles_decimal = 0;
        !           341:        crossbar.clock25_cycles_counter = 0;
        !           342:        crossbar.pendingCyclesOver25 = 0;
        !           343:        crossbar.clock32_cycles = 160;
        !           344:        crossbar.clock32_cycles_decimal = 0;
        !           345:        crossbar.clock32_cycles_counter = 0;
        !           346:        crossbar.pendingCyclesOver32 = 0;
        !           347:        crossbar.frequence_ratio = 0;
        !           348:        crossbar.frequence_ratio2 = 0;
        !           349: 
        !           350:        crossbar.dmaSelected = 0;
        !           351:        crossbar.track_monitored = 0;
        !           352:        crossbar.isInSteFreqMode = 1;
        !           353:        crossbar.int_freq_divider = 0;
        !           354:        crossbar.steFreq = 3;
        !           355:        crossbar.playTracks = 1;
        !           356:        crossbar.is16Bits = 0;
        !           357:        crossbar.isStereo = 1;
        !           358:        crossbar.codecInputSource = 3;
        !           359:        crossbar.codecAdcInput = 3;
        !           360:        crossbar.gainSettingLeft = 3276;
        !           361:        crossbar.gainSettingRight = 3276;
        !           362:        crossbar.attenuationSettingLeft = 65535;
        !           363:        crossbar.attenuationSettingRight = 65535;
        !           364:        crossbar.adc_dac_readBufferPosition = 0;
        !           365:        crossbar.adc_dac_readBufferPosition_decimal = 0;
        !           366: 
        !           367:        /* Start 25 Mhz and 32 Mhz Clocks */
        !           368:        Crossbar_Recalculate_Clocks_Cycles();
        !           369:        Crossbar_Start_InterruptHandler_25Mhz();
        !           370:        Crossbar_Start_InterruptHandler_32Mhz();
        !           371: 
        !           372:        /* Start Microphone jack emulation */
        !           373:        if (crossbar.microphone_ADC_is_started == 0) { 
        !           374:                crossbar.microphone_ADC_is_started = Microphone_Start((int)nAudioFrequency);
        !           375:        }
        !           376: 
        !           377:        /* Initialize Crossbar values after reboot */
        !           378:        IoMem_WriteByte(0xff8900,0x05);
        !           379:        IoMem_WriteByte(0xff8903,0xff);
        !           380:        IoMem_WriteByte(0xff8905,0xff);
        !           381:        IoMem_WriteByte(0xff8907,0xfe);
        !           382:        IoMem_WriteByte(0xff8909,0xff);
        !           383:        IoMem_WriteByte(0xff890b,0xff);
        !           384:        IoMem_WriteByte(0xff890d,0xfe);
        !           385:        IoMem_WriteByte(0xff890f,0xff);
        !           386:        IoMem_WriteByte(0xff8911,0xff);
        !           387:        IoMem_WriteByte(0xff8913,0xfe);
        !           388:        IoMem_WriteWord(0xff893c,0x2401);
        !           389: }
        !           390: 
        !           391: /**
        !           392:  * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
        !           393:  */
        !           394: void Crossbar_MemorySnapShot_Capture(bool bSave)
        !           395: {
        !           396:        /* Save/Restore details */
        !           397:        MemorySnapShot_Store(&nCbar_DmaSoundControl, sizeof(nCbar_DmaSoundControl));
        !           398:        MemorySnapShot_Store(&dmaPlay, sizeof(dmaPlay));
        !           399:        MemorySnapShot_Store(&dmaRecord, sizeof(dmaRecord));
        !           400:        MemorySnapShot_Store(&crossbar, sizeof(crossbar));
        !           401:        MemorySnapShot_Store(&dac, sizeof(dac));
        !           402:        MemorySnapShot_Store(&adc, sizeof(adc));
        !           403:        MemorySnapShot_Store(&dspXmit, sizeof(dspXmit));
        !           404:        MemorySnapShot_Store(&dspReceive, sizeof(dspReceive));
        !           405: }
        !           406: 
        !           407: 
        !           408: /*----------------------------------------------------------------------*/
        !           409: /*     Hardware I/O functions                                          */
        !           410: /*----------------------------------------------------------------------*/
        !           411: 
        !           412: /**
        !           413:  * Write byte to buffer interrupts (0xff8900).
        !           414:  */
        !           415: void Crossbar_BufferInter_WriteByte(void)
        !           416: {
        !           417:        Uint8 dmaCtrl = IoMem_ReadByte(0xff8900);
        !           418: 
        !           419:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8900 (Sound DMA control) write: 0x%02x\n", dmaCtrl);
        !           420: 
        !           421:        dmaPlay.timerA_int   = (dmaCtrl & 0x4) >> 2;
        !           422:        dmaPlay.mfp15_int    = (dmaCtrl & 0x1);
        !           423:        dmaRecord.timerA_int = (dmaCtrl & 0x8) >> 3;
        !           424:        dmaRecord.mfp15_int  = (dmaCtrl & 0x2) >> 1;
        !           425: }
        !           426: 
        !           427: /**
        !           428:  * Write byte from DMA control register (0xff8901).
        !           429:  */
        !           430: void Crossbar_DmaCtrlReg_WriteByte(void)
        !           431: {
        !           432:        Uint8 sndCtrl = IoMem_ReadByte(0xff8901);
        !           433: 
        !           434:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8901 (additional Sound DMA control) write: 0x%02x\n", sndCtrl);
        !           435: 
        !           436:        crossbar.dmaSelected = (sndCtrl & 0x80) >> 7;
        !           437: 
        !           438:        /* DMA Play mode */
        !           439:        if ((dmaPlay.isRunning == 0) && (sndCtrl & CROSSBAR_SNDCTRL_PLAY))
        !           440:        {
        !           441:                /* Turning on DMA Play sound emulation */
        !           442:                dmaPlay.isRunning = 1;
        !           443:                nCbar_DmaSoundControl = sndCtrl;
        !           444:                dmaPlay.loopMode = (sndCtrl & 0x2) >> 1;
        !           445:                Crossbar_setDmaPlay_Settings();
        !           446:        }
        !           447:        else if (dmaPlay.isRunning && ((sndCtrl & CROSSBAR_SNDCTRL_PLAY) == 0))
        !           448:        {
        !           449:                /* Create samples up until this point with current values */
        !           450:                Sound_Update();
        !           451: 
        !           452:                /* Turning off DMA play sound emulation */
        !           453:                dmaPlay.isRunning = 0;
        !           454:                dmaPlay.loopMode = 0;
        !           455:                nCbar_DmaSoundControl = sndCtrl;
        !           456:                memset(dac.buffer_left, 0, sizeof(dac.buffer_left));
        !           457:                memset(dac.buffer_right, 0, sizeof(dac.buffer_right));
        !           458:        }
        !           459: 
        !           460:        /* DMA Record mode */
        !           461:        if ((dmaRecord.isRunning == 0) && (sndCtrl & CROSSBAR_SNDCTRL_RECORD))
        !           462:        {
        !           463:                /* Turning on DMA record sound emulation */
        !           464:                dmaRecord.isRunning = 1;
        !           465:                dmaRecord.loopMode = (sndCtrl & 0x20) >> 5;
        !           466:                nCbar_DmaSoundControl = sndCtrl;
        !           467:                Crossbar_setDmaRecord_Settings();
        !           468:        }
        !           469:        else if (dmaRecord.isRunning && ((sndCtrl & CROSSBAR_SNDCTRL_RECORD) == 0))
        !           470:        {
        !           471:                /* Turning off DMA record sound emulation */
        !           472:                nCbar_DmaSoundControl = sndCtrl;
        !           473:                dmaRecord.isRunning = 0;
        !           474:                dmaRecord.loopMode = 0;
        !           475:        }
        !           476: }
        !           477: 
        !           478: 
        !           479: /**
        !           480:  * Read byte from sound frame start high register (0xff8903).
        !           481:  */
        !           482: void Crossbar_FrameStartHigh_ReadByte(void)
        !           483: {
        !           484:        if (crossbar.dmaSelected == 0) {
        !           485:                /* DMA Play selected */
        !           486:                IoMem_WriteByte(0xff8903, crossbar.dmaPlay_CurrentFrameStart >> 16);
        !           487:        }
        !           488:        else {
        !           489:                /* DMA Record selected */
        !           490:                IoMem_WriteByte(0xff8903, crossbar.dmaRecord_CurrentFrameStart >> 16);
        !           491:        }
        !           492: }
        !           493: 
        !           494: /**
        !           495:  * Write byte to sound frame start high register (0xff8903).
        !           496:  */
        !           497: void Crossbar_FrameStartHigh_WriteByte(void)
        !           498: {
        !           499:        Uint32 addr;
        !           500: 
        !           501:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8903 (Sound frame start high) write: 0x%02x\n", IoMem_ReadByte(0xff8903));
        !           502: 
        !           503:        addr = (IoMem_ReadByte(0xff8903) << 16) + (IoMem_ReadByte(0xff8905) << 8) + IoMem_ReadByte(0xff8907);
        !           504: 
        !           505:        if (crossbar.dmaSelected == 0) {
        !           506:                /* DMA Play selected */
        !           507:                crossbar.dmaPlay_CurrentFrameStart = addr & ~1;
        !           508:        }
        !           509:        else {
        !           510:                /* DMA Record selected */
        !           511:                crossbar.dmaRecord_CurrentFrameStart = addr & ~1;
        !           512:        }
        !           513: }
        !           514: 
        !           515: /**
        !           516:  * Read byte from sound frame start medium register (0xff8905).
        !           517:  */
        !           518: void Crossbar_FrameStartMed_ReadByte(void)
        !           519: {
        !           520:        if (crossbar.dmaSelected == 0) {
        !           521:                /* DMA Play selected */
        !           522:                IoMem_WriteByte(0xff8905, crossbar.dmaPlay_CurrentFrameStart >> 8);
        !           523:        }
        !           524:        else {
        !           525:                /* DMA Record selected */
        !           526:                IoMem_WriteByte(0xff8905, crossbar.dmaRecord_CurrentFrameStart >> 8);
        !           527:        }
        !           528: }
        !           529: 
        !           530: /**
        !           531:  * Write byte to sound frame start medium register (0xff8905).
        !           532:  */
        !           533: void Crossbar_FrameStartMed_WriteByte(void)
        !           534: {
        !           535:        Uint32 addr;
        !           536: 
        !           537:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8905 (Sound frame start med) write: 0x%02x\n", IoMem_ReadByte(0xff8905));
        !           538: 
        !           539:        addr = (IoMem_ReadByte(0xff8903) << 16) + (IoMem_ReadByte(0xff8905) << 8) + IoMem_ReadByte(0xff8907);
        !           540: 
        !           541:        if (crossbar.dmaSelected == 0) {
        !           542:                /* DMA Play selected */
        !           543:                crossbar.dmaPlay_CurrentFrameStart = addr & ~1;
        !           544:        }
        !           545:        else {
        !           546:                /* DMA Record selected */
        !           547:                crossbar.dmaRecord_CurrentFrameStart = addr & ~1;
        !           548:        }
        !           549: }
        !           550: 
        !           551: /**
        !           552:  * Read byte from sound frame start low register (0xff8907).
        !           553:  */
        !           554: void Crossbar_FrameStartLow_ReadByte(void)
        !           555: {
        !           556:        if (crossbar.dmaSelected == 0) {
        !           557:                /* DMA Play selected */
        !           558:                IoMem_WriteByte(0xff8907, crossbar.dmaPlay_CurrentFrameStart);
        !           559:        }
        !           560:        else {
        !           561:                /* DMA Record selected */
        !           562:                IoMem_WriteByte(0xff8907, crossbar.dmaRecord_CurrentFrameStart);
        !           563:        }
        !           564: }
        !           565: 
        !           566: /**
        !           567:  * Write byte to sound frame start low register (0xff8907).
        !           568:  */
        !           569: void Crossbar_FrameStartLow_WriteByte(void)
        !           570: {
        !           571:        Uint32 addr;
        !           572: 
        !           573:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8907 (Sound frame start low) write: 0x%02x\n", IoMem_ReadByte(0xff8907));
        !           574: 
        !           575:        addr = (IoMem_ReadByte(0xff8903) << 16) + (IoMem_ReadByte(0xff8905) << 8) + IoMem_ReadByte(0xff8907);
        !           576: 
        !           577:        if (crossbar.dmaSelected == 0) {
        !           578:                /* DMA Play selected */
        !           579:                crossbar.dmaPlay_CurrentFrameStart = addr & ~1;
        !           580:        }
        !           581:        else {
        !           582:                /* DMA Record selected */
        !           583:                crossbar.dmaRecord_CurrentFrameStart = addr & ~1;
        !           584:        }
        !           585: }
        !           586: 
        !           587: /*-----------------------------------------------------------------------*/
        !           588: 
        !           589: /**
        !           590:  * Read byte from sound frame count high register (0xff8909).
        !           591:  */
        !           592: void Crossbar_FrameCountHigh_ReadByte(void)
        !           593: {
        !           594:        if (crossbar.dmaSelected == 0) {
        !           595:                /* DMA Play selected */
        !           596:                IoMem_WriteByte(0xff8909, (dmaPlay.frameStartAddr + dmaPlay.frameCounter) >> 16);
        !           597:        }
        !           598:        else {
        !           599:                /* DMA Record selected */
        !           600:                IoMem_WriteByte(0xff8909, (dmaRecord.frameStartAddr + dmaRecord.frameCounter) >> 16);
        !           601:        }
        !           602: }
        !           603: 
        !           604: /**
        !           605:  * Write byte to sound frame count high register (0xff8909).
        !           606:  */
        !           607: void Crossbar_FrameCountHigh_WriteByte(void)
        !           608: {
        !           609:        Uint32 addr;
        !           610: 
        !           611:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8909 (Sound frame count high) write: 0x%02x\n", IoMem_ReadByte(0xff8909));
        !           612: 
        !           613:        /* Compute frameCounter current address */
        !           614:        addr = (IoMem_ReadByte(0xff8909) << 16) + (IoMem_ReadByte(0xff890b) << 8) + IoMem_ReadByte(0xff890d);
        !           615: 
        !           616:        if (crossbar.dmaSelected == 0) {
        !           617:                /* DMA Play selected */
        !           618:                crossbar.dmaPlay_CurrentFrameCount = addr;
        !           619:        }
        !           620:        else {
        !           621:                /* DMA Record selected */
        !           622:                crossbar.dmaRecord_CurrentFrameCount = addr;
        !           623:        }
        !           624: }
        !           625: 
        !           626: /**
        !           627:  * Read byte from sound frame count medium register (0xff890b).
        !           628:  */
        !           629: void Crossbar_FrameCountMed_ReadByte(void)
        !           630: {
        !           631:        if (crossbar.dmaSelected == 0) {
        !           632:                /* DMA Play selected */
        !           633:                IoMem_WriteByte(0xff890b, (dmaPlay.frameStartAddr + dmaPlay.frameCounter) >> 8);
        !           634:        }
        !           635:        else {
        !           636:                /* DMA Record selected */
        !           637:                IoMem_WriteByte(0xff890b, (dmaRecord.frameStartAddr + dmaRecord.frameCounter) >> 8);
        !           638:        }
        !           639: }
        !           640: 
        !           641: /**
        !           642:  * Write byte to sound frame count medium register (0xff890b).
        !           643:  */
        !           644: void Crossbar_FrameCountMed_WriteByte(void)
        !           645: {
        !           646:        Uint32 addr;
        !           647: 
        !           648:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff890b (Sound frame count med) write: 0x%02x\n", IoMem_ReadByte(0xff890b));
        !           649: 
        !           650:        /* Compute frameCounter current address */
        !           651:        addr = (IoMem_ReadByte(0xff8909) << 16) + (IoMem_ReadByte(0xff890b) << 8) + IoMem_ReadByte(0xff890d);
        !           652: 
        !           653:        if (crossbar.dmaSelected == 0) {
        !           654:                /* DMA Play selected */
        !           655:                crossbar.dmaPlay_CurrentFrameCount = addr;
        !           656:        }
        !           657:        else {
        !           658:                /* DMA Record selected */
        !           659:                crossbar.dmaRecord_CurrentFrameCount = addr;
        !           660:        }
        !           661: }
        !           662: 
        !           663: /**
        !           664:  * Read byte from sound frame count low register (0xff890d).
        !           665:  */
        !           666: void Crossbar_FrameCountLow_ReadByte(void)
        !           667: {
        !           668:        if (crossbar.dmaSelected == 0) {
        !           669:                /* DMA Play selected */
        !           670:                IoMem_WriteByte(0xff890d, (dmaPlay.frameStartAddr + dmaPlay.frameCounter));
        !           671:        }
        !           672:        else {
        !           673:                /* DMA Record selected */
        !           674:                IoMem_WriteByte(0xff890d, (dmaRecord.frameStartAddr + dmaRecord.frameCounter));
        !           675:        }
        !           676: }
        !           677: 
        !           678: /**
        !           679:  * Write byte to sound frame count low register (0xff890d).
        !           680:  */
        !           681: void Crossbar_FrameCountLow_WriteByte(void)
        !           682: {
        !           683:        Uint32 addr;
        !           684: 
        !           685:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff890d (Sound frame count low) write: 0x%02x\n", IoMem_ReadByte(0xff890d));
        !           686: 
        !           687:        /* Compute frameCounter current address */
        !           688:        addr = (IoMem_ReadByte(0xff8909) << 16) + (IoMem_ReadByte(0xff890b) << 8) + IoMem_ReadByte(0xff890d);
        !           689: 
        !           690:        if (crossbar.dmaSelected == 0) {
        !           691:                /* DMA Play selected */
        !           692:                crossbar.dmaPlay_CurrentFrameCount = addr;
        !           693:        }
        !           694:        else {
        !           695:                /* DMA Record selected */
        !           696:                crossbar.dmaRecord_CurrentFrameCount = addr;
        !           697:        }
        !           698: }
        !           699: 
        !           700: /*-----------------------------------------------------------------------*/
        !           701: 
        !           702: /**
        !           703:  * Read byte from sound frame end high register (0xff890f).
        !           704:  */
        !           705: void Crossbar_FrameEndHigh_ReadByte(void)
        !           706: {
        !           707:        if (crossbar.dmaSelected == 0) {
        !           708:                /* DMA Play selected */
        !           709:                IoMem_WriteByte(0xff890f, crossbar.dmaPlay_CurrentFrameEnd >> 16);
        !           710:        }
        !           711:        else {
        !           712:                /* DMA Record selected */
        !           713:                IoMem_WriteByte(0xff890f, crossbar.dmaRecord_CurrentFrameEnd >> 16);
        !           714:        }
        !           715: }
        !           716: 
        !           717: /**
        !           718:  * Write byte to sound frame end high register (0xff890f).
        !           719:  */
        !           720: void Crossbar_FrameEndHigh_WriteByte(void)
        !           721: {
        !           722:        Uint32 addr;
        !           723: 
        !           724:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff890f (Sound frame end high) write: 0x%02x\n", IoMem_ReadByte(0xff890f));
        !           725: 
        !           726:        addr = (IoMem_ReadByte(0xff890f) << 16) + (IoMem_ReadByte(0xff8911) << 8) + IoMem_ReadByte(0xff8913);
        !           727: 
        !           728:        if (crossbar.dmaSelected == 0) {
        !           729:                /* DMA Play selected */
        !           730:                crossbar.dmaPlay_CurrentFrameEnd = addr & ~1;
        !           731:        }
        !           732:        else {
        !           733:                /* DMA Record selected */
        !           734:                crossbar.dmaRecord_CurrentFrameEnd = addr & ~1;
        !           735:        }
        !           736: }
        !           737: 
        !           738: /**
        !           739:  * Read byte from sound frame end medium register (0xff8911).
        !           740:  */
        !           741: void Crossbar_FrameEndMed_ReadByte(void)
        !           742: {
        !           743:        if (crossbar.dmaSelected == 0) {
        !           744:                /* DMA Play selected */
        !           745:                IoMem_WriteByte(0xff8911, crossbar.dmaPlay_CurrentFrameEnd >> 8);
        !           746:        }
        !           747:        else {
        !           748:                /* DMA Record selected */
        !           749:                IoMem_WriteByte(0xff8911, crossbar.dmaRecord_CurrentFrameEnd >> 8);
        !           750:        }
        !           751: }
        !           752: 
        !           753: /**
        !           754:  * Write byte to sound frame end medium register (0xff8911).
        !           755:  */
        !           756: void Crossbar_FrameEndMed_WriteByte(void)
        !           757: {
        !           758:        Uint32 addr;
        !           759: 
        !           760:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8911 (Sound frame end med) write: 0x%02x\n", IoMem_ReadByte(0xff8911));
        !           761: 
        !           762:        addr = (IoMem_ReadByte(0xff890f) << 16) + (IoMem_ReadByte(0xff8911) << 8) + IoMem_ReadByte(0xff8913);
        !           763: 
        !           764:        if (crossbar.dmaSelected == 0) {
        !           765:                /* DMA Play selected */
        !           766:                crossbar.dmaPlay_CurrentFrameEnd = addr & ~1;
        !           767:        }
        !           768:        else {
        !           769:                /* DMA Record selected */
        !           770:                crossbar.dmaRecord_CurrentFrameEnd = addr & ~1;
        !           771:        }
        !           772: }
        !           773: 
        !           774: /**
        !           775:  * Read byte from sound frame end low register (0xff8913).
        !           776:  */
        !           777: void Crossbar_FrameEndLow_ReadByte(void)
        !           778: {
        !           779:        if (crossbar.dmaSelected == 0) {
        !           780:                /* DMA Play selected */
        !           781:                IoMem_WriteByte(0xff8913, crossbar.dmaPlay_CurrentFrameEnd);
        !           782:        }
        !           783:        else {
        !           784:                /* DMA Record selected */
        !           785:                IoMem_WriteByte(0xff8913, crossbar.dmaRecord_CurrentFrameEnd);
        !           786:        }
        !           787: }
        !           788: 
        !           789: /**
        !           790:  * Write byte to sound frame end low register (0xff8913).
        !           791:  */
        !           792: void Crossbar_FrameEndLow_WriteByte(void)
        !           793: {
        !           794:        Uint32 addr;
        !           795: 
        !           796:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8913 (Sound frame end low) write: 0x%02x\n", IoMem_ReadByte(0xff8913));
        !           797: 
        !           798:        addr = (IoMem_ReadByte(0xff890f) << 16) + (IoMem_ReadByte(0xff8911) << 8) + IoMem_ReadByte(0xff8913);
        !           799: 
        !           800:        if (crossbar.dmaSelected == 0) {
        !           801:                /* DMA Play selected */
        !           802:                crossbar.dmaPlay_CurrentFrameEnd = addr & ~1;
        !           803:        }
        !           804:        else {
        !           805:                /* DMA Record selected */
        !           806:                crossbar.dmaRecord_CurrentFrameEnd = addr & ~1;
        !           807:        }
        !           808: }
        !           809: 
        !           810: /*-----------------------------------------------------------------------*/
        !           811: /**
        !           812:  * Write byte to DMA track control (0xff8920).
        !           813:  */
        !           814: void Crossbar_DmaTrckCtrl_WriteByte(void)
        !           815: {
        !           816:        Uint8 sndCtrl = IoMem_ReadByte(0xff8920);
        !           817: 
        !           818:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8920 (sound mode control) write: 0x%02x\n", sndCtrl);
        !           819: 
        !           820:        crossbar.playTracks = (sndCtrl & 3) + 1;
        !           821:        crossbar.track_monitored = (sndCtrl & 30) >> 4;
        !           822: }
        !           823: 
        !           824: /**
        !           825:  * Write word to sound mode register (0xff8921).
        !           826:  */
        !           827: void Crossbar_SoundModeCtrl_WriteByte(void)
        !           828: {
        !           829:        Uint8 sndCtrl = IoMem_ReadByte(0xff8921);
        !           830: 
        !           831:        LOG_TRACE(TRACE_CROSSBAR, "crossbar : $ff8921 (additional sound mode control) write: 0x%02x\n", sndCtrl);
        !           832: 
        !           833:        crossbar.is16Bits = (sndCtrl & 0x40) >> 6;
        !           834:        crossbar.isStereo = 1 - ((sndCtrl & 0x80) >> 7);
        !           835:        crossbar.steFreq = sndCtrl & 0x3;
        !           836: 
        !           837:        Crossbar_Recalculate_Clocks_Cycles();
        !           838: }
        !           839: 
        !           840: /**
        !           841:  * Write word to Falcon Crossbar source controller (0xff8930).
        !           842:        Source: A/D Convertor                 BIT 15 14 13 12
        !           843:        00 - 25.175Mhz clock -------------------------+--+
        !           844:        01 - External clock --------------------------+--+
        !           845:        10 - 32Mhz clock (Don't use) -----------------+--'
        !           846: 
        !           847:        Source: External Input                BIT 11 10  9  8
        !           848:        0 - DSP IN, 1 - All others ----------------'  |  |  |
        !           849:        00 - 25.175Mhz clock -------------------------+--+  |
        !           850:        01 - External clock --------------------------+--+  |
        !           851:        10 - 32Mhz clock -----------------------------+--'  |
        !           852:        0 - Handshake on, 1 - Handshake off ----------------'
        !           853: 
        !           854:        Source: DSP-XMIT                      BIT  7  6  5  4
        !           855:        0 - Tristate and disconnect DSP -----------+  |  |  |
        !           856:            (Only for external SSI use)            |  |  |  |
        !           857:        1 - Connect DSP to multiplexer ------------'  |  |  |
        !           858:        00 - 25.175Mhz clock -------------------------+--+  |
        !           859:        01 - External clock --------------------------+--+  |
        !           860:        10 - 32Mhz clock -----------------------------+--'  |
        !           861:        0 - Handshake on, 1 - Handshake off ----------------'
        !           862: 
        !           863:        Source: DMA-PLAYBACK                  BIT  3  2  1  0
        !           864:        0 - Handshaking on, dest DSP-REC ----------+  |  |  |
        !           865:        1 - Destination is not DSP-REC ------------'  |  |  |
        !           866:        00 - 25.175Mhz clock -------------------------+--+  |
        !           867:        01 - External clock --------------------------+--+  |
        !           868:        10 - 32Mhz clock -----------------------------+--'  |
        !           869:        0 - Handshake on, 1 - Handshake off ----------------'
        !           870:  */
        !           871: void Crossbar_SrcControler_WriteWord(void)
        !           872: {
        !           873:        Uint16 nCbSrc = IoMem_ReadWord(0xff8930);
        !           874: 
        !           875:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8930 (source device) write: 0x%04x\n", nCbSrc);
        !           876: 
        !           877:        dspXmit.isTristated = 1 - ((nCbSrc >> 7) & 0x1);
        !           878:        dspXmit.isInHandshakeMode = 1 - ((nCbSrc >> 4) & 0x1);
        !           879:        
        !           880:        crossbar.dspXmit_freq = (nCbSrc >> 5) & 0x3;
        !           881:        crossbar.dmaPlay_freq = (nCbSrc >> 1) & 0x3;
        !           882: 
        !           883:        dmaPlay.isConnectedToDspInHandShakeMode = ((nCbSrc & 9) == 0 ? 1 : 0);                                
        !           884: }
        !           885: 
        !           886: /**
        !           887:  * Write word to Falcon Crossbar destination controller (0xff8932).
        !           888:        Source: D/A Convertor                 BIT 15 14 13 12
        !           889:        00 - DMA output ------------------------------+--+  |
        !           890:        01 - DSP output ------------------------------+--+  |
        !           891:        10 - External input --------------------------+--+  |
        !           892:        11 - ADC input -------------------------------+--'  |
        !           893:        0 - Handshake on, 1 - Handshake off ----------------'
        !           894: 
        !           895:        Source: External OutPut               BIT 11 10  9  8
        !           896:        0 - DSP OUT, 1 - All others ---------------'  |  |  |
        !           897:        00 - DMA output ------------------------------+--+  |
        !           898:        01 - DSP output ------------------------------+--+  |
        !           899:        10 - External input --------------------------+--+  |
        !           900:        11 - ADC input -------------------------------+--'  |
        !           901:        0 - Handshake on, 1 - Handshake off ----------------'
        !           902: 
        !           903:        Source: DSP-RECEIVE                   BIT  7  6  5  4
        !           904:        0 - Tristate and disconnect DSP -----------+  |  |  |
        !           905:            (Only for external SSI use)            |  |  |  |
        !           906:        1 - Connect DSP to multiplexer ------------'  |  |  |
        !           907:        00 - DMA output ------------------------------+--+  |
        !           908:        01 - DSP output ------------------------------+--+  |
        !           909:        10 - External input --------------------------+--+  |
        !           910:        11 - ADC input -------------------------------+--'  |
        !           911:        0 - Handshake on, 1 - Handshake off ----------------'
        !           912: 
        !           913:        Source: DMA-RECORD                    BIT  3  2  1  0
        !           914:        0 - Handshaking on, dest DSP-XMIT ---------+  |  |  |
        !           915:        1 - All -----------------------------------'  |  |  |
        !           916:        00 - DMA output ------------------------------+--+  |
        !           917:        01 - DSP output ------------------------------+--+  |
        !           918:        10 - External input --------------------------+--+  |
        !           919:        11 - ADC input -------------------------------+--'  |
        !           920:        0 - Handshake on, 1 - Handshake off ----------------'
        !           921:  */
        !           922: void Crossbar_DstControler_WriteWord(void)
        !           923: {
        !           924:        Uint16 destCtrl = IoMem_ReadWord(0xff8932);
        !           925: 
        !           926:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8932 (destination device) write: 0x%04x\n", destCtrl);
        !           927: 
        !           928:        dspReceive.isTristated = 1 - ((destCtrl & 0x80) >> 7);
        !           929:        dspReceive.isInHandshakeMode = 1 - ((destCtrl & 0x10) >> 4);
        !           930: 
        !           931:        /* destinations devices connexions */
        !           932:        dspReceive.isConnectedToCodec = (destCtrl & 0x60) == 0x60 ? 1 : 0;
        !           933:        dspReceive.isConnectedToDsp   = (destCtrl & 0x60) == 0x20 ? 1 : 0;
        !           934:        dspReceive.isConnectedToDma   = (destCtrl & 0x60) == 0x00 ? 1 : 0;
        !           935: 
        !           936:        dmaRecord.isConnectedToCodec = (destCtrl & 0x6) == 0x6 ? 1 : 0;
        !           937:        dmaRecord.isConnectedToDsp   = (destCtrl & 0x6) == 0x2 ? 1 : 0;
        !           938:        dmaRecord.isConnectedToDma   = (destCtrl & 0x6) == 0x0 ? 1 : 0;
        !           939: 
        !           940:        dac.isConnectedToCodec = (destCtrl & 0x6000) == 0x6000 ? 1 : 0;
        !           941:        dac.isConnectedToDsp   = (destCtrl & 0x6000) == 0x2000 ? 1 : 0;
        !           942:        dac.isConnectedToDma   = (destCtrl & 0x6000) == 0x0000 ? 1 : 0;
        !           943: 
        !           944:        /* sources devices connexions */
        !           945:        dspXmit.isConnectedToCodec = (destCtrl & 0x6000) == 0x2000 ? 1 : 0;
        !           946:        dspXmit.isConnectedToDsp   = (destCtrl & 0x60) == 0x20 ? 1 : 0;
        !           947:        dspXmit.isConnectedToDma   = (destCtrl & 0x6) == 0x2 ? 1 : 0;
        !           948: 
        !           949:        dmaPlay.isConnectedToCodec = (destCtrl & 0x6000) == 0x0000 ? 1 : 0;
        !           950:        dmaPlay.isConnectedToDsp   = (destCtrl & 0x60) == 0x00 ? 1 : 0;
        !           951:        dmaPlay.isConnectedToDma   = (destCtrl & 0x6) == 0x0 ? 1 : 0;
        !           952: 
        !           953:        adc.isConnectedToCodec = (destCtrl & 0x6000) == 0x6000 ? 1 : 0;
        !           954:        adc.isConnectedToDsp   = (destCtrl & 0x60) == 0x60 ? 1 : 0;
        !           955:        adc.isConnectedToDma   = (destCtrl & 0x6) == 0x6 ? 1 : 0;
        !           956: 
        !           957:        dmaPlay.isConnectedToDspInHandShakeMode = ((destCtrl & 7) == 2 ? 1 : 0);
        !           958:        dmaRecord.isConnectedToDspInHandShakeMode = ((destCtrl & 0xf) == 2 ? 1 : 0);
        !           959: }
        !           960: 
        !           961: /**
        !           962:  * Write byte to external clock divider register (0xff8934).
        !           963:  */
        !           964: void Crossbar_FreqDivExt_WriteByte(void)
        !           965: {
        !           966:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8934 (ext. clock divider) write: 0x%02x\n", IoMem_ReadByte(0xff8934));
        !           967: }
        !           968: 
        !           969: /**
        !           970:  * Write byte to internal clock divider register (0xff8935).
        !           971:  */
        !           972: void Crossbar_FreqDivInt_WriteByte(void)
        !           973: {
        !           974:        Uint8 clkDiv = IoMem_ReadByte(0xff8935);
        !           975: 
        !           976:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8935 (int. clock divider) write: 0x%02x\n", clkDiv);
        !           977: 
        !           978:        crossbar.int_freq_divider = clkDiv & 0xf;
        !           979:        Crossbar_Recalculate_Clocks_Cycles();
        !           980: }
        !           981: 
        !           982: /**
        !           983:  * Write byte to record track select register (0xff8936).
        !           984:  *     0 = Record 1 track
        !           985:  *     1 = Record 2 tracks
        !           986:  *     2 = Record 3 tracks
        !           987:  *     3 = Record 4 tracks
        !           988:  */
        !           989: void Crossbar_TrackRecSelect_WriteByte(void)
        !           990: {
        !           991:        Uint8 recTrack = IoMem_ReadByte(0xff8936);
        !           992: 
        !           993:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8936 (record track select) write: 0x%02x\n", recTrack);
        !           994: 
        !           995:        crossbar.recordTracks = recTrack & 3;
        !           996: }
        !           997: 
        !           998: /**
        !           999:  * Write byte to CODEC input source from 16 bit adder (0xff8937).
        !          1000:  *     Bit 1 : source = multiplexer
        !          1001:  *     Bit 0 : source = A/D convertor 
        !          1002:  */
        !          1003: void Crossbar_CodecInput_WriteByte(void)
        !          1004: {
        !          1005:        Uint8 inputSource = IoMem_ReadByte(0xff8937);
        !          1006: 
        !          1007:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8937 (CODEC input) write: 0x%02x\n", IoMem_ReadByte(0xff8937));
        !          1008: 
        !          1009:        crossbar.codecInputSource = inputSource & 3;
        !          1010: }
        !          1011: 
        !          1012: /**
        !          1013:  * Write byte to A/D converter input for L+R channel (0xff8938).
        !          1014:  *     Bit 1 :  Left (0 = Microphone ; 1 = PSG soundchip)
        !          1015:  *     Bit 0 : Right (0 = Microphone ; 1 = PSG soundchip)
        !          1016:  */
        !          1017: void Crossbar_AdcInput_WriteByte(void)
        !          1018: {
        !          1019:        Uint8 input = IoMem_ReadByte(0xff8938);
        !          1020: 
        !          1021:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8938 (ADC input) write: 0x%02x\n", IoMem_ReadByte(0xff8938));
        !          1022: 
        !          1023:        crossbar.codecAdcInput = input & 3;
        !          1024: }
        !          1025: 
        !          1026: /**
        !          1027:  * Write byte to input amplifier register (amplification for ADC device) (0xff8939).
        !          1028:  *     Bits LLLLRRRR
        !          1029:  *     Amplification is in +1.5 dB steps
        !          1030:  */
        !          1031: void Crossbar_InputAmp_WriteByte(void)
        !          1032: {
        !          1033:        Uint8 amplification = IoMem_ReadByte(0xff8939);
        !          1034: 
        !          1035:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8939 (CODEC channel amplification) write: 0x%02x\n", IoMem_ReadByte(0xff8939));
        !          1036: 
        !          1037:        crossbar.gainSettingLeft = Crossbar_ADC_volume_table[amplification >> 4];
        !          1038:        crossbar.gainSettingRight = Crossbar_ADC_volume_table[amplification & 0xf];
        !          1039: }
        !          1040: 
        !          1041: /**
        !          1042:  * Write byte to channel reduction register (attenuation for DAC device) (0xff893a).
        !          1043:  *     Bits LLLLRRRR
        !          1044:  *     Reduction is in -1.5 dB steps
        !          1045:  */
        !          1046: void Crossbar_OutputReduct_WriteByte(void)
        !          1047: {
        !          1048:        Uint8 reduction = IoMem_ReadByte(0xff893a);
        !          1049: 
        !          1050:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff893a (CODEC channel attenuation) write: 0x%02x\n", IoMem_ReadByte(0xff893a));
        !          1051: 
        !          1052:        crossbar.attenuationSettingLeft = Crossbar_DAC_volume_table[reduction >> 4];
        !          1053:        crossbar.attenuationSettingRight = Crossbar_DAC_volume_table[reduction & 0xf];
        !          1054: }
        !          1055: 
        !          1056: /**
        !          1057:  * Write word to CODEC status register (0xff893c).
        !          1058:  *     Bit 1 :  Left Channel Overflow (0/1)
        !          1059:  *     Bit 0 : Right Channel Overflow (0/1)
        !          1060:  */
        !          1061: void Crossbar_CodecStatus_WriteWord(void)
        !          1062: {
        !          1063:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff893c (CODEC status) write: 0x%04x\n", IoMem_ReadWord(0xff893c));
        !          1064: }
        !          1065: 
        !          1066: 
        !          1067: 
        !          1068: /*----------------------------------------------------------------------*/
        !          1069: /*------------------------- Crossbar functions -------------------------*/
        !          1070: /*----------------------------------------------------------------------*/
        !          1071: 
        !          1072: /**
        !          1073:  * Recalculates internal clocks 25 Mhz and 32 Mhz cycles
        !          1074:  */
        !          1075: static void Crossbar_Recalculate_Clocks_Cycles(void)
        !          1076: {
        !          1077:        double cyclesClk;
        !          1078: 
        !          1079:        crossbar.clock25_cycles_counter = 0;
        !          1080:        crossbar.clock32_cycles_counter = 0;
        !          1081: 
        !          1082:        /* Calculate 25 Mhz clock cycles */
        !          1083:        cyclesClk = ((double)CPU_FREQ / Crossbar_DetectSampleRate(25)) / (double)(crossbar.playTracks) / 2.0;
        !          1084:        crossbar.clock25_cycles = (int)(cyclesClk);
        !          1085:        crossbar.clock25_cycles_decimal = (int)((cyclesClk - (double)(crossbar.clock25_cycles)) * (double)DECIMAL_PRECISION);
        !          1086: 
        !          1087:        /* Calculate 32 Mhz clock cycles */
        !          1088:        cyclesClk = ((double)CPU_FREQ / Crossbar_DetectSampleRate(32)) / (double)(crossbar.playTracks) / 2.0;
        !          1089:        crossbar.clock32_cycles = (int)(cyclesClk);
        !          1090:        crossbar.clock32_cycles_decimal = (int)((cyclesClk - (double)(crossbar.clock32_cycles)) * (double)DECIMAL_PRECISION);
        !          1091: 
        !          1092:        /* Recalculate ratio between host's sound frequency and hatari's sound frequency */
        !          1093:        crossbar.frequence_ratio = (Uint32)((Crossbar_DetectSampleRate(25) / (double)nAudioFrequency) * (double)DECIMAL_PRECISION);
        !          1094: 
        !          1095:        /* Recalculate ratio between hatari's sound frequency and host's sound frequency */
        !          1096:        crossbar.frequence_ratio2 = (Uint32)(((double)nAudioFrequency / Crossbar_DetectSampleRate(25)) * (double)DECIMAL_PRECISION);
        !          1097:        
        !          1098:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : Recalculate_clock_Cycles\n");
        !          1099:        LOG_TRACE(TRACE_CROSSBAR, "           clock25 : %d\n", crossbar.clock25_cycles);
        !          1100:        LOG_TRACE(TRACE_CROSSBAR, "           clock32 : %d\n", crossbar.clock32_cycles);
        !          1101: 
        !          1102:        /* Verify if the new frequency doesn't mute the DAC */
        !          1103:        crossbar.isDacMuted = 0;
        !          1104:        if ((crossbar.int_freq_divider == 0) && (crossbar.steFreq == 0))
        !          1105:                crossbar.isDacMuted = 1;
        !          1106: 
        !          1107:        if ((crossbar.int_freq_divider == 6) || (crossbar.int_freq_divider == 8) || 
        !          1108:            (crossbar.int_freq_divider == 10) || (crossbar.int_freq_divider >= 12)) {
        !          1109:                crossbar.isDacMuted = 1;
        !          1110:        }
        !          1111: }
        !          1112: 
        !          1113: /**
        !          1114:  * Detect sample rate frequency
        !          1115:  *    clock : value of the internal clock (25 or 32).
        !          1116:  */
        !          1117: static double Crossbar_DetectSampleRate(Uint16 clock)
        !          1118: {
        !          1119:        /* Ste compatible sound */
        !          1120:        if (crossbar.int_freq_divider == 0) {
        !          1121:                crossbar.isInSteFreqMode = 1;
        !          1122:                return Ste_SampleRates[crossbar.steFreq];
        !          1123:        }
        !          1124: 
        !          1125:        crossbar.isInSteFreqMode = 0;
        !          1126: 
        !          1127:        /* 25 Mhz internal clock */
        !          1128:        if (clock == 25)
        !          1129:                return Falcon_SampleRates_25Mhz[crossbar.int_freq_divider - 1];
        !          1130: 
        !          1131:        /* 32 Mhz internal clock */
        !          1132:        return Falcon_SampleRates_32Mhz[crossbar.int_freq_divider - 1];
        !          1133: }
        !          1134: 
        !          1135: /**
        !          1136:  * Start internal 25 Mhz clock interrupt.
        !          1137:  */
        !          1138: static void Crossbar_Start_InterruptHandler_25Mhz(void)
        !          1139: {
        !          1140:        Uint32 cycles_25;
        !          1141:        
        !          1142:        cycles_25 = crossbar.clock25_cycles;
        !          1143:        crossbar.clock25_cycles_counter += crossbar.clock25_cycles_decimal;
        !          1144:        
        !          1145:        if (crossbar.clock25_cycles_counter >= DECIMAL_PRECISION) {
        !          1146:                crossbar.clock25_cycles_counter -= DECIMAL_PRECISION;
        !          1147:                cycles_25 ++;
        !          1148:        }
        !          1149: 
        !          1150:        if (crossbar.pendingCyclesOver25 >= cycles_25) {
        !          1151:                crossbar.pendingCyclesOver25 -= cycles_25;
        !          1152:                cycles_25 = 0;
        !          1153:        }
        !          1154:        else {
        !          1155:                cycles_25 -= crossbar.pendingCyclesOver25;
        !          1156:                crossbar.pendingCyclesOver25 = 0;
        !          1157:        }
        !          1158: 
        !          1159:        CycInt_AddRelativeInterrupt(cycles_25, INT_CPU_CYCLE, INTERRUPT_CROSSBAR_25MHZ);
        !          1160: }
        !          1161: 
        !          1162: /**
        !          1163:  * Start internal 32 Mhz clock interrupt.
        !          1164:  */
        !          1165: static void Crossbar_Start_InterruptHandler_32Mhz(void)
        !          1166: {
        !          1167:        Uint32 cycles_32;
        !          1168:        
        !          1169:        cycles_32 = crossbar.clock32_cycles;
        !          1170:        crossbar.clock32_cycles_counter += crossbar.clock32_cycles_decimal;
        !          1171: 
        !          1172:        if (crossbar.clock32_cycles_counter >= DECIMAL_PRECISION) {
        !          1173:                crossbar.clock32_cycles_counter -= DECIMAL_PRECISION;
        !          1174:                cycles_32 ++;
        !          1175:        }
        !          1176: 
        !          1177:        if (crossbar.pendingCyclesOver32 >= cycles_32){
        !          1178:                crossbar.pendingCyclesOver32 -= cycles_32;
        !          1179:                cycles_32 = 0;
        !          1180:        }
        !          1181:        else {
        !          1182:                cycles_32 -= crossbar.pendingCyclesOver32;
        !          1183:                crossbar.pendingCyclesOver32 = 0;
        !          1184:        }
        !          1185: 
        !          1186:        CycInt_AddRelativeInterrupt(cycles_32, INT_CPU_CYCLE, INTERRUPT_CROSSBAR_32MHZ);
        !          1187: }
        !          1188: 
        !          1189: 
        !          1190: /**
        !          1191:  * Execute transfers for internal 25 Mhz clock.
        !          1192:  */
        !          1193: void Crossbar_InterruptHandler_25Mhz(void)
        !          1194: {
        !          1195:        /* How many cycle was this sound interrupt delayed (>= 0) */
        !          1196:        crossbar.pendingCyclesOver25 += -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );
        !          1197: 
        !          1198:        /* Remove this interrupt from list and re-order */
        !          1199:        CycInt_AcknowledgeInterrupt();
        !          1200: 
        !          1201:        /* If transfer mode is in Ste mode, use only this clock for all the transfers */
        !          1202:        if (crossbar.isInSteFreqMode) {
        !          1203:                Crossbar_Process_DSPXmit_Transfer();
        !          1204:                Crossbar_Process_DMAPlay_Transfer();
        !          1205:                Crossbar_Process_ADCXmit_Transfer();
        !          1206:                
        !          1207:                /* Restart the 25 Mhz clock interrupt */
        !          1208:                Crossbar_Start_InterruptHandler_25Mhz();
        !          1209:                return;
        !          1210:        }
        !          1211: 
        !          1212:        Crossbar_Process_ADCXmit_Transfer();
        !          1213:                
        !          1214:        /* DSP Play transfer ? */
        !          1215:        if (crossbar.dspXmit_freq == CROSSBAR_FREQ_25MHZ) {
        !          1216:                Crossbar_Process_DSPXmit_Transfer();
        !          1217:        }
        !          1218:        
        !          1219:        /* DMA Play transfer ? */
        !          1220:        if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_25MHZ) {
        !          1221:                Crossbar_Process_DMAPlay_Transfer();
        !          1222:        }
        !          1223: 
        !          1224:        /* Restart the 25 Mhz clock interrupt */
        !          1225:        Crossbar_Start_InterruptHandler_25Mhz();
        !          1226: }
        !          1227: 
        !          1228: /**
        !          1229:  * Execute transfers for internal 32 Mhz clock.
        !          1230:  */
        !          1231: void Crossbar_InterruptHandler_32Mhz(void)
        !          1232: {
        !          1233:        /* How many cycle was this sound interrupt delayed (>= 0) */
        !          1234:        crossbar.pendingCyclesOver32 += -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );
        !          1235: 
        !          1236:        /* Remove this interrupt from list and re-order */
        !          1237:        CycInt_AcknowledgeInterrupt();
        !          1238: 
        !          1239:        /* If transfer mode is in Ste mode, don't use this clock for all the transfers */
        !          1240:        if (crossbar.isInSteFreqMode) {
        !          1241:                /* Restart the 32 Mhz clock interrupt */
        !          1242:                Crossbar_Start_InterruptHandler_32Mhz();
        !          1243:                return;
        !          1244:        }
        !          1245:        
        !          1246:        /* DSP Play transfer ? */
        !          1247:        if (crossbar.dspXmit_freq == CROSSBAR_FREQ_32MHZ) {
        !          1248:                Crossbar_Process_DSPXmit_Transfer();
        !          1249:        }
        !          1250:        
        !          1251:        /* DMA Play transfer ? */
        !          1252:        if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_32MHZ) {
        !          1253:                Crossbar_Process_DMAPlay_Transfer();
        !          1254:        }
        !          1255: 
        !          1256:        /* Restart the 32 Mhz clock interrupt */
        !          1257:        Crossbar_Start_InterruptHandler_32Mhz();
        !          1258: }
        !          1259: 
        !          1260: 
        !          1261: /*----------------------------------------------------------------------*/
        !          1262: /*--------------------- DSP Xmit processing ----------------------------*/
        !          1263: /*----------------------------------------------------------------------*/
        !          1264: 
        !          1265: /**
        !          1266:  * Process DSP xmit to crossbar transfer
        !          1267:  */
        !          1268: static void Crossbar_Process_DSPXmit_Transfer(void)
        !          1269: {
        !          1270:        Uint16 frame=0;
        !          1271:        Sint32 data;
        !          1272: 
        !          1273:        /* Is DSP Xmit connected to DMA Record in handshake mode ? */
        !          1274:        if (dmaRecord.isConnectedToDspInHandShakeMode) {
        !          1275:                Crossbar_Process_DMARecord_HandshakeMode();
        !          1276:                return;
        !          1277:        }
        !          1278: 
        !          1279:        /* Is DSP Xmit connected to something ? */
        !          1280:        if (!dspXmit.isConnectedToCodec && !dspXmit.isConnectedToDma && !dspXmit.isConnectedToDsp)
        !          1281:                return;
        !          1282: 
        !          1283:        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DSP --> Crossbar transfer\n");
        !          1284: 
        !          1285:        if (dspXmit.wordCount == 0) {
        !          1286:                frame = 1;
        !          1287:        }
        !          1288: 
        !          1289:        /* Send the frame status to the DSP SSI Xmit */
        !          1290:        DSP_SsiReceive_SC2(frame);
        !          1291: 
        !          1292:        /* Send the clock to the DSP SSI Xmit */
        !          1293:        DSP_SsiReceive_SCK();
        !          1294: 
        !          1295:        /* read data from DSP Xmit */
        !          1296:        data = DSP_SsiReadTxValue();
        !          1297: 
        !          1298:        /* Send DSP data to the DAC ? */
        !          1299:        if (dspXmit.isConnectedToCodec) {
        !          1300:                Crossbar_SendDataToDAC(data, dspXmit.wordCount);
        !          1301:        }
        !          1302: 
        !          1303:        /* Send DSP data to the DMA record ? */
        !          1304:        if (dspXmit.isConnectedToDma) {
        !          1305:                Crossbar_SendDataToDmaRecord(data);
        !          1306:        }
        !          1307: 
        !          1308:        /* Send DSP data to the DSP in ? */
        !          1309:        if (dspXmit.isConnectedToDsp) {
        !          1310:                Crossbar_SendDataToDspReceive(data, frame);
        !          1311:        }
        !          1312: 
        !          1313:        /* increase dspXmit.wordCount for next sample */
        !          1314:        dspXmit.wordCount++;
        !          1315:        if (dspXmit.wordCount >= (crossbar.playTracks * 2)) {
        !          1316:                dspXmit.wordCount = 0;
        !          1317:        }
        !          1318: }
        !          1319: 
        !          1320: /*----------------------------------------------------------------------*/
        !          1321: /*--------------------- DSP Receive processing -------------------------*/
        !          1322: /*----------------------------------------------------------------------*/
        !          1323: 
        !          1324: /**
        !          1325:  * Transmit data from crossbar to DSP receive.
        !          1326:  */
        !          1327: static void Crossbar_SendDataToDspReceive(Uint32 value, Uint16 frame)
        !          1328: {
        !          1329:        /* Verify that DSP IN is not tristated */
        !          1330:        if (dspReceive.isTristated) {
        !          1331:                return;
        !          1332:        }
        !          1333: 
        !          1334:        /* Send sample to DSP receive */
        !          1335:        DSP_SsiWriteRxValue(value);
        !          1336: 
        !          1337:        /* Send the frame status to the DSP SSI receive */
        !          1338:        /* only in non hanshake mode */
        !          1339:        if (dmaPlay.handshakeMode_Frame == 0) {
        !          1340:                DSP_SsiReceive_SC1(frame);
        !          1341:        }
        !          1342: 
        !          1343:        dmaPlay.handshakeMode_Frame = 0;
        !          1344:        
        !          1345:        /* Send the clock to the DSP SSI receive */
        !          1346:        DSP_SsiReceive_SC0();
        !          1347: }
        !          1348: 
        !          1349: /*----------------------------------------------------------------------*/
        !          1350: /*--------------------- DMA PLAY sound processing ----------------------*/
        !          1351: /*----------------------------------------------------------------------*/
        !          1352: 
        !          1353: /**
        !          1354:  * Set DMA Play sound start frame buffer, stop frame buffer, frame length
        !          1355:  */
        !          1356: static void Crossbar_setDmaPlay_Settings(void)
        !          1357: {
        !          1358:        /* DMA setings */
        !          1359:        dmaPlay.frameStartAddr = crossbar.dmaPlay_CurrentFrameStart;
        !          1360:        dmaPlay.frameEndAddr = crossbar.dmaPlay_CurrentFrameEnd;
        !          1361:        dmaPlay.frameLen = dmaPlay.frameEndAddr - dmaPlay.frameStartAddr;
        !          1362: //     dmaPlay.frameCounter = crossbar.dmaPlay_CurrentFrameCount - crossbar.dmaPlay_CurrentFrameStart;
        !          1363:        dmaPlay.frameCounter = 0;
        !          1364: 
        !          1365:        if (dmaPlay.frameEndAddr <= dmaPlay.frameStartAddr)
        !          1366:        {
        !          1367:                Log_Printf(LOG_WARN, "crossbar DMA Play: Illegal buffer size (from 0x%06x to 0x%06x)\n",
        !          1368:                          dmaPlay.frameStartAddr, dmaPlay.frameEndAddr);
        !          1369:        }
        !          1370: }
        !          1371: 
        !          1372: /**
        !          1373:  * Process DMA Play transfer to crossbar
        !          1374:  */
        !          1375: static void Crossbar_Process_DMAPlay_Transfer(void)
        !          1376: {
        !          1377:        Sint16 value, eightBits;
        !          1378:        Sint8  *pFrameStart;
        !          1379:        Uint8  dmaCtrlReg;
        !          1380:        
        !          1381:        /* if DMA play is not running, return */
        !          1382:        if (dmaPlay.isRunning == 0)
        !          1383:                return;
        !          1384:        
        !          1385:        /* if handshake mode */
        !          1386:        if (dmaPlay.isConnectedToDspInHandShakeMode) {
        !          1387:                if (dmaPlay.handshakeMode_Frame == 0) {
        !          1388:                        return;
        !          1389:                }
        !          1390:        }
        !          1391: 
        !          1392:        pFrameStart = (Sint8 *)&STRam[dmaPlay.frameStartAddr];
        !          1393: 
        !          1394:        /* 16 bits stereo mode ? */
        !          1395:        if (crossbar.is16Bits) {
        !          1396:                eightBits = 1;
        !          1397:                value = (Sint16)do_get_mem_word(&pFrameStart[dmaPlay.frameCounter]);
        !          1398:                dmaPlay.frameCounter += 2;
        !          1399:        }
        !          1400:        /* 8 bits stereo ? */
        !          1401:        else if (crossbar.isStereo) {
        !          1402:                eightBits = 64;
        !          1403:                value = (Sint16) pFrameStart[dmaPlay.frameCounter];
        !          1404:                dmaPlay.frameCounter ++;
        !          1405:        }
        !          1406:        /* 8 bits mono */
        !          1407:        else {
        !          1408:                eightBits = 64;
        !          1409:                value = (Sint16) pFrameStart[dmaPlay.frameCounter];
        !          1410:                if ((dmaPlay.currentFrame & 1) == 0) {
        !          1411:                        dmaPlay.frameCounter ++;
        !          1412: 
        !          1413:                }
        !          1414:        }
        !          1415:        
        !          1416:        /* Send sample to the DMA record ? */
        !          1417:        if (dmaPlay.isConnectedToDma) {
        !          1418:                LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DMA Play --> DMA record\n");
        !          1419:                Crossbar_SendDataToDmaRecord(value);
        !          1420:        }
        !          1421: 
        !          1422:        /* Send sample to the DAC ? */
        !          1423:        if (dmaPlay.isConnectedToCodec) {
        !          1424:                LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DMA Play --> DAC\n");
        !          1425:                Crossbar_SendDataToDAC(value * eightBits, dmaPlay.currentFrame);
        !          1426:        }
        !          1427: 
        !          1428:        /* Send sample to the DSP in ? */
        !          1429:        if (dmaPlay.isConnectedToDsp) {
        !          1430:                LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DMA Play --> DSP record\n");
        !          1431:                /* New frame ? */
        !          1432:                if (dmaPlay.currentFrame == 0) {
        !          1433:                        Crossbar_SendDataToDspReceive(value, 1);
        !          1434:                }
        !          1435:                else {
        !          1436:                        Crossbar_SendDataToDspReceive(value, 0);
        !          1437:                }
        !          1438:        }
        !          1439: 
        !          1440:        /* increase dmaPlay.currentFrame for next sample */
        !          1441:        dmaPlay.currentFrame ++;
        !          1442:        if (dmaPlay.currentFrame >= (crossbar.playTracks * 2)) {
        !          1443:                dmaPlay.currentFrame = 0;
        !          1444:        }
        !          1445: 
        !          1446:        /* Check if end-of-frame has been reached and raise interrupts if needed. */
        !          1447:        if (dmaPlay.frameCounter >= dmaPlay.frameLen)
        !          1448:        {
        !          1449:                /* Update sound */
        !          1450:                //Sound_Update();
        !          1451:                
        !          1452:                /* Send a MFP15_Int (I7) at end of replay buffer if enabled */
        !          1453:                if (dmaPlay.mfp15_int) {
        !          1454:                        MFP_InputOnChannel(MFP_TIMER_GPIP7_BIT, MFP_IERA, &MFP_IPRA);
        !          1455:                        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP15 (IT7) interrupt from DMA play\n");
        !          1456:                }
        !          1457: 
        !          1458:                /* Send a TimerA_Int at end of replay buffer if enabled */
        !          1459:                if (dmaPlay.timerA_int) {
        !          1460:                        if (MFP_TACR == 0x08) {       /* Is timer A in Event Count mode? */
        !          1461:                                MFP_TimerA_EventCount_Interrupt();
        !          1462:                                LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP Timer A interrupt from DMA play\n");
        !          1463:                        }
        !          1464:                }
        !          1465: 
        !          1466:                if (dmaPlay.loopMode) {
        !          1467:                        Crossbar_setDmaPlay_Settings();
        !          1468:                } 
        !          1469:                else {
        !          1470:                        dmaCtrlReg = IoMem_ReadByte(0xff8901) & 0xfe;
        !          1471:                        IoMem_bput(0xff8901, dmaCtrlReg);
        !          1472:                }
        !          1473:        }
        !          1474: }
        !          1475: 
        !          1476: /**
        !          1477:  * Function called when DmaPlay is in handshake mode */
        !          1478: void Crossbar_DmaPlayInHandShakeMode(void)
        !          1479: {
        !          1480:        dmaPlay.handshakeMode_Frame = 1;
        !          1481: }
        !          1482: 
        !          1483: /*----------------------------------------------------------------------*/
        !          1484: /*--------------------- DMA Record processing --------------------------*/
        !          1485: /*----------------------------------------------------------------------*/
        !          1486: 
        !          1487: /**
        !          1488:  * Set DMA Record sound start frame buffer, stop frame buffer, frame length
        !          1489:  */
        !          1490: static void Crossbar_setDmaRecord_Settings(void)
        !          1491: {
        !          1492:        /* DMA setings */
        !          1493:        dmaRecord.frameStartAddr = crossbar.dmaRecord_CurrentFrameStart;
        !          1494:        dmaRecord.frameEndAddr = crossbar.dmaRecord_CurrentFrameEnd;
        !          1495:        dmaRecord.frameLen = dmaRecord.frameEndAddr - dmaRecord.frameStartAddr;
        !          1496: //     dmaRecord.frameCounter = crossbar.dmaRecord_CurrentFrameCount - crossbar.dmaRecord_CurrentFrameStart;
        !          1497:        dmaRecord.frameCounter = 0;
        !          1498: 
        !          1499:        if (dmaRecord.frameEndAddr <= dmaRecord.frameStartAddr) {
        !          1500:                Log_Printf(LOG_WARN, "crossbar DMA Record: Illegal buffer size (from 0x%06x to 0x%06x)\n",
        !          1501:                          dmaRecord.frameStartAddr, dmaRecord.frameEndAddr);
        !          1502:        }
        !          1503: }
        !          1504: 
        !          1505: /**
        !          1506:  * DMA Record processing
        !          1507:  */
        !          1508: void Crossbar_SendDataToDmaRecord(Sint16 value)
        !          1509: {
        !          1510:        Sint8  *pFrameStart;
        !          1511:        Uint8  dmaCtrlReg;
        !          1512: 
        !          1513:        if (dmaRecord.isRunning == 0) {
        !          1514:                return;
        !          1515:        }
        !          1516:        
        !          1517:        pFrameStart = (Sint8 *)&STRam[dmaRecord.frameStartAddr];
        !          1518: 
        !          1519:        /* 16 bits stereo mode ? */
        !          1520:        if (crossbar.is16Bits) {
        !          1521:                do_put_mem_word(&pFrameStart[dmaRecord.frameCounter], value);
        !          1522:                dmaRecord.frameCounter += 2;
        !          1523:        }
        !          1524:        /* 8 bits stereo ? */
        !          1525:        else if (crossbar.isStereo) {
        !          1526:                do_put_mem_word(&pFrameStart[dmaRecord.frameCounter], value);
        !          1527:                dmaRecord.frameCounter += 2;
        !          1528: //             pFrameStart[dmaRecord.frameCounter] = (Uint8)value;
        !          1529: //             dmaRecord.frameCounter ++;
        !          1530:        }
        !          1531:        /* 8 bits mono */
        !          1532:        else {
        !          1533:                pFrameStart[dmaRecord.frameCounter] = (Uint8)value;
        !          1534:                dmaRecord.frameCounter ++;
        !          1535:        }
        !          1536: 
        !          1537:        /* Check if end-of-frame has been reached and raise interrupts if needed. */
        !          1538:        if (dmaRecord.frameCounter >= dmaRecord.frameLen)
        !          1539:        {
        !          1540:                /* Send a MFP15_Int (I7) at end of record buffer if enabled */
        !          1541:                if (dmaRecord.mfp15_int) {
        !          1542:                        MFP_InputOnChannel(MFP_TIMER_GPIP7_BIT, MFP_IERA, &MFP_IPRA);
        !          1543:                        LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP15 (IT7) interrupt from DMA record\n");
        !          1544:                }
        !          1545:        
        !          1546:                /* Send a TimerA_Int at end of record buffer if enabled */
        !          1547:                if (dmaRecord.timerA_int) {
        !          1548:                        if (MFP_TACR == 0x08)       /* Is timer A in Event Count mode? */
        !          1549:                                MFP_TimerA_EventCount_Interrupt();
        !          1550:                                LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP Timer A interrupt from DMA record\n");
        !          1551:                }
        !          1552: 
        !          1553:                if (dmaRecord.loopMode) {
        !          1554:                        Crossbar_setDmaRecord_Settings();
        !          1555:                }
        !          1556:                else {
        !          1557:                        dmaCtrlReg = IoMem_ReadByte(0xff8901) & 0xef;
        !          1558:                        IoMem_bput(0xff8901, dmaCtrlReg);
        !          1559:                }
        !          1560:        }
        !          1561: }
        !          1562: 
        !          1563: 
        !          1564: /**
        !          1565:  * Process DMA Record connected to DSP Xmit in HandShake mode.
        !          1566:  * In this special case, DMA Record is the "master" and Dsp Xmit is the "slave".
        !          1567:  */
        !          1568: static void Crossbar_Process_DMARecord_HandshakeMode(void)
        !          1569: {
        !          1570:        Sint16 data;
        !          1571: 
        !          1572:        /* If DMA record is activated and is running */
        !          1573:        if (dmaRecord.isRunning == 0) {
        !          1574:                return;
        !          1575:        }
        !          1576: 
        !          1577:        /* If DSP frame is activated (SC2 pin of the SSI port) */
        !          1578:        if (dmaRecord.handshakeMode_Frame == 0) {
        !          1579:                return;
        !          1580:        }
        !          1581: 
        !          1582:        /* Send the clock to the DSP SSI Xmit */
        !          1583:        DSP_SsiReceive_SCK();
        !          1584: 
        !          1585:        /* read data from DSP Xmit */
        !          1586:        data = DSP_SsiReadTxValue();
        !          1587:        dmaRecord.handshakeMode_Frame = 0;
        !          1588:                
        !          1589:        Crossbar_SendDataToDmaRecord(data);
        !          1590: }
        !          1591: 
        !          1592: /**
        !          1593:  * Get the frame value from DSP SSI (handshake mode only)
        !          1594:  */
        !          1595: void Crossbar_DmaRecordInHandShakeMode_Frame(Uint32 frame)
        !          1596: {
        !          1597:        dmaRecord.handshakeMode_Frame = frame;
        !          1598: }
        !          1599: 
        !          1600: 
        !          1601: /*----------------------------------------------------------------------*/
        !          1602: /*-------------------------- ADC processing ----------------------------*/
        !          1603: /*----------------------------------------------------------------------*/
        !          1604: 
        !          1605: /**
        !          1606:  * Get datas recorded by the microphone and convert them into falcon internal frequency
        !          1607:  *    - micro_bufferL : left track recorded by the microphone
        !          1608:  *    - micro_bufferR : right track recorded by the microphone
        !          1609:  *    - microBuffer_size : buffers size
        !          1610:  */
        !          1611: void Crossbar_GetMicrophoneDatas(Sint16 *micro_bufferL, Sint16 *micro_bufferR, Uint32 microBuffer_size)
        !          1612: {
        !          1613:        Uint32 i, size, bufferIndex, indexPos, intPart;
        !          1614: 
        !          1615:        size = (microBuffer_size * crossbar.frequence_ratio) >> 16;
        !          1616:        bufferIndex = 0;
        !          1617:        indexPos = 0;
        !          1618:        
        !          1619:        for (i = 0; i < size; i++) {
        !          1620:                adc.writePosition = (adc.writePosition + 1) % DACBUFFER_SIZE;
        !          1621: 
        !          1622:                adc.buffer_left[adc.writePosition] = micro_bufferL[bufferIndex];
        !          1623:                adc.buffer_right[adc.writePosition] = micro_bufferR[bufferIndex]; 
        !          1624: 
        !          1625:                indexPos += crossbar.frequence_ratio2;
        !          1626:                if (indexPos >= DECIMAL_PRECISION) {
        !          1627:                        intPart = indexPos >> 16;
        !          1628:                        bufferIndex += intPart; 
        !          1629:                        indexPos -= intPart * DECIMAL_PRECISION;
        !          1630:                }
        !          1631:        }
        !          1632: }
        !          1633: 
        !          1634: /**
        !          1635:  * Process ADC transfer to crossbar
        !          1636:  */
        !          1637: static void Crossbar_Process_ADCXmit_Transfer(void)
        !          1638: {
        !          1639:        Sint16 sample;
        !          1640:        Uint16 frame;
        !          1641:        
        !          1642:        /* swap from left to right channel or right to left channel */
        !          1643:        adc.wordCount = 1 - adc.wordCount;
        !          1644:                
        !          1645:        /* Left Channel */
        !          1646:        if (adc.wordCount == 0) {
        !          1647:                sample = adc.buffer_left[adc.readPosition];
        !          1648:                frame = 1;
        !          1649:        }
        !          1650:        else {
        !          1651:                sample = adc.buffer_right[adc.readPosition];
        !          1652:                adc.readPosition = (adc.readPosition + 1) % DACBUFFER_SIZE;
        !          1653:                frame = 0;
        !          1654:        }
        !          1655:        
        !          1656:        /* Send sample to DSP receive ? */
        !          1657:        if (adc.isConnectedToDsp) {
        !          1658:                Crossbar_SendDataToDspReceive(sample, frame);
        !          1659:        }
        !          1660:        
        !          1661:        /* Send sample to DMA record ? */
        !          1662:        if (adc.isConnectedToDma) {
        !          1663:                Crossbar_SendDataToDmaRecord(sample);
        !          1664:        }
        !          1665: 
        !          1666:        /* Send sample to DAC ? */
        !          1667:        if (adc.isConnectedToCodec) {
        !          1668:                Crossbar_SendDataToDAC(sample, adc.wordCount);
        !          1669:        }
        !          1670: }
        !          1671: 
        !          1672: 
        !          1673: /*----------------------------------------------------------------------*/
        !          1674: /*-------------------------- DAC processing ----------------------------*/
        !          1675: /*----------------------------------------------------------------------*/
        !          1676: 
        !          1677: /**
        !          1678:  * Put sample from crossbar into the DAC buffer.
        !          1679:  *    - value : sample value to play
        !          1680:  *    - sample_pos : position of the sample in the track (used to play the monitored track)
        !          1681:  */
        !          1682: static void Crossbar_SendDataToDAC(Sint16 value, Uint16 sample_pos)
        !          1683: {
        !          1684:        Uint16 track = crossbar.track_monitored * 2;
        !          1685: 
        !          1686:        if (sample_pos == track) {
        !          1687:                /* Left channel */
        !          1688:                dac.buffer_left[dac.writePosition] = value;
        !          1689:        }
        !          1690:        else if (sample_pos == track + 1) {
        !          1691:                /* Right channel */
        !          1692:                dac.buffer_right[dac.writePosition] = value;
        !          1693:                dac.writePosition = (dac.writePosition + 1) % (DACBUFFER_SIZE);
        !          1694:        }
        !          1695: }
        !          1696: 
        !          1697: /**
        !          1698:  * Mix PSG sound with microphone sound in ADC. 
        !          1699:  * Also mix ADC sound sample with the crossbar DAC samples.
        !          1700:  * (Called by sound.c)
        !          1701:  */
        !          1702: void Crossbar_GenerateSamples(int nMixBufIdx, int nSamplesToGenerate)
        !          1703: {
        !          1704:        int i, nBufIdx;
        !          1705:        Uint32 intPart;
        !          1706:        Sint16 adc_leftData, adc_rightData, dac_LeftData, dac_RightData;
        !          1707:        
        !          1708:        if (crossbar.isDacMuted) {
        !          1709:                /* Output sound = 0 */
        !          1710:                for (i = 0; i < nSamplesToGenerate; i++) {
        !          1711:                        nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
        !          1712:                        MixBuffer[nBufIdx][0] = 0;
        !          1713:                        MixBuffer[nBufIdx][1] = 0;
        !          1714:                }
        !          1715: 
        !          1716:                /* Counters are refreshed for when DAC becomes unmuted */
        !          1717:                dac.readPosition = dac.writePosition;
        !          1718:                dac.readPosition_decimal = 0;
        !          1719:                crossbar.adc_dac_readBufferPosition = adc.writePosition;
        !          1720:                return;
        !          1721:        }
        !          1722: 
        !          1723:        for (i = 0; i < nSamplesToGenerate; i++)
        !          1724:        {
        !          1725:                nBufIdx = (nMixBufIdx + i) % MIXBUFFER_SIZE;
        !          1726: 
        !          1727:                /* ADC mixing (PSG sound or microphone sound for left and right channels) */
        !          1728:                switch (crossbar.codecAdcInput) {
        !          1729:                        case 0:
        !          1730:                        default: /* Just here to remove compiler's warnings */
        !          1731:                                /* Microphone sound for left and right channels */
        !          1732:                                adc_leftData = adc.buffer_left[crossbar.adc_dac_readBufferPosition];
        !          1733:                                adc_rightData = adc.buffer_right[crossbar.adc_dac_readBufferPosition];
        !          1734:                                break;
        !          1735:                        case 1:
        !          1736:                                /* Microphone sound for left channel, PSG sound for right channel */
        !          1737:                                adc_leftData = adc.buffer_left[crossbar.adc_dac_readBufferPosition];
        !          1738:                                adc_rightData = MixBuffer[nBufIdx][1];
        !          1739:                                break;
        !          1740:                        case 2:
        !          1741:                                /* PSG sound for left channel, microphone sound for right channel */
        !          1742:                                adc_leftData = MixBuffer[nBufIdx][0];
        !          1743:                                adc_rightData = adc.buffer_right[crossbar.adc_dac_readBufferPosition];
        !          1744:                                break;
        !          1745:                        case 3:
        !          1746:                                /* PSG sound for left and right channels */
        !          1747:                                adc_leftData = MixBuffer[nBufIdx][0];
        !          1748:                                adc_rightData = MixBuffer[nBufIdx][1];
        !          1749:                                break;
        !          1750:                }
        !          1751: 
        !          1752:                /* DAC mixing (direct ADC + crossbar) */
        !          1753:                switch (crossbar.codecInputSource) {
        !          1754:                        case 0:
        !          1755:                        default: /* Just here to remove compiler's warnings */
        !          1756:                                /* No sound */
        !          1757:                                dac_LeftData  = 0;
        !          1758:                                dac_RightData = 0;
        !          1759:                                break;
        !          1760:                        case 1:
        !          1761:                                /* direct ADC->DAC sound only ADC*4/65536 */
        !          1762:                                dac_LeftData = (adc_leftData * crossbar.gainSettingLeft) >> 14;
        !          1763:                                dac_RightData = (adc_rightData * crossbar.gainSettingRight) >> 14;
        !          1764:                                break;
        !          1765:                        case 2:
        !          1766:                                /* Crossbar->DAC sound only */
        !          1767:                                dac_LeftData = dac.buffer_left[dac.readPosition];
        !          1768:                                dac_RightData = dac.buffer_right[dac.readPosition];
        !          1769:                                break;
        !          1770:                        case 3:
        !          1771:                                /* Mixing Direct ADC sound with Crossbar->DMA sound */
        !          1772:                                dac_LeftData = ((adc_leftData * crossbar.gainSettingLeft) >> 14) +
        !          1773:                                                dac.buffer_left[dac.readPosition];
        !          1774:                                dac_RightData = ((adc_rightData  * crossbar.gainSettingRight) >> 14) +
        !          1775:                                                dac.buffer_right[dac.readPosition];
        !          1776:                                break;
        !          1777:                }
        !          1778:                        
        !          1779:                MixBuffer[nBufIdx][0] = (dac_LeftData * crossbar.attenuationSettingLeft) >> 16;
        !          1780:                MixBuffer[nBufIdx][1] = (dac_RightData * crossbar.attenuationSettingRight) >> 16;
        !          1781: 
        !          1782:                /* Upgrade dac's buffer read pointer */ 
        !          1783:                dac.readPosition_decimal += crossbar.frequence_ratio;
        !          1784:                if (dac.readPosition_decimal >= DECIMAL_PRECISION) {
        !          1785:                        intPart = (dac.readPosition_decimal >> 16);
        !          1786:                        dac.readPosition = (dac.readPosition + intPart) % DACBUFFER_SIZE;
        !          1787:                        dac.readPosition_decimal -= intPart * DECIMAL_PRECISION;
        !          1788:                }
        !          1789:                
        !          1790:                /* Upgrade adc->dac's buffer read pointer */ 
        !          1791:                crossbar.adc_dac_readBufferPosition_decimal += crossbar.frequence_ratio;
        !          1792:                if (crossbar.adc_dac_readBufferPosition_decimal >= DECIMAL_PRECISION) {
        !          1793:                        intPart = (crossbar.adc_dac_readBufferPosition_decimal >> 16);
        !          1794:                        crossbar.adc_dac_readBufferPosition = (crossbar.adc_dac_readBufferPosition + intPart) % DACBUFFER_SIZE;
        !          1795:                        crossbar.adc_dac_readBufferPosition_decimal -= intPart * DECIMAL_PRECISION;
        !          1796:                }
        !          1797:        }
        !          1798: }

unix.superglobalmegacorp.com

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