From 9893489d45b1cdb284f42231a8407fe34cf0b0f3 Mon Sep 17 00:00:00 2001 From: Marcel Lauwerijssen Date: Wed, 24 Nov 2004 16:20:29 +0000 Subject: prepared multiple clockdomains --- FFT_Test/fft.hcc | 448 +++++++++++++++++++++++++++++++++++++--------------- FFT_Test/fft.hch | 8 +- FFT_Test/runfft.hcc | 110 +++---------- 3 files changed, 350 insertions(+), 216 deletions(-) diff --git a/FFT_Test/fft.hcc b/FFT_Test/fft.hcc index 82a1a29..93f4d62 100644 --- a/FFT_Test/fft.hcc +++ b/FFT_Test/fft.hcc @@ -1,31 +1,45 @@ -#include +#define PAL_TARGET_CLOCK_RATE 50000000 + #include -#include "weights256.hch" -#include "config.hch" +#include "pal_master.hch" + +#include "audio.hch" +#include "weights_256.hch" +#include "configuration.hch" #include "debug.hch" #include "xilinxmult.hch" - -#define PERFORM_FFT_CALCULATION 1 -#define USE_UNSIGNED_AUDIO 0 -#define HARDWARE_MULTIPLY 1 -#define PRINT_DEBUG 0 +#define HARDWARE_MULTIPLY 1 +#define PERFORM_FFT_CALCULATION 1 /* Define two multi-port RAMs for FFT calculation; one for real and one for imaginary values * Extra block RAM settings are defined to make sure read and write actions can be performed * within one clock-cycle. * Left out extra settings on new board the clock changes TODO !!!! */ +#if HARDWARE_MULTIPLY +mpram +{ + ram signed 18 rwrite[256]; + rom signed 18 read[256]; +} real with {block = "BlockRAM"}; + +mpram +{ + ram signed 18 rwrite[256]; + rom signed 18 read[256]; +} imaginary with {block = "BlockRAM"}; +#else mpram { ram signed 24 rwrite[256]; rom signed 24 read[256]; -} real with {block = "BlockRAM"/*, westart=2.5, welength=1, rclkpos={1.5}, wclkpos={3}, clkpulselen=0.5*/}; +} real with {block = "BlockRAM"}; mpram { ram signed 24 rwrite[256]; rom signed 24 read[256]; -} imaginary with {block = "BlockRAM"/*, westart=2.5, welength=1, rclkpos={1.5}, wclkpos={3}, clkpulselen=0.5*/}; - +} imaginary with {block = "BlockRAM"}; +#endif // multiplication factors for equalizer function ram signed 7 eq_settings[16] = {0,2,4,7,10,13,16,19,22,26,30,35,41,48,55,63}; @@ -46,55 +60,150 @@ ram signed 7 eq_settings[16] = {0,2,4,7,10,13,16,19,22,26,30,35,41,48,55,63}; macro proc multiply(result, op_a, op_b) { #if HARDWARE_MULTIPLY - xilinxmult(result, adjs(op_a,18), adjs(op_b,18)); + xilinxmult(result, op_a, adjs(op_b,18)); #else - macro expr mul_width = (width(op_a) + width(op_b)); - result = adjs(op_a, mul_width) * adjs(op_b, mul_width); + result = (adjs(op_a,38))*(adjs(op_a,38)); #endif -/* signed result; - - fixed_mul(result,x,y); - return result;*/ } -/*macro proc multiply(result, x,y) -{ -#if HARDWARE_MULTIPLY - xilinxmult(result, adjs(x,18), adjs(y,18)); -#else - result = ((adjs(x,36))*(adjs(y,36))); + +/* + * Forward declarations + */ +static macro proc FFTRun (); +static macro expr ClockRate = PAL_ACTUAL_CLOCK_RATE; +void calculate_fft(unsigned 1 select_inverse); +void TransferAudio(unsigned 1 import); + + +chan unsigned 1 AudioOutReady; +extern chan unsigned 1 AudioInReady; + +/* Create a dual port RAM */ + +mpram DualPortRam AudioIn with {block = "BlockRAM"}; +mpram DualPortRam AudioOut with {block = "BlockRAM"}; + +#if HARDWARE_MULTIPLY +signed 18 *audioptr_in1,*audioptr_in2,*audioptr_in3,*audioptr_in4; + +signed 18 *audioptr_out1,*audioptr_out2; + +unsigned 6 *displayptr1,*displayptr2,*displayptr3,*displayptr4; +#else +signed 16 *audioptr_in1,*audioptr_in2,*audioptr_in3,*audioptr_in4; + +signed 16 *audioptr_out1,*audioptr_out2; + #endif - + +/* + * Main program + */ +void main (void) +{ + FFTRun (); } -*/ +/* + * Runs the FFT + */ +static macro proc FFTRun () +{ + unsigned 1 select_inverse, sync; + select_inverse = 0; + //pointers for double and quadruple buffering: + audioptr_in1 = &AudioIn.fft[0]; + audioptr_in2 = &AudioIn.fft[64]; + audioptr_in3 = &AudioIn.fft[128]; + audioptr_in4 = &AudioIn.fft[192]; -/******************************************************************* -* Function: calculate_fft * -* * -* Arguments * -* select_inverse Boolean that indicates FFT or iFFT calculation * -* * -* Description * -* This routine performs the Fast Fourier Transform for * -* calculation of the frequency spectrum * -* * -*******************************************************************/ + audioptr_out1 = &AudioOut.fft[0]; + audioptr_out2 = &AudioOut.fft[64]; + + displayptr1 = &audiodata.ifft_info.write[0]; + displayptr2 = &audiodata.ifft_info.write[64]; + displayptr3 = &audiodata.ifft_info.write[128]; + displayptr4 = &audiodata.ifft_info.write[192]; + + for(;;) + { + //wait for the audiodata to become available + AudioInReady ? sync; + par + { + // switch pointers + audioptr_in1 = audioptr_in2; + audioptr_in2 = audioptr_in3; + audioptr_in3 = audioptr_in4; + audioptr_in4 = audioptr_in1; + + audioptr_out1 = audioptr_out2; + audioptr_out2 = audioptr_out1; + + displayptr1=displayptr2; + displayptr2=displayptr3; + displayptr3=displayptr4; + displayptr4=displayptr1; + } + + //perform FFT + perform_fft(audioptr_in1) + select_inverse != select_inverse; + + //perform equalize +// equalize_audio(&audiodata); + + //perform IFFT + perform_ifft(audioptr_out1,displayptr1); + select_inverse != select_inverse; + + //Notify the audio I/O module of the completion of the FFT/IFFT +// AudioOutReady ! 1; + } +} + + +/************************************************************************ +* Function: calculate_fft * +* * +* Arguments * +* select_inverse Boolean that indicates FFT or iFFT calculation * +* * +* Description * +* This routine performs the Fast Fourier Transform for * +* calculation of the frequency spectrum * +* * +* Cost: 12391 cycles * +************************************************************************/ void calculate_fft(unsigned 1 select_inverse) { unsigned 4 level; unsigned 8 point1,point2,j,f,k; unsigned 9 e,i; signed 16 weight1,weight2; - signed 24 p,q,r,t; +#if HARDWARE_MULTIPLY + signed 18 p,q,r,t; +#else + signed 24 p,q,r,t; +#endif signed a,b; - macro expr rescale (x) = (x[35] @ x[28:14]); +#if HARDWARE_MULTIPLY + // Macro to provide rescaling of 36-bit result of fixed point multiply + // down to an 18-bit result. The range of bits selected depends on the + // number that represents the value of "1" in the trig function lookup + // tables. (Eg. for 16384 == 1, the lowest bit selected should be [14]). + macro expr rescale (x) = (x[35] @ x[30:14]); +#else + //Macro to rescale the multiply result down to a 24-bit value. + macro expr rescale (x) = ((x>>FRACBITS)<-24); +#endif for(level=1;level<=NUMBER_OF_COLUMNS;level++) // count all the columns - { - e=1<<(NUMBER_OF_COLUMNS-level+1); // number of points in each block in this column - f=(e>>1)<-8; // number of butterflies in each block in this column + { + e=1<<(NUMBER_OF_COLUMNS-level+1); // number of points in each block in this column + f=(e>>1)<-8; // number of butterflies in each block in this column for(j=1;j<=f;j++) // count all the butterflies in each block { @@ -114,7 +223,8 @@ void calculate_fft(unsigned 1 select_inverse) for(i=0@j;i<=NUMBER_OF_POINTS;i+=e) // count all the blocks in this column - { // Butterfly calculation + { + // Butterfly calculation par { point1 = ((i<-8)-1); @@ -123,14 +233,14 @@ void calculate_fft(unsigned 1 select_inverse) par { - p=real.read[point1]+real.rwrite[point2]; - q=imaginary.read[point1]+imaginary.rwrite[point2]; + p = (real.read[point1] >> 1) + (real.rwrite[point2] >> 1); + q = (imaginary.read[point1] >> 1) + (imaginary.rwrite[point2] >> 1); } par { - r=real.read[point1]-real.rwrite[point2]; - t=imaginary.read[point1]-imaginary.rwrite[point2]; + r = (real.read[point1] >> 1) - (real.rwrite[point2] >> 1); + t = (imaginary.read[point1] >> 1) - (imaginary.rwrite[point2] >> 1); } multiply(a,r,weight1); @@ -138,7 +248,7 @@ void calculate_fft(unsigned 1 select_inverse) par { - real.rwrite[point2] = ((a-b)>>FRACBITS)<-24; + real.rwrite[point2] = (rescale(a-b)); imaginary.rwrite[point1] = q; } @@ -148,14 +258,13 @@ void calculate_fft(unsigned 1 select_inverse) par { real.rwrite[point1] = p; - imaginary.rwrite[point2] = ((a+b)>>FRACBITS)<-24; + imaginary.rwrite[point2] = (rescale(a+b)); } } } } } - j=1; for(i=1;i>= 1; - utemp = 0@((unsigned)((stemp + 32768)<-16)); - real.rwrite[k] = (signed)(utemp); -#else //Copying the array values has been pipelined to prevent parallel access to the //pcm_audio array. This copying procedure must be finished before another //sample is read from the audio input. The time available for this loop is @@ -240,13 +362,15 @@ void perform_fft(signed 16 *pcm_audio) { //COPYING NEEDS TO BE DONE IN 2 STEPS, BECAUSE THE VALUE THAT NEEDS TO WRITTEN //TO THE REAL-RAM NEEDS TO BE AVAILABLE ON THE START OFF THE CLOCKCYCLE. +#if HARDWARE_MULTIPLY + sample = adjs(pcm_audio[k+1],18); +#else sample = adjs(pcm_audio[k+1],24); +#endif real.rwrite[k] = sample; imaginary.rwrite[k] = 0; k++; - } - -#endif + } } while (k); @@ -258,37 +382,51 @@ void perform_fft(signed 16 *pcm_audio) } -/********************************************************************/ - -void perform_ifft(signed 16 *modified_audio/*, unsigned 6 *ifft_info*/) +/******************************************************************* +* Function: perform_ifft * +* * +* Arguments * +* modified_audio Pointer to the array containing the audio data * +* * +* ifft_info Pointer to the ifft_info array containing the * +* modified waveform data for display purposes* +* * +* * +* Description * +* This routine calls the ifft algorithm and after completing that* +* it obtains the modified audio data and copies that to the * +* output arrays of the audio I/O component. Besides that it * +* also fills the array used by the display routine for * +* displaying the waveform . * +* * +* * +* Cost: 259 cycles (excl. the calculate FFT function) * +* * +*******************************************************************/ +#if HARDWARE_MULTIPLY +void perform_ifft(signed 18 *modified_audio, unsigned 6 *ifft_info) +#else +void perform_ifft(signed 16 *modified_audio, unsigned 6 *ifft_info) +#endif { unsigned 6 k; - signed 24 p; - +#if HARDWARE_MULTIPLY + signed 18 p; +#else + signed 24 p; +#endif #if PERFORM_FFT_CALCULATION calculate_fft(1); #endif k=0; -#if PRINT_DEBUG - do - { - print_string("real["); - print_hex_value(0@k); - print_string("]: "); - print_hex_value((unsigned)real.read[k]); - print_string(" imaginary["); - print_hex_value(0@k); - print_string("]: "); - print_hex_value((unsigned)imaginary.read[k]); - print_eol(); - k++; - } - while(k!=0); -#endif //initialize variables for the copying pipeline #if PERFORM_FFT_CALCULATION + #if HARDWARE_MULTIPLY + p = (real.read[(0@k)+95] << NUMBER_OF_COLUMNS); + #else p = (real.read[(0@k)+95] >> NUMBER_OF_COLUMNS); + #endif #else p = (real.read[(0@k)+95]); #endif @@ -301,59 +439,98 @@ void perform_ifft(signed 16 *modified_audio/*, unsigned 6 *ifft_info*/) //determined by the sampling rate of 44,1 Khz par { -#if PERFORM_FFT_CALCULATION - // divide samples by number of points - p = (real.read[(0@k+1)+95] >> NUMBER_OF_COLUMNS); -#else - p = (real.read[(0@k+1)+95]); + /* + * Before copying the modified audio from the local real-array + * to the output array of the audio I/O component, compensate + * for the FFT calculation by shifting the values. + * 95 is added to start the output from the middle of the sliding + * window, this is done to get a better sound quality. + */ +#if PERFORM_FFT_CALCULATION + #if HARDWARE_MULTIPLY + p = (real.read[(0@k)+95] << NUMBER_OF_COLUMNS); + #else + p = (real.read[(0@k)+95] >> NUMBER_OF_COLUMNS); + #endif +#else + p = (real.read[(0@k)+95]); #endif -#if USE_UNSIGNED_AUDIO - p -= 32768; - p <<= 1; + //Copy the modified audio from the local real array to the output array of the audio I/O component. +#if HARDWARE_MULTIPLY + modified_audio[k] = p ; +#else + modified_audio[k] = (p<-16); #endif - modified_audio[k] = (p <-16); - //ifft_info[k] = (unsigned)(p[15:10]); + //Fill the array for displaying the waveform, only the 6 MSB are needed. + ifft_info[k] = (unsigned 6)(32+(p[17:12])); + k++; } } while(k); } -/********************************************************************/ -void equalize_audio(unsigned 4 *eq_level, unsigned 7 *fft_info) +/******************************************************************* +* Function: equalize_audio * +* * +* Arguments * +* audiodata Pointer to the audiodata structure * +* * +* * +* * +* Description * +* This routine equalizes the frequencies derived by the FFT * +* calculation, according to the settings of the equalizer * +* bars. * +* * +* * +* Cost: 3844 cycles (Maximum) * +* * +*******************************************************************/ +void equalize_audio(audiodata_t *audiodata) { -#if 0 +#if HARDWARE_MULTIPLY + signed 18 p,q; +#else signed 24 p,q; - signed 16 a; +#endif + signed 18 a; unsigned 8 i, mirror_i, bit, m, n; unsigned 7 old_value; unsigned 9 tmp; - //macro expr equalize_bar = adjs(q,24)-adjs(a,24); + //macro expr equalize_bar = multiply(q,a)[29:6]; - macro proc equalize_bar() + macro proc equalize_bar(retval) { signed result; multiply(result, q,a); - return result[29:6]; +#if HARDWARE_MULTIPLY + retval = result[23:6]; //drop last 6 bit to compensate the maximum multiplication with 64 from the eq_settings array +#else + retval = result[29:6]; //drop last 6 bit to compensate the maximum multiplication with 64 from the eq_settings array +#endif } p = real.read[0] - DC_COMPONENT; // remove DC component for calculations real.rwrite[0] = p; -// imaginary.rwrite[0] = 0; // remove DC component - - for(i=0;i<=NUMBER_OF_FREQUENCIES;i++) + for(i=0;i!=NUMBER_OF_FREQUENCIES;i++) { - // set multiplication factor (0..64) for current frequency bar - a = adjs(eq_settings[eq_level[i<-7]],16); + + par + { + // set multiplication factor (0..64) for current frequency bar, The first frequency band must be equalized at 100% (63) since there is no DC-component taken into account. + a = adjs(eq_settings[audiodata->equalizer_levels_ptr[i <- 7]],18); - // multiply frequency with this factor and divide by 64 (drop 6 LSB's) - q = real.read[i]; - p = equalize_bar; + + // multiply frequency with this factor and divide by 64 (drop 6 LSB's) + q = real.read[i]; + } + equalize_bar(p); real.rwrite[i] = p; q = imaginary.read[i]; - p = equalize_bar; + equalize_bar(p); imaginary.rwrite[i] = p; // the upper part(128..255) of the spectrum is mirrored to the lower part; @@ -362,11 +539,11 @@ void equalize_audio(unsigned 4 *eq_level, unsigned 7 *fft_info) { mirror_i = (NUMBER_OF_POINTS-1)-i+1; q = real.read[mirror_i]; - p = equalize_bar; + equalize_bar(p); real.rwrite[mirror_i] = p; q = imaginary.read[mirror_i]; - p = equalize_bar; + equalize_bar(p); imaginary.rwrite[mirror_i] = p; } } @@ -374,36 +551,53 @@ void equalize_audio(unsigned 4 *eq_level, unsigned 7 *fft_info) //write data to fft_info for display purposes for(i=0;idisplay_log) { bit=126; +#if HARDWARE_MULTIPLY + while ((p[15] == 0) && (bit != 0)) +#else while ((p[21] == 0) && (bit != 0)) +#endif par { p = p<<1; bit = bit - 18; } - old_value = fft_info[i<-7]; + old_value = audiodata->fft_info.write[0 @ (i <- 7)]; tmp = ((0@old_value) + (0@bit))>>1; - fft_info[i<-7] = (old_value <= (tmp<-7)) ? (tmp<-7) : old_value-1; + audiodata->fft_info.write[0 @ (i <- 7)] = (old_value <= (tmp<-7)) ? (tmp<-7) : old_value-1; } else { - old_value = fft_info[i<-7]; - fft_info[i<-7] = (old_value<=(unsigned)(p[21:15])) ? (unsigned)(p[21:15]) : old_value-1; + old_value = audiodata->fft_info.write[0 @ (i <- 7)]; +#if HARDWARE_MULTIPLY + audiodata->fft_info.write[0 @ (i <- 7)] = (old_value<=(unsigned)(p[15:9])) ? (unsigned)(p[15:9]) : old_value-1; +#else + audiodata->fft_info.write[0 @ (i <- 7)] = (old_value<=(unsigned)(p[21:15])) ? (unsigned)(p[21:15]) : old_value-1; +#endif } } // add DC component again before inverse FFT calculation is performed + p = real.read[0] + DC_COMPONENT; real.rwrite[0] = p; -#endif } + + diff --git a/FFT_Test/fft.hch b/FFT_Test/fft.hch index 87d54e7..e44e32b 100644 --- a/FFT_Test/fft.hch +++ b/FFT_Test/fft.hch @@ -5,4 +5,10 @@ void perform_ifft(signed 18 *modified_audio ,unsigned 6 *ifft_info); void perform_fft(signed 16 *pcm_audio); void perform_ifft(signed 16 *modified_audio ,unsigned 6 *ifft_info); #endif -void equalize_audio(unsigned 4 *eq_level, unsigned 7 *fft_info); +void equalize_audio(audiodata_t *audiodata); + +mpram DualPortRam +{ + ram signed 18 audio_io[256]; + ram signed 18 fft[256]; +}; diff --git a/FFT_Test/runfft.hcc b/FFT_Test/runfft.hcc index e470b1e..0c1c371 100644 --- a/FFT_Test/runfft.hcc +++ b/FFT_Test/runfft.hcc @@ -18,44 +18,39 @@ * 29 OCT 2002 1.00 MA Created * * * ****************************************************************/ - + #include #include "pal_master.hch" -#include "config.hch" -#include "debug.hch" -#include "fft.hch" +#include "configuration.hch" +#if USE_RUNFFT #include "audio.hch" +#include "fft.hch" -#include "presets.hch" +#include "debug.hch" /* * Forward declarations */ static macro expr ClockRate = PAL_ACTUAL_CLOCK_RATE; -#if HARDWARE_MULTIPLY -//input buffer -ram signed 18 audio_buffer_in[256] with { block = "BlockRAM"}; -//output buffer -ram signed 18 audio_buffer_out[128] with { block = "BlockRAM"}; -#else -//input buffer -ram signed 16 audio_buffer_in[256] with { block = "BlockRAM"}; -//output buffer -ram signed 16 audio_buffer_out[128] with { block = "BlockRAM"}; -#endif + //EQ settings for the FFT ram unsigned 4 EQ_info[128] with { block = "BlockRAM"}; //EQ settings received from the display +extern mpram DualPortRam AudioIn; +extern mpram DualPortRam AudioOut; + +extern chan unsigned 1 AudioOutReady; +chan unsigned 1 AudioInReady; #if HARDWARE_MULTIPLY signed 18 *audioptr_in1,*audioptr_in2,*audioptr_in3,*audioptr_in4; signed 18 *audioptr_out1,*audioptr_out2; -signed 6 *displayptr1,*displayptr2,*displayptr3,*displayptr4; +unsigned 6 *displayptr1,*displayptr2,*displayptr3,*displayptr4; #else signed 16 *audioptr_in1,*audioptr_in2,*audioptr_in3,*audioptr_in4; @@ -63,34 +58,10 @@ signed 16 *audioptr_out1,*audioptr_out2; #endif -shared expr preset_address = (active_preset << 7); - -void LoadPresets(audiodata_t * audiodata) -{ - unsigned 16 temp; - unsigned 10 count; - unsigned 8 index; - - count=0; - do - { - par - { - temp = presets[index]; - index++; - } - par { audiodata->equalizer_levels.write[count] = temp[7:4]; count++; } - par { audiodata->equalizer_levels.write[count] = temp[3:0]; count++; } - par { audiodata->equalizer_levels.write[count] = temp[15:12]; count++; } - par { audiodata->equalizer_levels.write[count] = temp[11:8]; count++; } - } while (count<768); - -} - /* * FFT routine */ -macro proc audio_main(AUDIOIN, AUDIOOUT, audiodata) +macro proc audio_main(AUDIOIN, AUDIOOUT) { signed 18 sample; unsigned 6 sample_count; @@ -104,26 +75,17 @@ macro proc audio_main(AUDIOIN, AUDIOOUT, audiodata) signed Output_sample; ram unsigned 6 input[64]; - active_preset = 2; //pointers for double and quadruple buffering: - audioptr_in1 = &audio_buffer_in[0]; - audioptr_in2 = &audio_buffer_in[64]; - audioptr_in3 = &audio_buffer_in[128]; - audioptr_in4 = &audio_buffer_in[192]; - - audioptr_out1 = &audio_buffer_out[0]; - audioptr_out2 = &audio_buffer_out[64]; + audioptr_in1 = &AudioIn.audio_io[0]; + audioptr_in2 = &AudioIn.audio_io[64]; + audioptr_in3 = &AudioIn.audio_io[128]; + audioptr_in4 = &AudioIn.audio_io[192]; - displayptr1 = &audiodata->ifft_info.write[0]; - displayptr2 = &audiodata->ifft_info.write[64]; - displayptr3 = &audiodata->ifft_info.write[128]; - displayptr4 = &audiodata->ifft_info.write[192]; + audioptr_out1 = &AudioOut.audio_io[0]; + audioptr_out2 = &AudioOut.audio_io[64]; FFT_Sync=0; - - LoadPresets(&audiodata); - first = 1; par { for(;;) @@ -140,39 +102,11 @@ par audioptr_out1 = audioptr_out2; audioptr_out2 = audioptr_out1; - - displayptr1=displayptr2; - displayptr2=displayptr3; - displayptr3=displayptr4; - displayptr4=displayptr1; FFT_Sync = 0; } - - // FFT calculation - perform_fft(audioptr_in1); - -#if 1 - for(i=0;iequalizer_levels.read[preset_address+(0 @ i)]; - EQ_info[i<-7] = eqinfo; - } - - - // set volume of each individual frequency bar (equalizer) - equalize_audio(&EQ_info[0], &audiodata->fft_info.write[0]); - -#endif // inverse FFT calculation - perform_ifft(audioptr_out1,displayptr1); - -/* - for (i = 0; i != 64; i++) - { - sample = audioptr_in1[i]; - audioptr_out1[i] = sample; - } -*/ + AudioInReady ! sync; + } else delay; @@ -215,5 +149,5 @@ par } }//end par }// end function - +#endif -- cgit v0.12