--- hatari/src/falcon/crossbar.c 2019/04/09 08:48:46 1.1 +++ hatari/src/falcon/crossbar.c 2019/04/09 08:57:00 1.1.1.8 @@ -1,11 +1,11 @@ /* Hatari - Crossbar.c - This file is distributed under the GNU Public License, version 2 or at - your option any later version. Read the file gpl.txt for details. + This file is distributed under the GNU General Public License, version 2 + or at your option any later version. Read the file gpl.txt for details. Falcon Crossbar (Matrice) emulation. - input device: + input device: - DSP transmit (SSI) - external DSP connector - ADC (micro + PSG chip) @@ -22,7 +22,7 @@ - internal clock 32 MHz - external clock (DSP external port, up to 32 Mhz) - Transfers between 2 devices can use handshaking or continuous mode + Transfers between 2 devices can use handshaking or continuous mode Hardware I/O registers: $FF8900 (byte) : Sound DMA control @@ -46,14 +46,14 @@ $FF8937 (byte) : Codec Input Source $FF8938 (byte) : Codec ADC Input $FF8939 (byte) : Gain Settings Per Channel - $FF893A (byte) : Attenuation Settings Per Channel + $FF893A (word) : Attenuation Settings Per Channel $FF893C (word) : Codec Status $FF8940 (word) : GPIO Data Direction $FF8942 (word) : GPIO Data Crossbar schematics: - + - one receiving device can be connected to only one source device - one source device can be connected to multiple receiving device @@ -66,7 +66,7 @@ TRANSMIT | | | | | | | | Mic L -----| DMA ---O------O------O-----O - /---|XOR ----|\ PLAYBACK | | | | + /---|XOR ----|\ PLAYBACK | | | | PSG --| | \ | | | | \---| | /-------X--------O------O------O-----O Mic R -----|XOR ----|/ | | | | | @@ -84,9 +84,9 @@ | | Output to: - - header, - - internal speaker, - - monitor speaker + - header, + - internal speaker, + - monitor speaker */ const char crossbar_fileid[] = "Hatari Crossbar.c : " __DATE__ " " __TIME__; @@ -95,6 +95,7 @@ const char crossbar_fileid[] = "Hatari C #include "audio.h" #include "configuration.h" #include "cycInt.h" +#include "m68000.h" #include "ioMem.h" #include "log.h" #include "memorySnapShot.h" @@ -104,6 +105,8 @@ const char crossbar_fileid[] = "Hatari C #include "microphone.h" #include "stMemory.h" #include "dsp.h" +#include "clocks_timings.h" + #define DACBUFFER_SIZE 2048 @@ -111,8 +114,7 @@ const char crossbar_fileid[] = "Hatari C /* Crossbar internal functions */ -static double Crossbar_DetectSampleRate(Uint16 clock); -static void Crossbar_Recalculate_Clocks_Cycles(void); +static int Crossbar_DetectSampleRate(Uint16 clock); static void Crossbar_Start_InterruptHandler_25Mhz(void); static void Crossbar_Start_InterruptHandler_32Mhz(void); @@ -160,50 +162,50 @@ static const Uint16 Crossbar_DAC_volume_ 16462, 13851, 11654, 9806, 8250, 6942, 5841, 4915 }; -static const double Ste_SampleRates[4] = +static const int Ste_SampleRates[4] = { - 6258.0, - 12517.0, - 25033.0, - 50066.0 + 6258, + 12517, + 25033, + 50066 }; -static const double Falcon_SampleRates_25Mhz[15] = +static const int Falcon_SampleRates_25Mhz[15] = { - 49170.0, - 32780.0, - 24585.0, - 19668.0, - 16390.0, - 14049.0, - 12292.0, - 10927.0, - 9834.0, - 8940.0, - 8195.0, - 7565.0, - 7024.0, - 6556.0, - 6146.0 + 49170, + 32780, + 24585, + 19668, + 16390, + 14049, + 12292, + 10927, + 9834, + 8940, + 8195, + 7565, + 7024, + 6556, + 6146 }; -static const double Falcon_SampleRates_32Mhz[15] = +static const int Falcon_SampleRates_32Mhz[15] = { - 62500.0, - 41666.0, - 31250.0, - 25000.0, - 20833.0, - 17857.0, - 15624.0, - 13889.0, - 12500.0, - 11363.0, - 10416.0, - 9615.0, - 8928.0, - 8333.0, - 7812.0 + 62500, + 41666, + 31250, + 25000, + 20833, + 17857, + 15624, + 13889, + 12500, + 11363, + 10416, + 9615, + 8928, + 8333, + 7812 }; struct dma_s { @@ -243,7 +245,7 @@ struct crossbar_s { Uint16 attenuationSettingLeft; /* Left channel attenuation for DAC */ Uint16 attenuationSettingRight; /* Right channel attenuation for DAC */ Uint16 microphone_ADC_is_started; - + Uint32 clock25_cycles; /* cycles for 25 Mzh interrupt */ Uint32 clock25_cycles_decimal; /* decimal part of cycles counter for 25 Mzh interrupt (*DECIMAL_PRECISION) */ Uint32 clock25_cycles_counter; /* Cycle counter for 25 Mhz interrupts */ @@ -252,24 +254,26 @@ struct crossbar_s { Uint32 clock32_cycles_decimal; /* decimal part of cycles counter for 32 Mzh interrupt (*DECIMAL_PRECISION) */ Uint32 clock32_cycles_counter; /* Cycle counter for 32 Mhz interrupts */ Uint32 pendingCyclesOver32; /* Number of delayed cycles for the interrupt */ - Uint32 frequence_ratio; /* Ratio between host computer's sound frequency and hatari's sound frequency */ - Uint32 frequence_ratio2; /* Ratio between hatari's sound frequency and host computer's sound frequency */ - + Sint64 frequence_ratio; /* Ratio between host computer's sound frequency and hatari's sound frequency */ + Sint64 frequence_ratio2; /* Ratio between hatari's sound frequency and host computer's sound frequency */ + Uint32 dmaPlay_CurrentFrameStart; /* current DmaPlay Frame start ($ff8903 $ff8905 $ff8907) */ Uint32 dmaPlay_CurrentFrameCount; /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */ Uint32 dmaPlay_CurrentFrameEnd; /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */ Uint32 dmaRecord_CurrentFrameStart; /* current DmaPlay Frame end ($ff890f $ff8911 $ff8913) */ Uint32 dmaRecord_CurrentFrameCount; /* current DmaRecord Frame start ($ff8903 $ff8905 $ff8907) */ Uint32 dmaRecord_CurrentFrameEnd; /* current DmaRecord Frame end ($ff890f $ff8911 $ff8913) */ - Uint32 adc_dac_readBufferPosition; /* read position for direct adc->dac transfer */ - Uint32 adc_dac_readBufferPosition_decimal; /* decimal part of read position for direct adc->dac transfer */ + Uint32 adc2dac_readBufferPosition; /* read position for direct adc->dac transfer */ + Sint64 adc2dac_readBufferPosition_float; /* float value of read position for direct adc->dac transfer index */ + + Uint32 save_special_transfer; /* Used in a special undocumented transfer mode (dsp sent is not in handshake mode and dsp receive is in handshake mode) */ }; struct codec_s { Sint16 buffer_left[DACBUFFER_SIZE]; Sint16 buffer_right[DACBUFFER_SIZE]; + Sint64 readPosition_float; Uint32 readPosition; - Uint32 readPosition_decimal; Uint32 writePosition; Uint32 isConnectedToCodec; Uint32 isConnectedToDsp; @@ -301,10 +305,6 @@ void Crossbar_Reset(bool bCold) { nCbar_DmaSoundControl = 0; - if (bCold) - { - } - /* Stop DMA sound playing / record */ IoMem_WriteByte(0xff8901,0); dmaPlay.isRunning = 0; @@ -321,15 +321,15 @@ void Crossbar_Reset(bool bCold) /* DAC inits */ memset(dac.buffer_left, 0, sizeof(dac.buffer_left)); memset(dac.buffer_right, 0, sizeof(dac.buffer_right)); + dac.readPosition_float = 0; dac.readPosition = 0; - dac.readPosition_decimal = 0; - dac.writePosition = 0; + dac.writePosition = (dac.readPosition+DACBUFFER_SIZE/2)%DACBUFFER_SIZE; /* ADC inits */ - memset(adc.buffer_left, 0, sizeof(dac.buffer_left)); - memset(adc.buffer_right, 0, sizeof(dac.buffer_right)); + memset(adc.buffer_left, 0, sizeof(adc.buffer_left)); + memset(adc.buffer_right, 0, sizeof(adc.buffer_right)); + adc.readPosition_float = 0; adc.readPosition = 0; - adc.readPosition_decimal = 0; adc.writePosition = 0; /* DSP inits */ @@ -361,8 +361,8 @@ void Crossbar_Reset(bool bCold) crossbar.gainSettingRight = 3276; crossbar.attenuationSettingLeft = 65535; crossbar.attenuationSettingRight = 65535; - crossbar.adc_dac_readBufferPosition = 0; - crossbar.adc_dac_readBufferPosition_decimal = 0; + crossbar.adc2dac_readBufferPosition = 0; + crossbar.adc2dac_readBufferPosition_float = 0; /* Start 25 Mhz and 32 Mhz Clocks */ Crossbar_Recalculate_Clocks_Cycles(); @@ -370,10 +370,13 @@ void Crossbar_Reset(bool bCold) Crossbar_Start_InterruptHandler_32Mhz(); /* Start Microphone jack emulation */ - if (crossbar.microphone_ADC_is_started == 0) { + if (crossbar.microphone_ADC_is_started == 0) { crossbar.microphone_ADC_is_started = Microphone_Start((int)nAudioFrequency); } + /* Initialize special transfer mode */ + crossbar.save_special_transfer = 0; + /* Initialize Crossbar values after reboot */ IoMem_WriteByte(0xff8900,0x05); IoMem_WriteByte(0xff8903,0xff); @@ -402,6 +405,10 @@ void Crossbar_MemorySnapShot_Capture(boo MemorySnapShot_Store(&adc, sizeof(adc)); MemorySnapShot_Store(&dspXmit, sizeof(dspXmit)); MemorySnapShot_Store(&dspReceive, sizeof(dspReceive)); + + /* After restoring, update the clock/freq counters */ + if ( !bSave ) + Crossbar_Recalculate_Clocks_Cycles(); } @@ -410,6 +417,44 @@ void Crossbar_MemorySnapShot_Capture(boo /*----------------------------------------------------------------------*/ /** + * Write byte to Microwire Mask register(0xff8924). + * Note: On Falcon, the Microwire is not present. + * But for compatibility with the STe, Atari implemented the Microwire + * as follow (when one writes at the following address): + * $ff8922: always reads 0 for any value written at this address + * $ff8924: NOT the value, then 8 cycles later, NOT the value again to its initial value. + */ +void Crossbar_Microwire_WriteWord(void) +{ + Uint16 microwire = IoMem_ReadWord(0xff8924); + LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8924 (MicroWire Mask) write: 0x%04x\n", microwire); + + /* NOT the value and store it */ + microwire = ~microwire; + IoMem_WriteWord(0xff8924, microwire); + LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8924 (MicroWire Mask) NOT value: 0x%04x\n", microwire); + + /* Start a new Microwire interrupt */ + CycInt_AddRelativeInterrupt(8, INT_CPU_CYCLE, INTERRUPT_DMASOUND_MICROWIRE); +} + +/** + * Crossbar Microwire mask interrupt, called from dmaSnd.c + */ +void Crossbar_InterruptHandler_Microwire(void) +{ + Uint16 microwire = IoMem_ReadWord(0xff8924); + + /* Remove this interrupt from list and re-order */ + CycInt_AcknowledgeInterrupt(); + + /* NOT the value again to it's original value and store it */ + microwire = ~microwire; + IoMem_WriteWord(0xff8924, microwire); + LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff8924 (MicroWire Mask) NOT value to original: 0x%04x\n", microwire); +} + +/** * Write byte to buffer interrupts (0xff8900). */ void Crossbar_BufferInter_WriteByte(void) @@ -447,14 +492,12 @@ void Crossbar_DmaCtrlReg_WriteByte(void) else if (dmaPlay.isRunning && ((sndCtrl & CROSSBAR_SNDCTRL_PLAY) == 0)) { /* Create samples up until this point with current values */ - Sound_Update(); + Sound_Update(false); /* Turning off DMA play sound emulation */ dmaPlay.isRunning = 0; dmaPlay.loopMode = 0; nCbar_DmaSoundControl = sndCtrl; - memset(dac.buffer_left, 0, sizeof(dac.buffer_left)); - memset(dac.buffer_right, 0, sizeof(dac.buffer_right)); } /* DMA Record mode */ @@ -462,16 +505,16 @@ void Crossbar_DmaCtrlReg_WriteByte(void) { /* Turning on DMA record sound emulation */ dmaRecord.isRunning = 1; - dmaRecord.loopMode = (sndCtrl & 0x20) >> 5; nCbar_DmaSoundControl = sndCtrl; + dmaRecord.loopMode = (sndCtrl & 0x20) >> 5; Crossbar_setDmaRecord_Settings(); } else if (dmaRecord.isRunning && ((sndCtrl & CROSSBAR_SNDCTRL_RECORD) == 0)) { /* Turning off DMA record sound emulation */ - nCbar_DmaSoundControl = sndCtrl; dmaRecord.isRunning = 0; dmaRecord.loopMode = 0; + nCbar_DmaSoundControl = sndCtrl; } } @@ -876,21 +919,18 @@ void Crossbar_SrcControler_WriteWord(voi dspXmit.isTristated = 1 - ((nCbSrc >> 7) & 0x1); dspXmit.isInHandshakeMode = 1 - ((nCbSrc >> 4) & 0x1); - + crossbar.dspXmit_freq = (nCbSrc >> 5) & 0x3; crossbar.dmaPlay_freq = (nCbSrc >> 1) & 0x3; - - dmaPlay.isConnectedToDspInHandShakeMode = ((nCbSrc & 9) == 0 ? 1 : 0); } /** * Write word to Falcon Crossbar destination controller (0xff8932). Source: D/A Convertor BIT 15 14 13 12 - 00 - DMA output ------------------------------+--+ | - 01 - DSP output ------------------------------+--+ | - 10 - External input --------------------------+--+ | - 11 - ADC input -------------------------------+--' | - 0 - Handshake on, 1 - Handshake off ----------------' + 00 - DMA output ------------------------------+--+ + 01 - DSP output ------------------------------+--+ + 10 - External input --------------------------+--+ + 11 - ADC input -------------------------------+--' Source: External OutPut BIT 11 10 9 8 0 - DSP OUT, 1 - All others ---------------' | | | @@ -954,7 +994,9 @@ void Crossbar_DstControler_WriteWord(voi adc.isConnectedToDsp = (destCtrl & 0x60) == 0x60 ? 1 : 0; adc.isConnectedToDma = (destCtrl & 0x6) == 0x6 ? 1 : 0; - dmaPlay.isConnectedToDspInHandShakeMode = ((destCtrl & 7) == 2 ? 1 : 0); + dmaPlay.isConnectedToDspInHandShakeMode = (((destCtrl >> 4) & 7) == 0 ? 1 : 0); + dmaPlay.handshakeMode_Frame = dmaPlay.isConnectedToDspInHandShakeMode; + dmaRecord.isConnectedToDspInHandShakeMode = ((destCtrl & 0xf) == 2 ? 1 : 0); } @@ -998,7 +1040,7 @@ void Crossbar_TrackRecSelect_WriteByte(v /** * Write byte to CODEC input source from 16 bit adder (0xff8937). * Bit 1 : source = multiplexer - * Bit 0 : source = A/D convertor + * Bit 0 : source = A/D convertor */ void Crossbar_CodecInput_WriteByte(void) { @@ -1040,17 +1082,17 @@ void Crossbar_InputAmp_WriteByte(void) /** * Write byte to channel reduction register (attenuation for DAC device) (0xff893a). - * Bits LLLLRRRR + * Bits XXXXLLLL RRRRXXXX * Reduction is in -1.5 dB steps */ -void Crossbar_OutputReduct_WriteByte(void) +void Crossbar_OutputReduct_WriteWord(void) { - Uint8 reduction = IoMem_ReadByte(0xff893a); + Uint16 reduction = IoMem_ReadWord(0xff893a); - LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff893a (CODEC channel attenuation) write: 0x%02x\n", IoMem_ReadByte(0xff893a)); + LOG_TRACE(TRACE_CROSSBAR, "Crossbar : $ff893a (CODEC channel attenuation) write: 0x%04x\n", reduction); - crossbar.attenuationSettingLeft = Crossbar_DAC_volume_table[reduction >> 4]; - crossbar.attenuationSettingRight = Crossbar_DAC_volume_table[reduction & 0xf]; + crossbar.attenuationSettingLeft = Crossbar_DAC_volume_table[(reduction >> 8) & 0x0f]; + crossbar.attenuationSettingRight = Crossbar_DAC_volume_table[(reduction >> 4) & 0x0f]; } /** @@ -1072,7 +1114,7 @@ void Crossbar_CodecStatus_WriteWord(void /** * Recalculates internal clocks 25 Mhz and 32 Mhz cycles */ -static void Crossbar_Recalculate_Clocks_Cycles(void) +void Crossbar_Recalculate_Clocks_Cycles(void) { double cyclesClk; @@ -1080,21 +1122,25 @@ static void Crossbar_Recalculate_Clocks_ crossbar.clock32_cycles_counter = 0; /* Calculate 25 Mhz clock cycles */ +#ifdef OLD_CPU_SHIFT cyclesClk = ((double)CPU_FREQ / Crossbar_DetectSampleRate(25)) / (double)(crossbar.playTracks) / 2.0; +#else + /* Take nCpuFreqShift into account to keep a constant sound rate at all cpu freq */ + cyclesClk = ((double)( ( CPU_FREQ << nCpuFreqShift ) ) / Crossbar_DetectSampleRate(25)) / (double)(crossbar.playTracks) / 2.0; +#endif crossbar.clock25_cycles = (int)(cyclesClk); crossbar.clock25_cycles_decimal = (int)((cyclesClk - (double)(crossbar.clock25_cycles)) * (double)DECIMAL_PRECISION); /* Calculate 32 Mhz clock cycles */ +#ifdef OLD_CPU_SHIFT cyclesClk = ((double)CPU_FREQ / Crossbar_DetectSampleRate(32)) / (double)(crossbar.playTracks) / 2.0; +#else + /* Take nCpuFreqShift into account to keep a constant sound rate at all cpu freq */ + cyclesClk = ((double)( ( CPU_FREQ << nCpuFreqShift ) ) / Crossbar_DetectSampleRate(32)) / (double)(crossbar.playTracks) / 2.0; +#endif crossbar.clock32_cycles = (int)(cyclesClk); crossbar.clock32_cycles_decimal = (int)((cyclesClk - (double)(crossbar.clock32_cycles)) * (double)DECIMAL_PRECISION); - /* Recalculate ratio between host's sound frequency and hatari's sound frequency */ - crossbar.frequence_ratio = (Uint32)((Crossbar_DetectSampleRate(25) / (double)nAudioFrequency) * (double)DECIMAL_PRECISION); - - /* Recalculate ratio between hatari's sound frequency and host's sound frequency */ - crossbar.frequence_ratio2 = (Uint32)(((double)nAudioFrequency / Crossbar_DetectSampleRate(25)) * (double)DECIMAL_PRECISION); - LOG_TRACE(TRACE_CROSSBAR, "Crossbar : Recalculate_clock_Cycles\n"); LOG_TRACE(TRACE_CROSSBAR, " clock25 : %d\n", crossbar.clock25_cycles); LOG_TRACE(TRACE_CROSSBAR, " clock32 : %d\n", crossbar.clock32_cycles); @@ -1104,17 +1150,37 @@ static void Crossbar_Recalculate_Clocks_ if ((crossbar.int_freq_divider == 0) && (crossbar.steFreq == 0)) crossbar.isDacMuted = 1; - if ((crossbar.int_freq_divider == 6) || (crossbar.int_freq_divider == 8) || + if ((crossbar.int_freq_divider == 6) || (crossbar.int_freq_divider == 8) || (crossbar.int_freq_divider == 10) || (crossbar.int_freq_divider >= 12)) { crossbar.isDacMuted = 1; + LOG_TRACE(TRACE_CROSSBAR, " DAC is muted\n"); } + + // Compute Ratio between host computer sound frequency and Hatari's sound frequency. + Crossbar_Compute_Ratio(); + + // Ensure dac.writePosition is correctly set based on current dac.readPosition + // -> force dac.wordCount=0 to update dac.writePosition on next call to Crossbar_GenerateSamples() + dac.wordCount = 0; +} + +/** + * Compute Ratio between host computer sound frequency and Hatari's DAC sound frequency and + * ratio between hatari's DAC sound frequency and host's sound frequency. + * Both values use << 32 to simulate floating point precision + * Can be called by audio.c if a sound frequency value is changed in the parameter GUI. + */ +void Crossbar_Compute_Ratio(void) +{ + crossbar.frequence_ratio = ( ((Sint64)Crossbar_DetectSampleRate(25)) << 32) / nAudioFrequency; + crossbar.frequence_ratio2 = ( ((Sint64)nAudioFrequency) << 32) / Crossbar_DetectSampleRate(25); } /** * Detect sample rate frequency * clock : value of the internal clock (25 or 32). */ -static double Crossbar_DetectSampleRate(Uint16 clock) +static int Crossbar_DetectSampleRate(Uint16 clock) { /* Ste compatible sound */ if (crossbar.int_freq_divider == 0) { @@ -1138,10 +1204,11 @@ static double Crossbar_DetectSampleRate( static void Crossbar_Start_InterruptHandler_25Mhz(void) { Uint32 cycles_25; - + +//fprintf ( stderr , "start int25 %x %x %x %x\n" , crossbar.clock25_cycles, crossbar.clock25_cycles_counter, crossbar.clock25_cycles_decimal, crossbar.pendingCyclesOver25 ); cycles_25 = crossbar.clock25_cycles; crossbar.clock25_cycles_counter += crossbar.clock25_cycles_decimal; - + if (crossbar.clock25_cycles_counter >= DECIMAL_PRECISION) { crossbar.clock25_cycles_counter -= DECIMAL_PRECISION; cycles_25 ++; @@ -1165,7 +1232,8 @@ static void Crossbar_Start_InterruptHand static void Crossbar_Start_InterruptHandler_32Mhz(void) { Uint32 cycles_32; - + +//fprintf ( stderr , "start int32 %x %x %x %x\n" , crossbar.clock32_cycles, crossbar.clock32_cycles_counter, crossbar.clock32_cycles_decimal, crossbar.pendingCyclesOver32 ); cycles_32 = crossbar.clock32_cycles; crossbar.clock32_cycles_counter += crossbar.clock32_cycles_decimal; @@ -1192,6 +1260,7 @@ static void Crossbar_Start_InterruptHand */ void Crossbar_InterruptHandler_25Mhz(void) { +//fprintf ( stderr , "int25 %x\n" , crossbar.pendingCyclesOver25 ); /* How many cycle was this sound interrupt delayed (>= 0) */ crossbar.pendingCyclesOver25 += -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE ); @@ -1203,19 +1272,19 @@ void Crossbar_InterruptHandler_25Mhz(voi Crossbar_Process_DSPXmit_Transfer(); Crossbar_Process_DMAPlay_Transfer(); Crossbar_Process_ADCXmit_Transfer(); - + /* Restart the 25 Mhz clock interrupt */ Crossbar_Start_InterruptHandler_25Mhz(); return; } Crossbar_Process_ADCXmit_Transfer(); - + /* DSP Play transfer ? */ if (crossbar.dspXmit_freq == CROSSBAR_FREQ_25MHZ) { Crossbar_Process_DSPXmit_Transfer(); } - + /* DMA Play transfer ? */ if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_25MHZ) { Crossbar_Process_DMAPlay_Transfer(); @@ -1230,6 +1299,7 @@ void Crossbar_InterruptHandler_25Mhz(voi */ void Crossbar_InterruptHandler_32Mhz(void) { +//fprintf ( stderr , "int32 %x\n" , crossbar.pendingCyclesOver32 ); /* How many cycle was this sound interrupt delayed (>= 0) */ crossbar.pendingCyclesOver32 += -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE ); @@ -1242,12 +1312,12 @@ void Crossbar_InterruptHandler_32Mhz(voi Crossbar_Start_InterruptHandler_32Mhz(); return; } - + /* DSP Play transfer ? */ if (crossbar.dspXmit_freq == CROSSBAR_FREQ_32MHZ) { Crossbar_Process_DSPXmit_Transfer(); } - + /* DMA Play transfer ? */ if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_32MHZ) { Crossbar_Process_DMAPlay_Transfer(); @@ -1270,6 +1340,10 @@ static void Crossbar_Process_DSPXmit_Tra Uint16 frame=0; Sint32 data; + /* If DSP Xmit is tristated, do nothing */ + if (dspXmit.isTristated) + return; + /* Is DSP Xmit connected to DMA Record in handshake mode ? */ if (dmaRecord.isConnectedToDspInHandShakeMode) { Crossbar_Process_DMARecord_HandshakeMode(); @@ -1280,8 +1354,6 @@ static void Crossbar_Process_DSPXmit_Tra if (!dspXmit.isConnectedToCodec && !dspXmit.isConnectedToDma && !dspXmit.isConnectedToDsp) return; - LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DSP --> Crossbar transfer\n"); - if (dspXmit.wordCount == 0) { frame = 1; } @@ -1295,6 +1367,8 @@ static void Crossbar_Process_DSPXmit_Tra /* read data from DSP Xmit */ data = DSP_SsiReadTxValue(); + LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DSP --> Crossbar transfer\t0x%06x\n", data); + /* Send DSP data to the DAC ? */ if (dspXmit.isConnectedToCodec) { Crossbar_SendDataToDAC(data, dspXmit.wordCount); @@ -1341,7 +1415,7 @@ static void Crossbar_SendDataToDspReceiv } dmaPlay.handshakeMode_Frame = 0; - + /* Send the clock to the DSP SSI receive */ DSP_SsiReceive_SC0(); } @@ -1374,45 +1448,63 @@ static void Crossbar_setDmaPlay_Settings */ static void Crossbar_Process_DMAPlay_Transfer(void) { + Uint16 temp, increment_frame; Sint16 value, eightBits; Sint8 *pFrameStart; Uint8 dmaCtrlReg; - + /* if DMA play is not running, return */ if (dmaPlay.isRunning == 0) return; - - /* if handshake mode */ - if (dmaPlay.isConnectedToDspInHandShakeMode) { - if (dmaPlay.handshakeMode_Frame == 0) { - return; - } - } pFrameStart = (Sint8 *)&STRam[dmaPlay.frameStartAddr]; + increment_frame = 0; /* 16 bits stereo mode ? */ if (crossbar.is16Bits) { eightBits = 1; value = (Sint16)do_get_mem_word(&pFrameStart[dmaPlay.frameCounter]); - dmaPlay.frameCounter += 2; + increment_frame = 2; } /* 8 bits stereo ? */ else if (crossbar.isStereo) { eightBits = 64; value = (Sint16) pFrameStart[dmaPlay.frameCounter]; - dmaPlay.frameCounter ++; + increment_frame = 1; } /* 8 bits mono */ else { eightBits = 64; value = (Sint16) pFrameStart[dmaPlay.frameCounter]; if ((dmaPlay.currentFrame & 1) == 0) { - dmaPlay.frameCounter ++; + increment_frame = 1; + } + } +//fprintf ( stderr , "cbar %x %x %x\n" , dmaPlay.frameCounter , value , increment_frame ); + if (dmaPlay.isConnectedToDspInHandShakeMode) { + /* Handshake mode */ + if (dmaPlay.handshakeMode_Frame == 0) + return; + + dmaPlay.frameCounter += increment_frame; + + /* Special undocumented transfer mode : + When DMA Play --> DSP Receive is in HandShake mode at 32 Mhz, + datas are shifted 2 bits on the left after the transfer. + This occurs with all demos using the Mpeg2 player from nocrew (amanita, LostBlubb, Wait, ...) + */ + if (crossbar.dmaPlay_freq == CROSSBAR_FREQ_32MHZ) { + temp = (crossbar.save_special_transfer<<2) + ((value & 0xc000)>>14); + crossbar.save_special_transfer = value; + value = temp; } } - + else { + /* Non Handshake mode */ + dmaPlay.frameCounter += increment_frame; + } + /* Send sample to the DMA record ? */ if (dmaPlay.isConnectedToDma) { LOG_TRACE(TRACE_CROSSBAR, "Crossbar : DMA Play --> DMA record\n"); @@ -1446,12 +1538,9 @@ static void Crossbar_Process_DMAPlay_Tra /* Check if end-of-frame has been reached and raise interrupts if needed. */ if (dmaPlay.frameCounter >= dmaPlay.frameLen) { - /* Update sound */ - //Sound_Update(); - /* Send a MFP15_Int (I7) at end of replay buffer if enabled */ if (dmaPlay.mfp15_int) { - MFP_InputOnChannel(MFP_TIMER_GPIP7_BIT, MFP_IERA, &MFP_IPRA); + MFP_InputOnChannel ( MFP_INT_GPIP7 , 0 ); LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP15 (IT7) interrupt from DMA play\n"); } @@ -1465,10 +1554,18 @@ static void Crossbar_Process_DMAPlay_Tra if (dmaPlay.loopMode) { Crossbar_setDmaPlay_Settings(); - } + } else { + /* Create samples up until this point with current values */ + Sound_Update(false); + dmaCtrlReg = IoMem_ReadByte(0xff8901) & 0xfe; - IoMem_bput(0xff8901, dmaCtrlReg); + IoMem_WriteByte(0xff8901, dmaCtrlReg); + + /* Turning off DMA play sound emulation */ + dmaPlay.isRunning = 0; + dmaPlay.loopMode = 0; + nCbar_DmaSoundControl = dmaCtrlReg; } } } @@ -1513,7 +1610,7 @@ void Crossbar_SendDataToDmaRecord(Sint16 if (dmaRecord.isRunning == 0) { return; } - + pFrameStart = (Sint8 *)&STRam[dmaRecord.frameStartAddr]; /* 16 bits stereo mode ? */ @@ -1539,15 +1636,15 @@ void Crossbar_SendDataToDmaRecord(Sint16 { /* Send a MFP15_Int (I7) at end of record buffer if enabled */ if (dmaRecord.mfp15_int) { - MFP_InputOnChannel(MFP_TIMER_GPIP7_BIT, MFP_IERA, &MFP_IPRA); + MFP_InputOnChannel ( MFP_INT_GPIP7 , 0 ); LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP15 (IT7) interrupt from DMA record\n"); } - + /* Send a TimerA_Int at end of record buffer if enabled */ if (dmaRecord.timerA_int) { if (MFP_TACR == 0x08) /* Is timer A in Event Count mode? */ MFP_TimerA_EventCount_Interrupt(); - LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP Timer A interrupt from DMA record\n"); + LOG_TRACE(TRACE_CROSSBAR, "Crossbar : MFP Timer A interrupt from DMA record\n"); } if (dmaRecord.loopMode) { @@ -1555,7 +1652,12 @@ void Crossbar_SendDataToDmaRecord(Sint16 } else { dmaCtrlReg = IoMem_ReadByte(0xff8901) & 0xef; - IoMem_bput(0xff8901, dmaCtrlReg); + IoMem_WriteByte(0xff8901, dmaCtrlReg); + + /* Turning off DMA record sound emulation */ + dmaRecord.isRunning = 0; + dmaRecord.loopMode = 0; + nCbar_DmaSoundControl = dmaCtrlReg; } } } @@ -1585,7 +1687,7 @@ static void Crossbar_Process_DMARecord_H /* read data from DSP Xmit */ data = DSP_SsiReadTxValue(); dmaRecord.handshakeMode_Frame = 0; - + Crossbar_SendDataToDmaRecord(data); } @@ -1610,24 +1712,22 @@ void Crossbar_DmaRecordInHandShakeMode_F */ void Crossbar_GetMicrophoneDatas(Sint16 *micro_bufferL, Sint16 *micro_bufferR, Uint32 microBuffer_size) { - Uint32 i, size, bufferIndex, indexPos, intPart; + Uint32 i, size, bufferIndex; + Sint64 idxPos; - size = (microBuffer_size * crossbar.frequence_ratio) >> 16; + size = (microBuffer_size * crossbar.frequence_ratio>>32); bufferIndex = 0; - indexPos = 0; - + idxPos = 0; + for (i = 0; i < size; i++) { adc.writePosition = (adc.writePosition + 1) % DACBUFFER_SIZE; adc.buffer_left[adc.writePosition] = micro_bufferL[bufferIndex]; - adc.buffer_right[adc.writePosition] = micro_bufferR[bufferIndex]; + adc.buffer_right[adc.writePosition] = micro_bufferR[bufferIndex]; - indexPos += crossbar.frequence_ratio2; - if (indexPos >= DECIMAL_PRECISION) { - intPart = indexPos >> 16; - bufferIndex += intPart; - indexPos -= intPart * DECIMAL_PRECISION; - } + idxPos += crossbar.frequence_ratio2; + bufferIndex += idxPos>>32; + idxPos &= 0xffffffff; /* only keep the fractional part */ } } @@ -1638,10 +1738,10 @@ static void Crossbar_Process_ADCXmit_Tra { Sint16 sample; Uint16 frame; - + /* swap from left to right channel or right to left channel */ adc.wordCount = 1 - adc.wordCount; - + /* Left Channel */ if (adc.wordCount == 0) { sample = adc.buffer_left[adc.readPosition]; @@ -1652,12 +1752,12 @@ static void Crossbar_Process_ADCXmit_Tra adc.readPosition = (adc.readPosition + 1) % DACBUFFER_SIZE; frame = 0; } - + /* Send sample to DSP receive ? */ if (adc.isConnectedToDsp) { Crossbar_SendDataToDspReceive(sample, frame); } - + /* Send sample to DMA record ? */ if (adc.isConnectedToDma) { Crossbar_SendDataToDmaRecord(sample); @@ -1683,6 +1783,10 @@ static void Crossbar_SendDataToDAC(Sint1 { Uint16 track = crossbar.track_monitored * 2; +//fprintf ( stderr , "datadac %x %x\n" , value , dac.writePosition ); + /* Increase counter for each sample received by the DAC */ + dac.wordCount++; + if (sample_pos == track) { /* Left channel */ dac.buffer_left[dac.writePosition] = value; @@ -1695,16 +1799,19 @@ static void Crossbar_SendDataToDAC(Sint1 } /** - * Mix PSG sound with microphone sound in ADC. + * Mix PSG sound with microphone sound in ADC. * Also mix ADC sound sample with the crossbar DAC samples. * (Called by sound.c) */ void Crossbar_GenerateSamples(int nMixBufIdx, int nSamplesToGenerate) { int i, nBufIdx; - Uint32 intPart; + int n; Sint16 adc_leftData, adc_rightData, dac_LeftData, dac_RightData; - + Sint16 dac_read_left, dac_read_right; + +//fprintf ( stderr , "gen %03x %03x %03x %03x\n" , dac.writePosition , dac.readPosition , (dac.writePosition-dac.readPosition)%DACBUFFER_SIZE , nSamplesToGenerate ); + if (crossbar.isDacMuted) { /* Output sound = 0 */ for (i = 0; i < nSamplesToGenerate; i++) { @@ -1714,9 +1821,8 @@ void Crossbar_GenerateSamples(int nMixBu } /* Counters are refreshed for when DAC becomes unmuted */ - dac.readPosition = dac.writePosition; - dac.readPosition_decimal = 0; - crossbar.adc_dac_readBufferPosition = adc.writePosition; + dac.readPosition = (dac.writePosition-DACBUFFER_SIZE/2)%DACBUFFER_SIZE; + crossbar.adc2dac_readBufferPosition = adc.writePosition; return; } @@ -1729,18 +1835,18 @@ void Crossbar_GenerateSamples(int nMixBu case 0: default: /* Just here to remove compiler's warnings */ /* Microphone sound for left and right channels */ - adc_leftData = adc.buffer_left[crossbar.adc_dac_readBufferPosition]; - adc_rightData = adc.buffer_right[crossbar.adc_dac_readBufferPosition]; + adc_leftData = adc.buffer_left[crossbar.adc2dac_readBufferPosition]; + adc_rightData = adc.buffer_right[crossbar.adc2dac_readBufferPosition]; break; case 1: /* Microphone sound for left channel, PSG sound for right channel */ - adc_leftData = adc.buffer_left[crossbar.adc_dac_readBufferPosition]; + adc_leftData = adc.buffer_left[crossbar.adc2dac_readBufferPosition]; adc_rightData = MixBuffer[nBufIdx][1]; break; case 2: /* PSG sound for left channel, microphone sound for right channel */ adc_leftData = MixBuffer[nBufIdx][0]; - adc_rightData = adc.buffer_right[crossbar.adc_dac_readBufferPosition]; + adc_rightData = adc.buffer_right[crossbar.adc2dac_readBufferPosition]; break; case 3: /* PSG sound for left and right channels */ @@ -1750,6 +1856,17 @@ void Crossbar_GenerateSamples(int nMixBu } /* DAC mixing (direct ADC + crossbar) */ + /* If DAC didn't receive any data, we force left/right value to 0 */ + if ( dac.wordCount == 0 ) /* Nothing received */ + { + dac_read_left = 0; + dac_read_right = 0; + } + else + { + dac_read_left = dac.buffer_left[dac.readPosition]; + dac_read_right = dac.buffer_right[dac.readPosition]; + } switch (crossbar.codecInputSource) { case 0: default: /* Just here to remove compiler's warnings */ @@ -1764,35 +1881,219 @@ void Crossbar_GenerateSamples(int nMixBu break; case 2: /* Crossbar->DAC sound only */ - dac_LeftData = dac.buffer_left[dac.readPosition]; - dac_RightData = dac.buffer_right[dac.readPosition]; + dac_LeftData = dac_read_left; + dac_RightData = dac_read_right; break; case 3: /* Mixing Direct ADC sound with Crossbar->DMA sound */ dac_LeftData = ((adc_leftData * crossbar.gainSettingLeft) >> 14) + - dac.buffer_left[dac.readPosition]; - dac_RightData = ((adc_rightData * crossbar.gainSettingRight) >> 14) + - dac.buffer_right[dac.readPosition]; + dac_read_left; + dac_RightData = ((adc_rightData * crossbar.gainSettingRight) >> 14) + + dac_read_right; break; } - + MixBuffer[nBufIdx][0] = (dac_LeftData * crossbar.attenuationSettingLeft) >> 16; MixBuffer[nBufIdx][1] = (dac_RightData * crossbar.attenuationSettingRight) >> 16; - /* Upgrade dac's buffer read pointer */ - dac.readPosition_decimal += crossbar.frequence_ratio; - if (dac.readPosition_decimal >= DECIMAL_PRECISION) { - intPart = (dac.readPosition_decimal >> 16); - dac.readPosition = (dac.readPosition + intPart) % DACBUFFER_SIZE; - dac.readPosition_decimal -= intPart * DECIMAL_PRECISION; - } - - /* Upgrade adc->dac's buffer read pointer */ - crossbar.adc_dac_readBufferPosition_decimal += crossbar.frequence_ratio; - if (crossbar.adc_dac_readBufferPosition_decimal >= DECIMAL_PRECISION) { - intPart = (crossbar.adc_dac_readBufferPosition_decimal >> 16); - crossbar.adc_dac_readBufferPosition = (crossbar.adc_dac_readBufferPosition + intPart) % DACBUFFER_SIZE; - crossbar.adc_dac_readBufferPosition_decimal -= intPart * DECIMAL_PRECISION; + /* Upgrade dac's buffer read pointer */ + dac.readPosition_float += crossbar.frequence_ratio; + n = dac.readPosition_float >> 32; /* number of samples to skip */ + +#if 0 + if (n) { + // It becomes safe to zero old data if tail has moved + for (j=0; jdac's buffer read pointer */ + crossbar.adc2dac_readBufferPosition_float += crossbar.frequence_ratio; + n = crossbar.adc2dac_readBufferPosition_float >> 32; /* number of samples to skip */ + crossbar.adc2dac_readBufferPosition = (crossbar.adc2dac_readBufferPosition + n) % DACBUFFER_SIZE; + crossbar.adc2dac_readBufferPosition_float &= 0xffffffff; /* only keep the fractional part */ } + + /* If the DAC didn't receive any data since last call to Crossbar_GenerateSamples() */ + /* then we need to adjust dac.writePosition to be always ahead of dac.readPosition */ + if ( dac.wordCount == 0 ) + { +// fprintf ( stderr , "fix writepos %x (readpos %x)\n" , (dac.readPosition+DACBUFFER_SIZE/2)%DACBUFFER_SIZE , dac.readPosition ); + dac.writePosition = (dac.readPosition+DACBUFFER_SIZE/2)%DACBUFFER_SIZE; + } + dac.wordCount = 0; } + + +/** + * display the Crossbar registers values (for debugger info command) + */ +void Crossbar_Info(FILE *fp, Uint32 dummy) +{ + const char *matrixDMA, *matrixDSP, *matrixEXT, *matrixDAC; + char frqDMA[11], frqDAC[11], frqDSP[11], frqEXT[11]; + char frqSTE[30], frq25Mhz[30], frq32Mhz[30]; + char dataSize[15]; + static const char *matrix_tab[8] = { + "OOHO", + "OOXO", + "OHOO", + "OXOO", + "HOOO", + "XOOO", + "OOOH", + "OOOX" + }; + + if (ConfigureParams.System.nMachineType != MACHINE_FALCON) { + fprintf(fp, "Not Falcon - no Crossbar!\n"); + return; + } + + fprintf(fp, "$FF8900.b : Sound DMA control : %02x\n", IoMem_ReadByte(0xff8900)); + fprintf(fp, "$FF8901.b : Sound DMA control : %02x\n", IoMem_ReadByte(0xff8901)); + fprintf(fp, "$FF8903.b : Frame Start High : %02x\n", IoMem_ReadByte(0xff8903)); + fprintf(fp, "$FF8905.b : Frame Start middle : %02x\n", IoMem_ReadByte(0xff8905)); + fprintf(fp, "$FF8907.b : Frame Start low : %02x\n", IoMem_ReadByte(0xff8907)); + fprintf(fp, "$FF8909.b : Frame Count High : %02x\n", IoMem_ReadByte(0xff8909)); + fprintf(fp, "$FF890B.b : Frame Count middle : %02x\n", IoMem_ReadByte(0xff890b)); + fprintf(fp, "$FF890D.b : Frame Count low : %02x\n", IoMem_ReadByte(0xff890d)); + fprintf(fp, "$FF890F.b : Frame End High : %02x\n", IoMem_ReadByte(0xff890f)); + fprintf(fp, "$FF8911.b : Frame End middle : %02x\n", IoMem_ReadByte(0xff8911)); + fprintf(fp, "$FF8913.b : Frame End low : %02x\n", IoMem_ReadByte(0xff8913)); + fprintf(fp, "\n"); + fprintf(fp, "$FF8920.b : Sound Mode Control : %02x\n", IoMem_ReadByte(0xff8920)); + fprintf(fp, "$FF8921.b : Sound Mode Control : %02x\n", IoMem_ReadByte(0xff8921)); + fprintf(fp, "$FF8930.w : DMA Crossbar Input Select Controller : %04x\n", IoMem_ReadWord(0xff8930)); + fprintf(fp, "$FF8932.w : DMA Crossbar Output Select Controller : %04x\n", IoMem_ReadWord(0xff8932)); + fprintf(fp, "\n"); + fprintf(fp, "$FF8934.b : External Sync Frequency Divider : %02x\n", IoMem_ReadByte(0xff8934)); + fprintf(fp, "$FF8935.b : Internal Sync Frequency Divider : %02x\n", IoMem_ReadByte(0xff8935)); + fprintf(fp, "$FF8936.b : Record Track select : %02x\n", IoMem_ReadByte(0xff8936)); + fprintf(fp, "$FF8937.b : Codec Input Source : %02x\n", IoMem_ReadByte(0xff8937)); + fprintf(fp, "$FF8938.b : Codec ADC Input : %02x\n", IoMem_ReadByte(0xff8938)); + fprintf(fp, "$FF8939.b : Gain Settings Per Channel : %02x\n", IoMem_ReadByte(0xff8939)); + fprintf(fp, "$FF893A.b : Attenuation Settings Per Channel : %02x\n", IoMem_ReadByte(0xff893a)); + fprintf(fp, "$FF893C.w : Codec Status : %04x\n", IoMem_ReadWord(0xff893c)); + fprintf(fp, "$FF8940.w : GPIO Data Direction : %04x\n", IoMem_ReadWord(0xff8940)); + fprintf(fp, "$FF8942.w : GPIO Data : %04x\n", IoMem_ReadWord(0xff8942)); + fprintf(fp, "\n"); + + /* DAC connexion */ + switch ((IoMem_ReadWord(0xff8932) >> 13) & 0x3) { + case 0 : + /* DAC connexion with DMA Playback */ + if ((IoMem_ReadWord(0xff8930) & 0x1) == 1) + matrixDAC = "OOXO"; + else + matrixDAC = "OOHO"; + break; + case 1 : + /* DAC connexion with DSP Transmit */ + if ((IoMem_ReadWord(0xff8930) & 0x10) == 0x10) + matrixDAC = "OXOO"; + else + matrixDAC = "OHOO"; + break; + case 2 : + /* DAC connexion with External Input */ + if ((IoMem_ReadWord(0xff8930) & 0x100) == 0x100) + matrixDAC = "XOOO"; + else + matrixDAC = "HOOO"; + break; + default: /* case 3 */ + /* DAC connexion with ADC */ + matrixDAC = "OOOX"; + break; + } + + /* DMA connexion */ + matrixDMA = matrix_tab[IoMem_ReadWord(0xff8932) & 0x7]; + + /* DSP connexion */ + matrixDSP = matrix_tab[(IoMem_ReadWord(0xff8932) >> 4) & 0x7]; + + /* External input connexion */ + matrixEXT = matrix_tab[(IoMem_ReadWord(0xff8932) >> 8) & 0x7]; + + if ((IoMem_ReadByte(0xff8935) & 0xf) == 0) { + strcpy(frqDSP, "(STe Freq)"); + strcpy(frqDMA, "(STe Freq)"); + strcpy(frqEXT, "(STe Freq)"); + strcpy(frqDAC, "(STe Freq)"); + } + else { + /* DSP Clock */ + switch ((IoMem_ReadWord(0xff8930) >> 5) & 0x3) { + case 0: strcpy(frqDSP, " (25 Mhz) "); break; + case 1: strcpy(frqDSP, "(External)"); break; + case 2: strcpy(frqDSP, " (32 Mhz) "); break; + default: strcpy(frqDSP, "undefined "); break; + } + + /* DMA Clock */ + switch ((IoMem_ReadWord(0xff8930) >> 1) & 0x3) { + case 0: strcpy(frqDMA, " (25 Mhz) "); break; + case 1: strcpy(frqDMA, "(External)"); break; + case 2: strcpy(frqDMA, " (32 Mhz) "); break; + default: strcpy(frqDMA, "undefined "); break; + } + + /* External Clock */ + switch ((IoMem_ReadWord(0xff8930) >> 9) & 0x3) { + case 0: strcpy(frqEXT, " (25 Mhz) "); break; + case 1: strcpy(frqEXT, "(External)"); break; + case 2: strcpy(frqEXT, " (32 Mhz) "); break; + default: strcpy(frqEXT, "undefined "); break; + } + + /* DAC Clock */ + strcpy(frqDAC, " (25 Mhz) "); + } + + /* data size */ + switch ((IoMem_ReadByte(0xff8921) >> 6) & 0x3) { + case 0: strcpy (dataSize, "8 bits stereo"); break; + case 1: strcpy (dataSize, "16 bits stereo"); break; + case 2: strcpy (dataSize, "8 bits mono"); break; + default: strcpy (dataSize, "undefined"); break; + } + + /* STE, 25Mhz and 32 Mhz sound frequencies */ + if ((IoMem_ReadByte(0xff8935) & 0xf) == 0) { + sprintf(frqSTE, "Ste Freq : %d Khz", Ste_SampleRates[IoMem_ReadByte(0xff8921) & 0x3]); + strcpy (frq25Mhz, "25 Mhz Freq : - Khz"); + strcpy (frq32Mhz, "32 Mzh Freq : - Khz"); + } + else { + strcpy (frqSTE, "Ste Freq : - Khz"); + sprintf(frq25Mhz, "25 Mhz Freq : %d Khz", Falcon_SampleRates_25Mhz[(IoMem_ReadByte(0xff8935) & 0xf) - 1]); + sprintf(frq32Mhz, "32 Mzh Freq : %d Khz", Falcon_SampleRates_32Mhz[(IoMem_ReadByte(0xff8935) & 0xf) - 1]); + } + + /* Display the crossbar Matrix */ + fprintf(fp, " INPUT\n"); + fprintf(fp, "External Imp ---%c------%c------%c------%c\n", matrixDAC[0], matrixDMA[0], matrixDSP[0], matrixEXT[0]); + fprintf(fp, "%s | | | | O = no connexion\n", frqEXT); + fprintf(fp, " | | | | X = connexion\n"); + fprintf(fp, "Dsp Transmit ---%c------%c------%c------%c H = Handshake connexion\n", matrixDAC[1], matrixDMA[1], matrixDSP[1], matrixEXT[1]); + fprintf(fp, "%s | | | |\n", frqDSP); + fprintf(fp, " | | | | %s\n", dataSize); + fprintf(fp, "DMA PlayBack ---%c------%c------%c------%c\n", matrixDAC[2], matrixDMA[2], matrixDSP[2], matrixEXT[2]); + fprintf(fp, "%s | | | | Sound Freq :\n", frqDMA); + fprintf(fp, " | | | | %s\n", frqSTE); + fprintf(fp, "ADC ---%c------%c------%c------%c %s\n", matrixDAC[3], matrixDMA[3], matrixDSP[3], matrixEXT[3], frq25Mhz); + fprintf(fp, "%s | | | | %s\n", frqDAC, frq32Mhz); + fprintf(fp, " | | | |\n"); + fprintf(fp, " DAC DMA DSP External OUTPUT\n"); + fprintf(fp, " Record Record Out\n"); + fprintf(fp, "\n"); +} +