diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 68989cd3..2a6b3e9e 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -598,9 +598,9 @@ static inline void do_dsd_dop_check(unsigned &dsdMode, int &dsdCount, unsigned c } -/* I2S delivery thread */ +#ifndef CODEC_MASTER #pragma unsafe arrays -unsigned static deliver(chanend ?c_out, chanend ?c_spd_out +unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out #ifdef ADAT_TX , chanend c_adat_out , unsigned adatSmuxMode @@ -624,10 +624,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out int started = 0; #endif -#ifdef CODEC_MASTER - int firstIteration = 1; -#endif - unsigned dsdMarker = DSD_MARKER_2; /* This alternates between DSD_MARKER_1 and DSD_MARKER_2 */ int dsdCount = 0; #if (DSD_CHANS_DAC != 0) @@ -713,23 +709,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out /* Main Audio I/O loop */ while (1) { -#ifdef CODEC_MASTER - /* In CODEC master mode, the I/O loop assumes L/RCLK = 32bit clocks. - * Check this every iteration and resync if we get a bclk glitch. - */ - int syncError = 0; - - if (!firstIteration) - { - InitPorts(divide); - } - else - { - firstIteration = 0; - } - - while (!syncError) -#endif // CODEC_MASTER { #if (DSD_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT > 0) if(dsdMode == DSD_MODE_NATIVE) do_dsd_native(samplesOut, dsdSample_l, dsdSample_r, divide); @@ -757,16 +736,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out // Manual IN instruction since compiler generates an extra setc per IN (bug #15256) unsigned sample; asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); -#ifdef CODEC_MASTER - unsigned lrval; - p_lrclk :> lrval; -#ifdef I2S_MODE_TDM - syncError += (lrval != 0x00000000); -#else - syncError += (lrval != 0x80000000); -#endif // I2S_MODE_TDM -#endif // CODEC_MASTER - sample = bitrev(sample); int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 0, 2, 4.. on each line. #if (AUD_TO_USB_RATIO > 1) @@ -794,10 +763,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif - - - -#ifndef CODEC_MASTER /* LR clock delayed by one clock, This is so MSB is output on the falling edge of BCLK * after the falling edge on which LRCLK was toggled. (see I2S spec) */ /* Generate clocks LR Clock low - LEFT */ @@ -806,7 +771,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out #else p_lrclk <: 0x80000000; #endif -#endif #pragma xta endpoint "i2s_output_l" @@ -833,10 +797,8 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif // (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) -#ifndef CODEC_MASTER /* Clock out the LR Clock, the DAC data and Clock in the next sample into ADC */ doI2SClocks(divide); -#endif // !CODEC_MASTER #ifdef ADAT_TX TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 1); @@ -907,23 +869,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out /* Manual IN instruction since compiler generates an extra setc per IN (bug #15256) */ unsigned sample; asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); -#ifdef CODEC_MASTER - unsigned lrval; - p_lrclk :> lrval; -#ifdef I2S_MODE_TDM - if (frameCount == (I2S_CHANS_PER_FRAME-2)) - { - syncError += (lrval != 0x80000000); - } - else - { - syncError += (lrval != 0x00000000); - } -#else - syncError += (lrval != 0x7FFFFFFF); -#endif // I2S_MODE_TDM -#endif // CODEC_MASTER - sample = bitrev(sample); int chanIndex = ((frameCount-1)&(I2S_CHANS_PER_FRAME-1))+i; // channels 1, 3, 5.. on each line. #if (AUD_TO_USB_RATIO > 1 && !I2S_DOWNSAMPLE_MONO_IN) @@ -951,7 +896,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif -#ifndef CODEC_MASTER #ifdef I2S_MODE_TDM if(frameCount == (I2S_CHANS_PER_FRAME-2)) p_lrclk <: 0x80000000; @@ -959,7 +903,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out p_lrclk <: 0x00000000; #else p_lrclk <: 0x7FFFFFFF; -#endif #endif index = 0; @@ -986,11 +929,7 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif // (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) -#ifndef CODEC_MASTER doI2SClocks(divide); -#endif // !CODEC_MASTER - - } // !dsdMode do_dsd_dop_check(dsdMode, dsdCount, curSamFreq, samplesOut, dsdMarker); @@ -1031,6 +970,402 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out #pragma xta endpoint "deliver_return" return 0; } +#endif //ndef CODEC_MASTER + + +#ifdef CODEC_MASTER +/* I2S delivery thread */ +#pragma unsafe arrays +unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out +#ifdef ADAT_TX + , chanend c_adat_out + , unsigned adatSmuxMode +#endif + , unsigned divide, unsigned curSamFreq +#if(defined(SPDIF_RX) || defined(ADAT_RX)) + , chanend c_dig_rx +#endif +#if (NUM_PDM_MICS > 0) + , chanend c_pdm_pcm +#endif +) +{ + + /* Since DAC and ADC buffered ports off by one sample we buffer previous ADC frame */ + unsigned readBuffNo = 0; + unsigned index; + +#ifdef RAMP_CHECK + unsigned prev=0; + int started = 0; +#endif + + int firstIteration = 1; + + unsigned dsdMarker = DSD_MARKER_2; /* This alternates between DSD_MARKER_1 and DSD_MARKER_2 */ + int dsdCount = 0; +#if (DSD_CHANS_DAC != 0) + int everyOther = 1; + unsigned dsdSample_l = 0x96960000; + unsigned dsdSample_r = 0x96960000; +#endif + unsigned underflowWord = 0; + + unsigned frameCount = 0; +#ifdef ADAT_TX + adatCounter = 0; +#endif + +#if(DSD_CHANS_DAC != 0) + if(dsdMode == DSD_MODE_DOP) + { + underflowWord = 0xFA969600; + } + else if(dsdMode == DSD_MODE_NATIVE) + { + underflowWord = 0x96969696; + } +#endif + + unsigned audioToUsbRatioCounter = 0; +#if (NUM_PDM_MICS > 0) + unsigned audioToMicsRatioCounter = 0; +#endif + +#if (AUD_TO_USB_RATIO > 1) + union i2sInDs3 + { + long long doubleWordAlignmentEnsured; + int32_t delayLine[I2S_DOWNSAMPLE_CHANS_IN][SRC_FF3V_FIR_NUM_PHASES][SRC_FF3V_FIR_TAPS_PER_PHASE]; + } i2sInDs3; + memset(&i2sInDs3.delayLine, 0, sizeof i2sInDs3.delayLine); + int64_t i2sInDs3Sum[I2S_DOWNSAMPLE_CHANS_IN]; + + union i2sOutUs3 + { + long long doubleWordAlignmentEnsured; + int32_t delayLine[I2S_CHANS_DAC][SRC_FF3V_FIR_TAPS_PER_PHASE]; + } i2sOutUs3; + memset(&i2sOutUs3.delayLine, 0, sizeof i2sOutUs3.delayLine); +#endif /* (AUD_TO_USB_RATIO > 1) */ + + +#if ((DEBUG_MIC_ARRAY == 1) && (NUM_PDM_MICS > 0)) + /* Get initial samples from PDM->PCM converter to avoid stalling the decimators */ + c_pdm_pcm <: 1; + master + { +#pragma loop unroll + for(int i = PDM_MIC_INDEX; i < (NUM_PDM_MICS + PDM_MIC_INDEX); i++) + { + c_pdm_pcm :> samplesIn[readBuffNo][i]; + } + } +#endif // ((DEBUG_MIC_ARRAY == 1) && (NUM_PDM_MICS > 0)) + + UserBufferManagementInit(); + + unsigned command = DoSampleTransfer(c_out, readBuffNo, underflowWord); + + // Reinitialise user state before entering the main loop + UserBufferManagementInit(); + +#ifdef ADAT_TX + unsafe{ + //TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 0); + volatile unsigned * unsafe samplePtr = &samplesOut[ADAT_TX_INDEX]; + outuint(c_adat_out, (unsigned) samplePtr); + } +#endif + if(command) + { + return command; + } + + InitPorts(divide); + + /* Main Audio I/O loop */ + while (1) + { + /* In CODEC master mode, the I/O loop assumes L/RCLK = 32bit clocks. + * Check this every iteration and resync if we get a bclk glitch. + */ + int syncError = 0; + + if (!firstIteration) + { + InitPorts(divide); + } + else + { + firstIteration = 0; + } + + while (!syncError) + { +#if (DSD_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT > 0) + if(dsdMode == DSD_MODE_NATIVE) do_dsd_native(samplesOut, dsdSample_l, dsdSample_r, divide); + else if(dsdMode == DSD_MODE_DOP) do_dsp_dop(everyOther, samplesOut, dsdSample_l, dsdSample_r, divide); + else +#endif + { +#if (I2S_CHANS_ADC != 0) +#if (AUD_TO_USB_RATIO > 1) + if (0 == audioToUsbRatioCounter) + { + memset(&i2sInDs3Sum, 0, sizeof i2sInDs3Sum); + } +#endif /* (AUD_TO_USB_RATIO > 1) */ + /* Input previous L sample into L in buffer */ + index = 0; + /* First input (i.e. frameCount == 0) we read last ADC channel of previous frame.. */ + unsigned buffIndex = (frameCount > 1) ? !readBuffNo : readBuffNo; + +#pragma loop unroll + /* First time around we get channel 7 of TDM8 */ + for(int i = 0; i < I2S_CHANS_ADC; i+=I2S_CHANS_PER_FRAME) + { + // p_i2s_adc[index++] :> sample; + // Manual IN instruction since compiler generates an extra setc per IN (bug #15256) + unsigned sample; + asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); + unsigned lrval; + p_lrclk :> lrval; +#ifdef I2S_MODE_TDM + syncError += (lrval != 0x00000000); +#else + syncError += (lrval != 0x80000000); +#endif // I2S_MODE_TDM + + sample = bitrev(sample); + int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 0, 2, 4.. on each line. +#if (AUD_TO_USB_RATIO > 1) + if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter) + { + samplesIn[buffIndex][chanIndex] = + src_ds3_voice_add_final_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } + else + { + i2sInDs3Sum[chanIndex] = + src_ds3_voice_add_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } +#else + samplesIn[buffIndex][chanIndex] = sample; +#endif /* (AUD_TO_USB_RATIO > 1) */ + } +#endif + + +#pragma xta endpoint "i2s_output_l" + +#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + index = 0; +#pragma loop unroll + /* Output "even" channel to DAC (i.e. left) */ + for(int i = 0; i < I2S_CHANS_DAC; i+=I2S_CHANS_PER_FRAME) + { +#if (AUD_TO_USB_RATIO > 1) + if (0 == audioToUsbRatioCounter) + { + samplesOut[frameCount+i] = src_us3_voice_input_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2], + samplesOut[frameCount+i]); + } + else /* audioToUsbRatioCounter == 1 or 2 */ + { + samplesOut[frameCount+i] = src_us3_voice_get_next_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2-audioToUsbRatioCounter]); + } +#endif /* (AUD_TO_USB_RATIO > 1) */ + p_i2s_dac[index++] <: bitrev(samplesOut[frameCount +i]); + } +#endif // (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + +#ifdef ADAT_TX + TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 1); +#endif + + if(frameCount == 0) + { + +#if defined(SPDIF_RX) || defined(ADAT_RX) + /* Sync with clockgen */ + inuint(c_dig_rx); + + /* Note, digi-data we just store in samplesIn[readBuffNo] - we only double buffer the I2S input data */ +#endif +#ifdef SPDIF_RX + asm("ldw %0, dp[g_digData]" :"=r"(samplesIn[readBuffNo][SPDIF_RX_INDEX + 0])); + asm("ldw %0, dp[g_digData+4]":"=r"(samplesIn[readBuffNo][SPDIF_RX_INDEX + 1])); +#endif +#ifdef ADAT_RX + asm("ldw %0, dp[g_digData+8]" :"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX])); + asm("ldw %0, dp[g_digData+12]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 1])); + asm("ldw %0, dp[g_digData+16]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 2])); + asm("ldw %0, dp[g_digData+20]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 3])); + asm("ldw %0, dp[g_digData+24]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 4])); + asm("ldw %0, dp[g_digData+28]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 5])); + asm("ldw %0, dp[g_digData+32]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 6])); + asm("ldw %0, dp[g_digData+36]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 7])); +#endif + +#if defined(SPDIF_RX) || defined(ADAT_RX) + /* Request digital data (with prefill) */ + outuint(c_dig_rx, 0); +#endif +#if defined(SPDIF_TX) && (NUM_USB_CHAN_OUT > 0) + outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to S/PDIF Tx thread */ + unsigned sample = samplesOut[SPDIF_TX_INDEX + 1]; + outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */ +#endif + +#if (NUM_PDM_MICS > 0) + if ((AUD_TO_MICS_RATIO - 1) == audioToMicsRatioCounter) + { + /* Get samples from PDM->PCM converter */ + c_pdm_pcm <: 1; + master + { +#pragma loop unroll + for(int i = PDM_MIC_INDEX; i < (NUM_PDM_MICS + PDM_MIC_INDEX); i++) + { + c_pdm_pcm :> samplesIn[readBuffNo][i]; + } + } + audioToMicsRatioCounter = 0; + } + else + { + ++audioToMicsRatioCounter; + } +#endif + } + +#if (I2S_CHANS_ADC != 0) + index = 0; + /* Channels 0, 2, 4.. on each line */ +#pragma loop unroll + for(int i = 0; i < I2S_CHANS_ADC; i += I2S_CHANS_PER_FRAME) + { + /* Manual IN instruction since compiler generates an extra setc per IN (bug #15256) */ + unsigned sample; + asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); + unsigned lrval; + p_lrclk :> lrval; +#ifdef I2S_MODE_TDM + if (frameCount == (I2S_CHANS_PER_FRAME-2)) + { + syncError += (lrval != 0x80000000); + } + else + { + syncError += (lrval != 0x00000000); + } +#else + syncError += (lrval != 0x7FFFFFFF); +#endif // I2S_MODE_TDM + + sample = bitrev(sample); + int chanIndex = ((frameCount-1)&(I2S_CHANS_PER_FRAME-1))+i; // channels 1, 3, 5.. on each line. +#if (AUD_TO_USB_RATIO > 1 && !I2S_DOWNSAMPLE_MONO_IN) + if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter) + { + samplesIn[buffIndex][chanIndex] = + src_ds3_voice_add_final_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } + else + { + i2sInDs3Sum[chanIndex] = + src_ds3_voice_add_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } +#else + samplesIn[buffIndex][chanIndex] = sample; +#endif /* (AUD_TO_USB_RATIO > 1) && !I2S_DOWNSAMPLE_MONO_IN */ + } +#endif + + index = 0; +#pragma xta endpoint "i2s_output_r" +#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + /* Output "odd" channel to DAC (i.e. right) */ +#pragma loop unroll + for(int i = 1; i < I2S_CHANS_DAC; i+=I2S_CHANS_PER_FRAME) + { +#if (AUD_TO_USB_RATIO > 1) + if (audioToUsbRatioCounter == 0) + { + samplesOut[frameCount+i] = src_us3_voice_input_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2], + samplesOut[frameCount+i]); + } + else + { /* audioToUsbRatioCounter is 1 or 2 */ + samplesOut[frameCount+i] = src_us3_voice_get_next_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2-audioToUsbRatioCounter]); + } +#endif /* (AUD_TO_USB_RATIO > 1) */ + p_i2s_dac[index++] <: bitrev(samplesOut[frameCount + i]); + } +#endif // (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + + } // !dsdMode + do_dsd_dop_check(dsdMode, dsdCount, curSamFreq, samplesOut, dsdMarker); + +#ifdef I2S_MODE_TDM + /* Increase frameCount by 2 since we have output two channels (per data line) */ + frameCount+=2; + if(frameCount == I2S_CHANS_PER_FRAME) +#endif + { + if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter) + { + /* Do samples transfer */ + /* The below looks a bit odd but forces the compiler to inline twice */ + unsigned command; + if(readBuffNo) + command = DoSampleTransfer(c_out, 1, underflowWord); + else + command = DoSampleTransfer(c_out, 0, underflowWord); + + if(command) + { + return command; + } + + /* Reset frame counter and flip the ADC buffer */ + audioToUsbRatioCounter = 0; + frameCount = 0; + readBuffNo = !readBuffNo; + } + else + { + ++audioToUsbRatioCounter; + } + } + } + } +#pragma xta endpoint "deliver_return" + return 0; +} +#endif //CODEC_MASTER + #if defined(SPDIF_TX) && (SPDIF_TX_TILE != AUDIO_IO_TILE) void SpdifTxWrapper(chanend c_spdif_tx) @@ -1354,7 +1689,11 @@ chanend c_dig_rx, outuint(c_adat_out, adatMultiple); outuint(c_adat_out, adatSmuxMode); #endif - command = deliver(c_mix_out +#if CODEC_MASTER + command = deliver_slave(c_mix_out +#else + command = deliver_master(c_mix_out +#endif #ifdef SPDIF_TX , c_spdif_out #else