From 232473e8a4cae4504611f1b7a4d0b1d318b35840 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Mon, 6 May 2024 10:27:22 +0100 Subject: [PATCH 01/11] Generalized the StreamingDataWidthConverter_Batch to allow padding or cropping --- streamtools.h | 57 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/streamtools.h b/streamtools.h index 64cf7ad..2b4e291 100644 --- a/streamtools.h +++ b/streamtools.h @@ -417,16 +417,20 @@ void FMPadding_Batch( } } + /** * \brief Stream Data Width Converter - Converts the width of the input stream in the output stream * * Used to upscale or downscale a stream, without any loss of data in the procedure. * For downscaling (InWidth > OutWidth), InWidth has to be a multiple of OutWidth. * For upscaling (InWidth < OutWidth), OutWidth has to be a multiple of InWidth. + * Additionally performs padding or cropping of the output stream based on the + * Resize parameter * * \tparam InWidth Width, in number of bits, of the input stream * \tparam OutWidth Width, in number of bits, of the output stream * \tparam NumInWords Number of input words to process + * \tparam Resize Padding or cropping amount in bits * * \param in Input stream * \param out Output stream @@ -435,15 +439,19 @@ void FMPadding_Batch( */ template void StreamingDataWidthConverter_Batch(hls::stream > & in, hls::stream > & out, const unsigned int numReps) { - static_assert((InWidth % OutWidth == 0) || (OutWidth % InWidth == 0), ""); - if (InWidth > OutWidth) { + + const unsigned int OutWidthUnpadded = (const unsigned int) (OutWidth - Resize); + static_assert((InWidth % OutWidthUnpadded == 0) || (OutWidthUnpadded % InWidth == 0), ""); + + if (InWidth > OutWidthUnpadded) { // emit multiple output words per input word read - const unsigned int outPerIn = InWidth / OutWidth; + const unsigned int outPerIn = InWidth / OutWidthUnpadded; const unsigned int totalIters = NumInWords * outPerIn * numReps; unsigned int o = 0; ap_uint ei = 0; @@ -454,10 +462,26 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, ei = in.read(); } // pick output word from the rightmost position - ap_uint eo = ei(OutWidth - 1, 0); + // initialized to 0 for potential padding + ap_uint eo = 0; + + if (Resize == 0) { + // no padding or cropping + eo = ei(OutWidth - 1, 0); + + } else if (Resize > 0 ) { + // pad by assigning the pre-padded width only, + // the rest have already been initialized to 0 + eo(OutWidthUnpadded - 1, 0) = ei(OutWidthUnpadded - 1, 0); + + } else { + // crop by only assigning the newly cropped width + eo(OutWidth - 1, 0) = ei(OutWidth-1, 0); + } + out.write(eo); // shift input to get new output word for next iteration - ei = ei >> OutWidth; + ei = ei >> OutWidthUnpadded; // increment written output count o++; // wraparound indices to recreate the nested loop structure @@ -474,16 +498,33 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, } } else { // InWidth < OutWidth // read multiple input words per output word emitted - const unsigned int inPerOut = OutWidth / InWidth; + const unsigned int inPerOut = OutWidthUnpadded / InWidth; const unsigned int totalIters = NumInWords * numReps; unsigned int i = 0; + // initialized to 0 for potential padding ap_uint eo = 0; for (unsigned int t = 0; t < totalIters; t++) { #pragma HLS pipeline style=flp II=1 // read input and shift into output buffer ap_uint ei = in.read(); eo = eo >> InWidth; - eo(OutWidth - 1, OutWidth - InWidth) = ei; + + if (Resize == 0) { + // no padding or cropping + eo(OutWidth - 1, OutWidth - InWidth) = ei; + + } else if (Resize > 0) { + // pad by assigning the pre-padded width only, + // the rest have already been initialized to 0 + eo(OutWidthUnpadded - 1, OutWidthUnpadded - InWidth) = ei; + + } else { + // crop by only assigning the newly cropped width + eo(OutWidth - 1, OutWidth - InWidth) = ei(OutWidth-1, 0); + + } + + // increment read input count i++; // wraparound logic to recreate nested loop functionality From 671c3d8f15d1edef24acdb151cb15c1df74a2640 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Mon, 6 May 2024 16:26:20 +0100 Subject: [PATCH 02/11] Cropping and Padding decoupled to two parameters, effecting either the input or output ports only. --- streamtools.h | 77 +++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/streamtools.h b/streamtools.h index 2b4e291..1a04aca 100644 --- a/streamtools.h +++ b/streamtools.h @@ -430,7 +430,8 @@ void FMPadding_Batch( * \tparam InWidth Width, in number of bits, of the input stream * \tparam OutWidth Width, in number of bits, of the output stream * \tparam NumInWords Number of input words to process - * \tparam Resize Padding or cropping amount in bits + * \tparam Cropping Cropping of the input + * \tparam Padding Padding of the output * * \param in Input stream * \param out Output stream @@ -440,18 +441,29 @@ void FMPadding_Batch( template void StreamingDataWidthConverter_Batch(hls::stream > & in, hls::stream > & out, const unsigned int numReps) { - const unsigned int OutWidthUnpadded = (const unsigned int) (OutWidth - Resize); - static_assert((InWidth % OutWidthUnpadded == 0) || (OutWidthUnpadded % InWidth == 0), ""); + const unsigned int InWidthOriginal = InWidth; + const unsigned int OutWidthOriginal = OutWidth; - if (InWidth > OutWidthUnpadded) { + if (Cropping > 0) { + // cropping, the input width has changed + const unsigned int InWidthOriginal = (const unsigned int) (InWidth - Cropping); + } else if (Resize < 0) { + // padding, the output width has changed + const unsigned int OutWidthOriginal = (const unsigned int) (OutWidth - Padding); + } + + static_assert((InWidthOriginal % OutWidthOriginal == 0) || (OutWidthOriginal % InWidthOriginal == 0), ""); + + if (InWidthOriginal > OutWidthOriginal) { // emit multiple output words per input word read - const unsigned int outPerIn = InWidth / OutWidthUnpadded; + const unsigned int outPerIn = InWidthOriginal / OutWidthOriginal; const unsigned int totalIters = NumInWords * outPerIn * numReps; unsigned int o = 0; ap_uint ei = 0; @@ -465,23 +477,14 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, // initialized to 0 for potential padding ap_uint eo = 0; - if (Resize == 0) { - // no padding or cropping - eo = ei(OutWidth - 1, 0); - - } else if (Resize > 0 ) { - // pad by assigning the pre-padded width only, - // the rest have already been initialized to 0 - eo(OutWidthUnpadded - 1, 0) = ei(OutWidthUnpadded - 1, 0); - - } else { - // crop by only assigning the newly cropped width - eo(OutWidth - 1, 0) = ei(OutWidth-1, 0); - } - + // Read only up to padded bits if they exist + eo(OutWidthOriginal - 1, 0) = ei(OutWidthOriginal - 1, 0); + out.write(eo); // shift input to get new output word for next iteration - ei = ei >> OutWidthUnpadded; + + ei = ei >> OutWidthOriginal; + // increment written output count o++; // wraparound indices to recreate the nested loop structure @@ -489,16 +492,22 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, o = 0; } } - } else if (InWidth == OutWidth) { + } else if (InWidthOriginal == OutWidthOriginal) { // straight-through copy for (unsigned int i = 0; i < NumInWords * numReps; i++) { #pragma HLS pipeline style=flp II=1 ap_uint e = in.read(); - out.write(e); + + // initialized to 0 for potential padding + ap_uint eo = 0; + // this performs padding if necessary + eo(OutWidthOriginal - 1, 0) = ei(OutWidthOriginal - 1, 0); + + out.write(eo); } } else { // InWidth < OutWidth // read multiple input words per output word emitted - const unsigned int inPerOut = OutWidthUnpadded / InWidth; + const unsigned int inPerOut = OutWidthOriginal / InWidthOriginal; const unsigned int totalIters = NumInWords * numReps; unsigned int i = 0; // initialized to 0 for potential padding @@ -507,23 +516,13 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, #pragma HLS pipeline style=flp II=1 // read input and shift into output buffer ap_uint ei = in.read(); - eo = eo >> InWidth; - - if (Resize == 0) { - // no padding or cropping - eo(OutWidth - 1, OutWidth - InWidth) = ei; - - } else if (Resize > 0) { - // pad by assigning the pre-padded width only, - // the rest have already been initialized to 0 - eo(OutWidthUnpadded - 1, OutWidthUnpadded - InWidth) = ei; - } else { - // crop by only assigning the newly cropped width - eo(OutWidth - 1, OutWidth - InWidth) = ei(OutWidth-1, 0); - - } + // If cropping exists, it should be ignored here + eo = eo >> InWidthOriginal; + // no padding or cropping + // again, ignore cropped input bits if they exist + eo(OutWidth - 1, OutWidth - InWidthOriginal) = ei(InWidthOriginal-1, 0); // increment read input count i++; From 4250e1615a6a0861fdb1bcb92540b3b35d46f698 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Mon, 6 May 2024 16:31:33 +0100 Subject: [PATCH 03/11] fixed wrong commit --- streamtools.h | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/streamtools.h b/streamtools.h index 1a04aca..17d52d3 100644 --- a/streamtools.h +++ b/streamtools.h @@ -424,14 +424,13 @@ void FMPadding_Batch( * Used to upscale or downscale a stream, without any loss of data in the procedure. * For downscaling (InWidth > OutWidth), InWidth has to be a multiple of OutWidth. * For upscaling (InWidth < OutWidth), OutWidth has to be a multiple of InWidth. - * Additionally performs padding or cropping of the output stream based on the - * Resize parameter + * Additionally performs padding or cropping of the streams * * \tparam InWidth Width, in number of bits, of the input stream * \tparam OutWidth Width, in number of bits, of the output stream * \tparam NumInWords Number of input words to process * \tparam Cropping Cropping of the input - * \tparam Padding Padding of the output +* \tparam Padding Padding of the output * * \param in Input stream * \param out Output stream @@ -448,16 +447,8 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, hls::stream > & out, const unsigned int numReps) { - const unsigned int InWidthOriginal = InWidth; - const unsigned int OutWidthOriginal = OutWidth; - - if (Cropping > 0) { - // cropping, the input width has changed - const unsigned int InWidthOriginal = (const unsigned int) (InWidth - Cropping); - } else if (Resize < 0) { - // padding, the output width has changed - const unsigned int OutWidthOriginal = (const unsigned int) (OutWidth - Padding); - } + const unsigned int InWidthOriginal = InWidth - Cropping; + const unsigned int OutWidthOriginal = OutWidth - Padding; static_assert((InWidthOriginal % OutWidthOriginal == 0) || (OutWidthOriginal % InWidthOriginal == 0), ""); @@ -496,7 +487,7 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, // straight-through copy for (unsigned int i = 0; i < NumInWords * numReps; i++) { #pragma HLS pipeline style=flp II=1 - ap_uint e = in.read(); + ap_uint ei = in.read(); // initialized to 0 for potential padding ap_uint eo = 0; From 9d845f6dc6e1d7db08dd364eadca028712c4f60a Mon Sep 17 00:00:00 2001 From: lstasytis Date: Wed, 15 May 2024 15:26:24 +0100 Subject: [PATCH 04/11] Padding and Cropping introduced via tracking of forwarded bits from input stream to output stream --- streamtools.h | 118 ++++++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/streamtools.h b/streamtools.h index 17d52d3..b30413f 100644 --- a/streamtools.h +++ b/streamtools.h @@ -422,15 +422,14 @@ void FMPadding_Batch( * \brief Stream Data Width Converter - Converts the width of the input stream in the output stream * * Used to upscale or downscale a stream, without any loss of data in the procedure. - * For downscaling (InWidth > OutWidth), InWidth has to be a multiple of OutWidth. - * For upscaling (InWidth < OutWidth), OutWidth has to be a multiple of InWidth. - * Additionally performs padding or cropping of the streams + * Additionally performs padding or cropping of the streams if + * InWidth*NumInWords != OutWidth*NumOutWords * * \tparam InWidth Width, in number of bits, of the input stream * \tparam OutWidth Width, in number of bits, of the output stream * \tparam NumInWords Number of input words to process - * \tparam Cropping Cropping of the input -* \tparam Padding Padding of the output + *\tparam NumOutWords Number of output words to process + * * \param in Input stream * \param out Output stream @@ -440,88 +439,105 @@ void FMPadding_Batch( template void StreamingDataWidthConverter_Batch(hls::stream > & in, hls::stream > & out, const unsigned int numReps) { - const unsigned int InWidthOriginal = InWidth - Cropping; - const unsigned int OutWidthOriginal = OutWidth - Padding; - - static_assert((InWidthOriginal % OutWidthOriginal == 0) || (OutWidthOriginal % InWidthOriginal == 0), ""); - - if (InWidthOriginal > OutWidthOriginal) { + if (InWidth > OutWidth) { // emit multiple output words per input word read - const unsigned int outPerIn = InWidthOriginal / OutWidthOriginal; - const unsigned int totalIters = NumInWords * outPerIn * numReps; - unsigned int o = 0; + const unsigned int totalIters = NumOutWords * numReps; + unsigned int width_written = 0; + unsigned int words_written = 0; ap_uint ei = 0; for (unsigned int t = 0; t < totalIters; t++) { #pragma HLS pipeline style=flp II=1 + // read new input word if current out count is zero - if (o == 0) { + if (width_written == 0) { ei = in.read(); } // pick output word from the rightmost position // initialized to 0 for potential padding ap_uint eo = 0; - // Read only up to padded bits if they exist - eo(OutWidthOriginal - 1, 0) = ei(OutWidthOriginal - 1, 0); + eo(OutWidth - 1, 0) = ei(OutWidth - 1, 0); out.write(eo); // shift input to get new output word for next iteration - - ei = ei >> OutWidthOriginal; + ei = ei >> OutWidth; - // increment written output count - o++; - // wraparound indices to recreate the nested loop structure - if (o == outPerIn) { - o = 0; - } + // increment written output count and size + width_written += OutWidth; + words_written += 1; + if (width_written >= InWidth || words_written >= NumOutWords) + { + width_written = 0; + if (words_written >= NumOutWords) { + words_written = 0; + } + } } - } else if (InWidthOriginal == OutWidthOriginal) { + } else if (InWidth == OutWidth) { // straight-through copy - for (unsigned int i = 0; i < NumInWords * numReps; i++) { -#pragma HLS pipeline style=flp II=1 - ap_uint ei = in.read(); - - // initialized to 0 for potential padding - ap_uint eo = 0; - // this performs padding if necessary - eo(OutWidthOriginal - 1, 0) = ei(OutWidthOriginal - 1, 0); + // NumOutWords != NumInWords if padding or cropping happened + // So we use one of two versions where we control how many times + // the streams are read/written. - out.write(eo); - } + if (NumOutWords >= NumInWords) { + for (unsigned int i = 0; i < NumOutWords * numReps; i++) { +#pragma HLS pipeline style=flp II=1 + ap_uint e = 0; + if (i < NumInWords) { + e = in.read(); + } + out.write(e); + } + } else { + for (unsigned int i = 0; i < NumInWords * numReps; i++) { +#pragma HLS pipeline style=flp II=1 + ap_uint e = in.read(); + if (i < NumOutWords) { + out.write(e); + } + } + } } else { // InWidth < OutWidth // read multiple input words per output word emitted - const unsigned int inPerOut = OutWidthOriginal / InWidthOriginal; const unsigned int totalIters = NumInWords * numReps; unsigned int i = 0; + unsigned int width_read = 0; + unsigned int words_read = 0; // initialized to 0 for potential padding - ap_uint eo = 0; + // we allocate InWidth extra space for cases where we have leftover from + // a previous word due to our width_read tracking scheme for when to + // write out eo (potentially introducing padding or cropping) + ap_uint eo = 0; for (unsigned int t = 0; t < totalIters; t++) { #pragma HLS pipeline style=flp II=1 // read input and shift into output buffer ap_uint ei = in.read(); - // If cropping exists, it should be ignored here - eo = eo >> InWidthOriginal; + // important to shift in 0s for padding + eo = eo >> InWidth; - // no padding or cropping - // again, ignore cropped input bits if they exist - eo(OutWidth - 1, OutWidth - InWidthOriginal) = ei(InWidthOriginal-1, 0); + eo(OutWidth+InWidth - 1, OutWidth) = ei(InWidth-1, 0); + + // increment words added + words_read += 1; + // increment width added + width_read += InWidth; - // increment read input count - i++; // wraparound logic to recreate nested loop functionality - if (i == inPerOut) { - i = 0; - out.write(eo); - } + if (width_read >= OutWidth || words_read >= NumInWords) { + width_read -= OutWidth; + words_read = 0; + out.write(eo(OutWidth+InWidth-1,InWidth)); + if (words_read >= NumInWords) { + words_read = 0; + } + } } } } From 28eeeffb427a3ab1b9ffd7c4fa90e29c441375a7 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Thu, 23 May 2024 09:37:56 +0100 Subject: [PATCH 05/11] DWC version which performs data width conversion, padding and cropping by using a shift register where either the input or the output word are in a static position while the other are dynamically tracked as to where the write the bits using a variable for tracking how many values are currently in the buffer. --- streamtools.h | 102 +++++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 46 deletions(-) diff --git a/streamtools.h b/streamtools.h index b30413f..9479d81 100644 --- a/streamtools.h +++ b/streamtools.h @@ -448,36 +448,47 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, if (InWidth > OutWidth) { // emit multiple output words per input word read const unsigned int totalIters = NumOutWords * numReps; - unsigned int width_written = 0; + + unsigned int words_written = 0; - ap_uint ei = 0; + unsigned int words_read = 0; + unsigned int els_in_buffer = 0; + + // we allocate OutWidth extra space for cases where we have leftover from + // a previous word due to our els_in_buffer tracking scheme for when to + // read in ei (potentially introducing padding or cropping) + ap_uint eo = 0; + for (unsigned int t = 0; t < totalIters; t++) { #pragma HLS pipeline style=flp II=1 - // read new input word if current out count is zero - if (width_written == 0) { - ei = in.read(); + + // conditionally read in + if ((els_in_buffer < OutWidth) && words_read < NumInWords) { + ap_uint ei = in.read(); + eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); + els_in_buffer += InWidth; + words_read += 1; } - // pick output word from the rightmost position - // initialized to 0 for potential padding - ap_uint eo = 0; - - eo(OutWidth - 1, 0) = ei(OutWidth - 1, 0); - - out.write(eo); - // shift input to get new output word for next iteration - ei = ei >> OutWidth; - - // increment written output count and size - width_written += OutWidth; - words_written += 1; - if (width_written >= InWidth || words_written >= NumOutWords) - { - width_written = 0; - if (words_written >= NumOutWords) { - words_written = 0; + + if (words_written == NumOutWords-1) { + // we reached the end of the transaction for this numReps superiteration + // if we are still lacking elements, we pad the rest with 0s + words_read = 0; + words_written = 0; + if (els_in_buffer < OutWidth) { + els_in_buffer = OutWidth; } } + + + // write each cycle and shift in 0s + out.write(eo(OutWidth-1,0)); + els_in_buffer -= OutWidth; + eo = eo >> OutWidth; + words_written+=1; + + } } else if (InWidth == OutWidth) { // straight-through copy @@ -493,7 +504,7 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, e = in.read(); } out.write(e); - } + } } else { for (unsigned int i = 0; i < NumInWords * numReps; i++) { #pragma HLS pipeline style=flp II=1 @@ -506,38 +517,37 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, } else { // InWidth < OutWidth // read multiple input words per output word emitted const unsigned int totalIters = NumInWords * numReps; - unsigned int i = 0; - unsigned int width_read = 0; unsigned int words_read = 0; - // initialized to 0 for potential padding - // we allocate InWidth extra space for cases where we have leftover from - // a previous word due to our width_read tracking scheme for when to + unsigned int els_in_buffer = 0; + + // we allocate OutWidth extra space for cases where we have leftover from + // a previous word due to our els_in_buffer tracking scheme for when to // write out eo (potentially introducing padding or cropping) ap_uint eo = 0; for (unsigned int t = 0; t < totalIters; t++) { #pragma HLS pipeline style=flp II=1 - // read input and shift into output buffer - ap_uint ei = in.read(); - - // important to shift in 0s for padding - eo = eo >> InWidth; - eo(OutWidth+InWidth - 1, OutWidth) = ei(InWidth-1, 0); - - // increment words added + // read input each cycle and shift into output buffer + ap_uint ei = in.read(); + eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); + els_in_buffer += InWidth; words_read += 1; - // increment width added - width_read += InWidth; - // wraparound logic to recreate nested loop functionality - if (width_read >= OutWidth || words_read >= NumInWords) { - width_read -= OutWidth; + if (words_read == NumInWords) { + // we reached the end of the transaction for this numReps superiteration + // if we are still lacking elements, we pad the rest with 0s words_read = 0; - out.write(eo(OutWidth+InWidth-1,InWidth)); - if (words_read >= NumInWords) { - words_read = 0; + if (els_in_buffer < OutWidth) { + els_in_buffer = OutWidth; } - } + } + + // conditionally write out + if (els_in_buffer >= OutWidth) { + out.write(eo(OutWidth-1,0)); + els_in_buffer -= OutWidth; + eo = eo >> OutWidth; + } } } } From efe52b87a22b6d6880b8a74de958b88f19728e64 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Mon, 10 Jun 2024 15:10:55 +0100 Subject: [PATCH 06/11] Decreasing bit count used for tracking values, further cleanup --- streamtools.h | 133 ++++++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 59 deletions(-) diff --git a/streamtools.h b/streamtools.h index 9479d81..ac3066c 100644 --- a/streamtools.h +++ b/streamtools.h @@ -49,6 +49,7 @@ #define STREAMTOOLS_H #include "ap_axi_sdata.h" +#include /** * \brief Stream limiter - limits the number of stream packets @@ -418,6 +419,12 @@ void FMPadding_Batch( } + +constexpr int log2_of_template_arg(unsigned int word) +{ + return int(std::log2(word))+1; +} + /** * \brief Stream Data Width Converter - Converts the width of the input stream in the output stream * @@ -428,7 +435,11 @@ void FMPadding_Batch( * \tparam InWidth Width, in number of bits, of the input stream * \tparam OutWidth Width, in number of bits, of the output stream * \tparam NumInWords Number of input words to process - *\tparam NumOutWords Number of output words to process + * \tparam NumOutWords Number of output words to process + * \tparam NumInWordsLog Number of bits to use for tracking NumInWords + * \tparam NumOutWordsLog Number of bits to use for tracking NumOutWords + * \tparam BufferWidthLog Number of bits to use for tracking element in buffer count + * \tparam totalIters Number of loop iterations in total to process a transaction * * \param in Input stream @@ -439,57 +450,64 @@ void FMPadding_Batch( template void StreamingDataWidthConverter_Batch(hls::stream > & in, hls::stream > & out, const unsigned int numReps) { + // cant use a template argument to construct a constant using a func..? + //const unsigned int NumOutWordsLog = log2_of_template_arg(NumOutWords); + unsigned int totalItersReps = totalIters*numReps; + ap_uint words_written = 0; + ap_uint words_read = 0; + ap_uint els_in_buffer = 0; - if (InWidth > OutWidth) { - // emit multiple output words per input word read - const unsigned int totalIters = NumOutWords * numReps; - + // we allocate OutWidth extra space for cases where we have leftover from + // a previous word due to our els_in_buffer tracking scheme for when to + // read in ei (potentially introducing padding or cropping) - unsigned int words_written = 0; - unsigned int words_read = 0; - unsigned int els_in_buffer = 0; + ap_uint eo = 0; + ap_uint ei; - // we allocate OutWidth extra space for cases where we have leftover from - // a previous word due to our els_in_buffer tracking scheme for when to - // read in ei (potentially introducing padding or cropping) - ap_uint eo = 0; + if (InWidth > OutWidth) { + // emit multiple output words per input word read - for (unsigned int t = 0; t < totalIters; t++) { + for (unsigned int t = 0; t < totalItersReps; t++) { #pragma HLS pipeline style=flp II=1 - // conditionally read in - if ((els_in_buffer < OutWidth) && words_read < NumInWords) { - ap_uint ei = in.read(); - eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); - els_in_buffer += InWidth; - words_read += 1; + if (els_in_buffer < OutWidth) { + if (words_read < NumInWords){ + ei = in.read(); + words_read+=1; + eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); + } + // always introducing elements to provide padding functionality + els_in_buffer += InWidth; } - if (words_written == NumOutWords-1) { - // we reached the end of the transaction for this numReps superiteration - // if we are still lacking elements, we pad the rest with 0s + // write each cycle and shift + if (words_written < NumOutWords){ + out.write(eo(OutWidth-1,0)); + els_in_buffer -= OutWidth; + eo = eo >> OutWidth; + words_written+=1; + } + + // we reached the end of the transaction for this numReps superiteration + // reset all trackers to allow further stream IO and stop padding/cropping + if ((words_written == NumOutWords) && (words_read == NumInWords)) { words_read = 0; words_written = 0; - if (els_in_buffer < OutWidth) { - els_in_buffer = OutWidth; - } + els_in_buffer = 0; } - - - // write each cycle and shift in 0s - out.write(eo(OutWidth-1,0)); - els_in_buffer -= OutWidth; - eo = eo >> OutWidth; - words_written+=1; - } + } else if (InWidth == OutWidth) { // straight-through copy // NumOutWords != NumInWords if padding or cropping happened @@ -497,7 +515,7 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, // the streams are read/written. if (NumOutWords >= NumInWords) { - for (unsigned int i = 0; i < NumOutWords * numReps; i++) { + for (unsigned int i = 0; i < totalItersReps; i++) { #pragma HLS pipeline style=flp II=1 ap_uint e = 0; if (i < NumInWords) { @@ -506,7 +524,7 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, out.write(e); } } else { - for (unsigned int i = 0; i < NumInWords * numReps; i++) { + for (unsigned int i = 0; i < totalItersReps; i++) { #pragma HLS pipeline style=flp II=1 ap_uint e = in.read(); if (i < NumOutWords) { @@ -516,38 +534,35 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, } } else { // InWidth < OutWidth // read multiple input words per output word emitted - const unsigned int totalIters = NumInWords * numReps; - unsigned int words_read = 0; - unsigned int els_in_buffer = 0; - - // we allocate OutWidth extra space for cases where we have leftover from - // a previous word due to our els_in_buffer tracking scheme for when to - // write out eo (potentially introducing padding or cropping) - ap_uint eo = 0; - for (unsigned int t = 0; t < totalIters; t++) { + + for (unsigned int t = 0; t < totalItersReps; t++) { #pragma HLS pipeline style=flp II=1 // read input each cycle and shift into output buffer - ap_uint ei = in.read(); - eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); - els_in_buffer += InWidth; - words_read += 1; - - if (words_read == NumInWords) { - // we reached the end of the transaction for this numReps superiteration - // if we are still lacking elements, we pad the rest with 0s - words_read = 0; - if (els_in_buffer < OutWidth) { - els_in_buffer = OutWidth; - } + // padding if we ran out of input words + if (words_read < NumInWords){ + ei = in.read(); + eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); + words_read+=1; + els_in_buffer += InWidth; } - + // conditionally write out - if (els_in_buffer >= OutWidth) { + if (((els_in_buffer >= OutWidth) && (words_written < NumOutWords)) || words_read >= NumInWords) { out.write(eo(OutWidth-1,0)); els_in_buffer -= OutWidth; eo = eo >> OutWidth; + words_written+=1; + } + + // we reached the end of the transaction for this numReps superiteration + // reset all trackers to allow further stream IO and stop padding/cropping + if ((words_written == NumOutWords) && (words_read == NumInWords)) { + words_read = 0; + words_written = 0; + els_in_buffer = 0; } + } } } From 239d0fc515a3a9117a81637dcc19e3f85dcaf970 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Mon, 10 Jun 2024 15:19:09 +0100 Subject: [PATCH 07/11] bugfix --- streamtools.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/streamtools.h b/streamtools.h index ac3066c..7ca6aaa 100644 --- a/streamtools.h +++ b/streamtools.h @@ -548,7 +548,7 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, } // conditionally write out - if (((els_in_buffer >= OutWidth) && (words_written < NumOutWords)) || words_read >= NumInWords) { + if (((els_in_buffer >= OutWidth) || (words_read >= NumInWords)) && (words_written < NumOutWords)) { out.write(eo(OutWidth-1,0)); els_in_buffer -= OutWidth; eo = eo >> OutWidth; @@ -562,7 +562,6 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, words_written = 0; els_in_buffer = 0; } - } } } From 5fb0f96bd22225951958ad2fd37c330492b22fd7 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Mon, 17 Jun 2024 11:29:40 +0100 Subject: [PATCH 08/11] support for 4D input --- streamtools.h | 67 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/streamtools.h b/streamtools.h index 7ca6aaa..41339f9 100644 --- a/streamtools.h +++ b/streamtools.h @@ -49,7 +49,6 @@ #define STREAMTOOLS_H #include "ap_axi_sdata.h" -#include /** * \brief Stream limiter - limits the number of stream packets @@ -420,10 +419,10 @@ void FMPadding_Batch( -constexpr int log2_of_template_arg(unsigned int word) +/*constexpr int log2_of_template_arg(unsigned int word) { return int(std::log2(word))+1; -} +}*/ /** * \brief Stream Data Width Converter - Converts the width of the input stream in the output stream @@ -460,8 +459,7 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, hls::stream > & out, const unsigned int numReps) { // cant use a template argument to construct a constant using a func..? - //const unsigned int NumOutWordsLog = log2_of_template_arg(NumOutWords); - unsigned int totalItersReps = totalIters*numReps; + unsigned int totalItersReps = totalIters*numReps+numReps; ap_uint words_written = 0; ap_uint words_read = 0; ap_uint els_in_buffer = 0; @@ -470,6 +468,7 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, // a previous word due to our els_in_buffer tracking scheme for when to // read in ei (potentially introducing padding or cropping) + ap_uint eo_final = 0; ap_uint eo = 0; ap_uint ei; @@ -479,6 +478,23 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, for (unsigned int t = 0; t < totalItersReps; t++) { #pragma HLS pipeline style=flp II=1 + + + // we reached the end of the transaction for this numReps superiteration + // reset all trackers to allow further stream IO and stop padding/cropping + + + eo_final(OutWidth-1,0) = eo(OutWidth-1,0); + + // write each cycle and shift + if ((words_written < NumOutWords) && (els_in_buffer >= OutWidth)){ + out.write(eo_final(OutWidth-1,0)); + els_in_buffer -= OutWidth; + eo = eo >> OutWidth; + words_written+=1; + } + + // conditionally read in if (els_in_buffer < OutWidth) { if (words_read < NumInWords){ @@ -490,22 +506,17 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, els_in_buffer += InWidth; } - // write each cycle and shift - if (words_written < NumOutWords){ - out.write(eo(OutWidth-1,0)); - els_in_buffer -= OutWidth; - eo = eo >> OutWidth; - words_written+=1; - } - // we reached the end of the transaction for this numReps superiteration - // reset all trackers to allow further stream IO and stop padding/cropping + + if ((words_written == NumOutWords) && (words_read == NumInWords)) { words_read = 0; words_written = 0; els_in_buffer = 0; } + + } } else if (InWidth == OutWidth) { @@ -538,6 +549,22 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, for (unsigned int t = 0; t < totalItersReps; t++) { #pragma HLS pipeline style=flp II=1 + // we reached the end of the transaction for this numReps superiteration + // reset all trackers to allow further stream IO and stop padding/cropping + + + eo_final(OutWidth-1,0) = eo(OutWidth-1,0); + + // conditionally write out + if (((els_in_buffer >= OutWidth) || (words_read >= NumInWords)) && (words_written < NumOutWords)) { + out.write(eo_final(OutWidth-1,0)); + els_in_buffer -= OutWidth; + eo = eo >> OutWidth; + words_written+=1; + } + + + // read input each cycle and shift into output buffer // padding if we ran out of input words if (words_read < NumInWords){ @@ -547,21 +574,15 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, els_in_buffer += InWidth; } - // conditionally write out - if (((els_in_buffer >= OutWidth) || (words_read >= NumInWords)) && (words_written < NumOutWords)) { - out.write(eo(OutWidth-1,0)); - els_in_buffer -= OutWidth; - eo = eo >> OutWidth; - words_written+=1; - } - // we reached the end of the transaction for this numReps superiteration - // reset all trackers to allow further stream IO and stop padding/cropping + + if ((words_written == NumOutWords) && (words_read == NumInWords)) { words_read = 0; words_written = 0; els_in_buffer = 0; } + } } } From 0c75c5e102b643d76f18e853aed1ac880f37ea80 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Wed, 18 Sep 2024 10:14:44 +0100 Subject: [PATCH 09/11] moved datatype log computations to cpp side --- streamtools.h | 100 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 14 deletions(-) diff --git a/streamtools.h b/streamtools.h index 41339f9..faaf408 100644 --- a/streamtools.h +++ b/streamtools.h @@ -49,6 +49,8 @@ #define STREAMTOOLS_H #include "ap_axi_sdata.h" +#include "utils.hpp" +#include /** * \brief Stream limiter - limits the number of stream packets @@ -417,15 +419,87 @@ void FMPadding_Batch( } } +/** + * \brief Stream Data Width Converter - Converts the width of the input stream in the output stream + * + * Used to upscale or downscale a stream, without any loss of data in the procedure. + * For downscaling (InWidth > OutWidth), InWidth has to be a multiple of OutWidth. + * For upscaling (InWidth < OutWidth), OutWidth has to be a multiple of InWidth. + * + * \tparam InWidth Width, in number of bits, of the input stream + * \tparam OutWidth Width, in number of bits, of the output stream + * \tparam NumInWords Number of input words to process + * + * \param in Input stream + * \param out Output stream + * \param numReps Number of times the function has to be called + * + */ +template +void StreamingDataWidthConverter_Batch(hls::stream > & in, + hls::stream > & out, const unsigned int numReps) { + static_assert((InWidth % OutWidth == 0) || (OutWidth % InWidth == 0), ""); - -/*constexpr int log2_of_template_arg(unsigned int word) -{ - return int(std::log2(word))+1; -}*/ + if (InWidth > OutWidth) { + // emit multiple output words per input word read + const unsigned int outPerIn = InWidth / OutWidth; + const unsigned int totalIters = NumInWords * outPerIn * numReps; + unsigned int o = 0; + ap_uint ei = 0; + for (unsigned int t = 0; t < totalIters; t++) { +#pragma HLS pipeline style=flp II=1 + // read new input word if current out count is zero + if (o == 0) { + ei = in.read(); + } + // pick output word from the rightmost position + ap_uint eo = ei(OutWidth - 1, 0); + out.write(eo); + // shift input to get new output word for next iteration + ei = ei >> OutWidth; + // increment written output count + o++; + // wraparound indices to recreate the nested loop structure + if (o == outPerIn) { + o = 0; + } + } + } else if (InWidth == OutWidth) { + // straight-through copy + for (unsigned int i = 0; i < NumInWords * numReps; i++) { +#pragma HLS pipeline style=flp II=1 + ap_uint e = in.read(); + out.write(e); + } + } else { // InWidth < OutWidth + // read multiple input words per output word emitted + const unsigned int inPerOut = OutWidth / InWidth; + const unsigned int totalIters = NumInWords * numReps; + unsigned int i = 0; + ap_uint eo = 0; + for (unsigned int t = 0; t < totalIters; t++) { +#pragma HLS pipeline style=flp II=1 + // read input and shift into output buffer + ap_uint ei = in.read(); + eo = eo >> InWidth; + eo(OutWidth - 1, OutWidth - InWidth) = ei; + // increment read input count + i++; + // wraparound logic to recreate nested loop functionality + if (i == inPerOut) { + i = 0; + out.write(eo); + } + } + } +} /** - * \brief Stream Data Width Converter - Converts the width of the input stream in the output stream + * \brief Generalized Stream Data Width Converter - + * Converts the width of the input stream in the output stream * * Used to upscale or downscale a stream, without any loss of data in the procedure. * Additionally performs padding or cropping of the streams if @@ -435,9 +509,6 @@ void FMPadding_Batch( * \tparam OutWidth Width, in number of bits, of the output stream * \tparam NumInWords Number of input words to process * \tparam NumOutWords Number of output words to process - * \tparam NumInWordsLog Number of bits to use for tracking NumInWords - * \tparam NumOutWordsLog Number of bits to use for tracking NumOutWords - * \tparam BufferWidthLog Number of bits to use for tracking element in buffer count * \tparam totalIters Number of loop iterations in total to process a transaction * @@ -450,15 +521,16 @@ template -void StreamingDataWidthConverter_Batch(hls::stream > & in, +void StreamingDataWidthConverterGeneralized_Batch(hls::stream > & in, hls::stream > & out, const unsigned int numReps) { - // cant use a template argument to construct a constant using a func..? + const unsigned int BufferLength = InWidth+OutWidth; + constexpr unsigned NumInWordsLog = clog2(NumInWords)+1; + constexpr unsigned NumOutWordsLog = clog2(NumOutWords)+1; + constexpr unsigned BufferWidthLog = clog2(BufferLength)+1; + unsigned int totalItersReps = totalIters*numReps+numReps; ap_uint words_written = 0; ap_uint words_read = 0; From 2cd5b20f9a0b15f59326471952f3d8a4bac3af35 Mon Sep 17 00:00:00 2001 From: lstasytis Date: Wed, 18 Sep 2024 10:17:23 +0100 Subject: [PATCH 10/11] small refactor --- streamtools.h | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/streamtools.h b/streamtools.h index faaf408..c57b1d2 100644 --- a/streamtools.h +++ b/streamtools.h @@ -50,7 +50,6 @@ #include "ap_axi_sdata.h" #include "utils.hpp" -#include /** * \brief Stream limiter - limits the number of stream packets @@ -530,34 +529,24 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > constexpr unsigned NumInWordsLog = clog2(NumInWords)+1; constexpr unsigned NumOutWordsLog = clog2(NumOutWords)+1; constexpr unsigned BufferWidthLog = clog2(BufferLength)+1; - unsigned int totalItersReps = totalIters*numReps+numReps; ap_uint words_written = 0; ap_uint words_read = 0; ap_uint els_in_buffer = 0; - // we allocate OutWidth extra space for cases where we have leftover from // a previous word due to our els_in_buffer tracking scheme for when to // read in ei (potentially introducing padding or cropping) - ap_uint eo_final = 0; ap_uint eo = 0; ap_uint ei; - if (InWidth > OutWidth) { // emit multiple output words per input word read - for (unsigned int t = 0; t < totalItersReps; t++) { #pragma HLS pipeline style=flp II=1 - - // we reached the end of the transaction for this numReps superiteration // reset all trackers to allow further stream IO and stop padding/cropping - - eo_final(OutWidth-1,0) = eo(OutWidth-1,0); - // write each cycle and shift if ((words_written < NumOutWords) && (els_in_buffer >= OutWidth)){ out.write(eo_final(OutWidth-1,0)); @@ -565,8 +554,6 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > eo = eo >> OutWidth; words_written+=1; } - - // conditionally read in if (els_in_buffer < OutWidth) { if (words_read < NumInWords){ @@ -577,26 +564,17 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > // always introducing elements to provide padding functionality els_in_buffer += InWidth; } - - - - if ((words_written == NumOutWords) && (words_read == NumInWords)) { words_read = 0; words_written = 0; els_in_buffer = 0; } - - - } - } else if (InWidth == OutWidth) { // straight-through copy // NumOutWords != NumInWords if padding or cropping happened // So we use one of two versions where we control how many times // the streams are read/written. - if (NumOutWords >= NumInWords) { for (unsigned int i = 0; i < totalItersReps; i++) { #pragma HLS pipeline style=flp II=1 @@ -617,16 +595,11 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > } } else { // InWidth < OutWidth // read multiple input words per output word emitted - for (unsigned int t = 0; t < totalItersReps; t++) { #pragma HLS pipeline style=flp II=1 - // we reached the end of the transaction for this numReps superiteration // reset all trackers to allow further stream IO and stop padding/cropping - - eo_final(OutWidth-1,0) = eo(OutWidth-1,0); - // conditionally write out if (((els_in_buffer >= OutWidth) || (words_read >= NumInWords)) && (words_written < NumOutWords)) { out.write(eo_final(OutWidth-1,0)); @@ -634,9 +607,6 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > eo = eo >> OutWidth; words_written+=1; } - - - // read input each cycle and shift into output buffer // padding if we ran out of input words if (words_read < NumInWords){ @@ -645,10 +615,6 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > words_read+=1; els_in_buffer += InWidth; } - - - - if ((words_written == NumOutWords) && (words_read == NumInWords)) { words_read = 0; words_written = 0; From 2e7b259c4fb63d5f4d8fc281b9352399b6d5f494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20B=2E=20Preu=C3=9Fer?= Date: Wed, 30 Oct 2024 11:59:57 +0100 Subject: [PATCH 11/11] Add credits and align coding style. --- streamtools.h | 76 +++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/streamtools.h b/streamtools.h index c57b1d2..8e7ed05 100644 --- a/streamtools.h +++ b/streamtools.h @@ -36,6 +36,7 @@ * Thomas B. Preusser * Marie-Curie Fellow, Xilinx Ireland, Grant Agreement No. 751339 * Christoph Doehring + * Lukas Stasytis * * @file stream-tools.h * @@ -509,36 +510,37 @@ void StreamingDataWidthConverter_Batch(hls::stream > & in, * \tparam NumInWords Number of input words to process * \tparam NumOutWords Number of output words to process * \tparam totalIters Number of loop iterations in total to process a transaction - * * \param in Input stream * \param out Output stream * \param numReps Number of times the function has to be called * */ -template -void StreamingDataWidthConverterGeneralized_Batch(hls::stream > & in, - hls::stream > & out, const unsigned int numReps) { - - const unsigned int BufferLength = InWidth+OutWidth; +void StreamingDataWidthConverterGeneralized_Batch( + hls::stream> &in, + hls::stream> &out, + unsigned const numReps +) { + constexpr unsigned BufferLength = InWidth+OutWidth; constexpr unsigned NumInWordsLog = clog2(NumInWords)+1; constexpr unsigned NumOutWordsLog = clog2(NumOutWords)+1; constexpr unsigned BufferWidthLog = clog2(BufferLength)+1; - unsigned int totalItersReps = totalIters*numReps+numReps; + unsigned const totalItersReps = totalIters*numReps+numReps; + ap_uint words_written = 0; ap_uint words_read = 0; ap_uint els_in_buffer = 0; // we allocate OutWidth extra space for cases where we have leftover from // a previous word due to our els_in_buffer tracking scheme for when to - // read in ei (potentially introducing padding or cropping) - ap_uint eo_final = 0; + // read in input (potentially introducing padding or cropping) ap_uint eo = 0; - ap_uint ei; if (InWidth > OutWidth) { // emit multiple output words per input word read for (unsigned int t = 0; t < totalItersReps; t++) { @@ -546,23 +548,23 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > // we reached the end of the transaction for this numReps superiteration // reset all trackers to allow further stream IO and stop padding/cropping - eo_final(OutWidth-1,0) = eo(OutWidth-1,0); + // write each cycle and shift - if ((words_written < NumOutWords) && (els_in_buffer >= OutWidth)){ - out.write(eo_final(OutWidth-1,0)); + if ((words_written < NumOutWords) && (els_in_buffer >= OutWidth)) { + out.write(eo(OutWidth-1,0)); els_in_buffer -= OutWidth; eo = eo >> OutWidth; - words_written+=1; + words_written++; } // conditionally read in if (els_in_buffer < OutWidth) { - if (words_read < NumInWords){ - ei = in.read(); - words_read+=1; - eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); + if (words_read < NumInWords) { + ap_uint const ei = in.read(); + words_read++; + eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei; } // always introducing elements to provide padding functionality - els_in_buffer += InWidth; + els_in_buffer += InWidth; } if ((words_written == NumOutWords) && (words_read == NumInWords)) { words_read = 0; @@ -571,7 +573,7 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > } } } else if (InWidth == OutWidth) { - // straight-through copy + // straight-through copy // NumOutWords != NumInWords if padding or cropping happened // So we use one of two versions where we control how many times // the streams are read/written. @@ -579,18 +581,14 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > for (unsigned int i = 0; i < totalItersReps; i++) { #pragma HLS pipeline style=flp II=1 ap_uint e = 0; - if (i < NumInWords) { - e = in.read(); - } + if(i < NumInWords) e = in.read(); out.write(e); } } else { for (unsigned int i = 0; i < totalItersReps; i++) { #pragma HLS pipeline style=flp II=1 - ap_uint e = in.read(); - if (i < NumOutWords) { - out.write(e); - } + ap_uint const e = in.read(); + if(i < NumOutWords) out.write(e); } } } else { // InWidth < OutWidth @@ -599,20 +597,20 @@ void StreamingDataWidthConverterGeneralized_Batch(hls::stream > #pragma HLS pipeline style=flp II=1 // we reached the end of the transaction for this numReps superiteration // reset all trackers to allow further stream IO and stop padding/cropping - eo_final(OutWidth-1,0) = eo(OutWidth-1,0); + // conditionally write out if (((els_in_buffer >= OutWidth) || (words_read >= NumInWords)) && (words_written < NumOutWords)) { - out.write(eo_final(OutWidth-1,0)); + out.write(eo(OutWidth-1,0)); els_in_buffer -= OutWidth; eo = eo >> OutWidth; - words_written+=1; + words_written++; } - // read input each cycle and shift into output buffer + // read input each cycle and shift into output buffer // padding if we ran out of input words - if (words_read < NumInWords){ - ei = in.read(); - eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei(InWidth-1, 0); - words_read+=1; + if (words_read < NumInWords) { + ap_uint const ei = in.read(); + eo(InWidth + els_in_buffer - 1, els_in_buffer) = ei; + words_read++; els_in_buffer += InWidth; } if ((words_written == NumOutWords) && (words_read == NumInWords)) {