--- hatari/src/falcon/crossbar.c 2019/04/09 08:49:37 1.1.1.2 +++ hatari/src/falcon/crossbar.c 2019/04/09 08:53:22 1.1.1.5 @@ -1,8 +1,8 @@ /* 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: @@ -46,7 +46,7 @@ $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 @@ -111,7 +111,7 @@ const char crossbar_fileid[] = "Hatari C /* Crossbar internal functions */ -static double Crossbar_DetectSampleRate(Uint16 clock); +static int Crossbar_DetectSampleRate(Uint16 clock); static void Crossbar_Recalculate_Clocks_Cycles(void); static void Crossbar_Start_InterruptHandler_25Mhz(void); static void Crossbar_Start_InterruptHandler_32Mhz(void); @@ -160,50 +160,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 { @@ -252,8 +252,8 @@ 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) */ @@ -261,8 +261,8 @@ struct crossbar_s { 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) */ }; @@ -270,8 +270,8 @@ struct crossbar_s { 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; @@ -323,15 +323,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; /* ADC inits */ 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 */ @@ -363,8 +363,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(); @@ -415,6 +415,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) @@ -955,6 +993,8 @@ void Crossbar_DstControler_WriteWord(voi adc.isConnectedToDma = (destCtrl & 0x6) == 0x6 ? 1 : 0; dmaPlay.isConnectedToDspInHandShakeMode = (((destCtrl >> 4) & 7) == 0 ? 1 : 0); + dmaPlay.handshakeMode_Frame = dmaPlay.isConnectedToDspInHandShakeMode; + dmaRecord.isConnectedToDspInHandShakeMode = ((destCtrl & 0xf) == 2 ? 1 : 0); } @@ -1040,17 +1080,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]; } /** @@ -1101,6 +1141,7 @@ static void Crossbar_Recalculate_Clocks_ 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. @@ -1108,23 +1149,22 @@ static void Crossbar_Recalculate_Clocks_ } /** - * Compute Ratio between host computer sound frequency and Hatari's sound frequency and - * ratio between hatari's sound frequency and host's sound frequency. + * 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 = (Uint32)((Crossbar_DetectSampleRate(25) / (double)nAudioFrequency) * (double)DECIMAL_PRECISION); - - /* Recompute ratio between hatari's sound frequency and host's sound frequency */ - crossbar.frequence_ratio2 = (Uint32)(((double)nAudioFrequency / Crossbar_DetectSampleRate(25)) * (double)DECIMAL_PRECISION); + 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) { @@ -1294,8 +1334,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; } @@ -1309,6 +1347,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); @@ -1421,24 +1461,26 @@ static void Crossbar_Process_DMAPlay_Tra } } - /* if handshake mode */ - if (dmaPlay.isConnectedToDspInHandShakeMode && crossbar.dmaPlay_freq == CROSSBAR_FREQ_32MHZ) { + 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 (32 Mhz) - and DSP Send --> DAC is not in handshake mode (25 Mhz) + 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, ...)) + This occurs with all demos using the Mpeg2 player from nocrew (amanita, LostBlubb, Wait, ...) */ - temp = (crossbar.save_special_transfer<<2) + ((value & 0xc000)>>14); - crossbar.save_special_transfer = value; - value = temp; + 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; } @@ -1477,7 +1519,7 @@ static void Crossbar_Process_DMAPlay_Tra { /* 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"); } @@ -1573,7 +1615,7 @@ 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"); } @@ -1649,24 +1691,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]; - 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 */ } } @@ -1741,7 +1781,7 @@ static void Crossbar_SendDataToDAC(Sint1 void Crossbar_GenerateSamples(int nMixBufIdx, int nSamplesToGenerate) { int i, nBufIdx; - Uint32 intPart; + unsigned n; Sint16 adc_leftData, adc_rightData, dac_LeftData, dac_RightData; if (crossbar.isDacMuted) { @@ -1754,8 +1794,7 @@ 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; + crossbar.adc2dac_readBufferPosition = adc.writePosition; return; } @@ -1768,18 +1807,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 */ @@ -1823,19 +1862,15 @@ void Crossbar_GenerateSamples(int nMixBu 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; - } + dac.readPosition_float += crossbar.frequence_ratio; + n = dac.readPosition_float >> 32; /* number of samples to skip */ + dac.readPosition = (dac.readPosition + n) % DACBUFFER_SIZE; + dac.readPosition_float &= 0xffffffff; /* only keep the fractional part */ /* 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; - } + 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 */ } }