{"id":37,"date":"2006-03-01T00:00:00","date_gmt":"2006-03-09T00:00:00","guid":{"rendered":"http:\/\/www.electronics-cooling.com\/?p=37"},"modified":"2010-03-03T12:47:46","modified_gmt":"2010-03-03T12:47:46","slug":"object-oriented-design-for-dsp-hardware","status":"publish","type":"post","link":"https:\/\/www.techdesignforums.com\/practice\/technique\/object-oriented-design-for-dsp-hardware\/","title":{"rendered":"Object-oriented design for DSP hardware"},"content":{"rendered":"<p><span class=\"drop\">F<\/span>or years, ASIC and FPGA designers have \tshared the goal of having totally reusable intellectual \tproperty (IP) blocks. This goal has been \tpartially fulfilled, with the introduction of \thigh-level hardware description languages such \tas VHDL and Verilog, and powerful Register \tTransfer Level (RTL) synthesis tools in the late \t1980s and early 1990s. However, with a few \texceptions, most of the IP written for RTL \tsynthesis is substantially modified each time it \tis used in a new project.<\/p>\n<p>A new design methodology is emerging where \tthe IP blocks and their components are described \tas classes and templates in C++ and then re-used \twith the appropriate specializations for a range of different applications. \tThis way, the flexibility of being able to adapt the originally \tdesigned block to an application is retained, yet the engineer can \tstill use the original template without any modifications. \tBy adopting this methodology, it is possible to achieve an order of \tmagnitude increase in productivity for the design of digital signal \tprocessing (DSP) blocks without major compromises in the quality \tof results compared with those obtained from hand writing RTL.<\/p>\n<h3>Motivation<\/h3>\n<p>The original motivation for this exercise came from the design of \ta digital radio frequency (RF) modulator. The RF modulator&rsquo;s \tbuilding blocks include mixers for performing frequency shifting \tand various low pass and band pass filters to eliminate undesired \tcomponents of the modulated signal. All of these are implemented as \tvery simple finite impulse response (FIR) filters. The mixers are \timplemented using digital oscillators and multipliers.<\/p>\n<p>While the architecture of each of the filters and mixers is essentially \tthe same throughout the design, it is not desirable to write a single \tfilter RTL code in VHDL or Verilog and then customize it using \tgenerics or parameters. The size, bit-widths, and performance \tparameters for each permutation are very different. Creating \tspecialized instantiations of a pre-defined filter or mixer as written \tin RTL would produce an implementation that makes inefficient \tuse of the available hardware resources.<\/p>\n<div class=\"floatImage\" style=\"width: 335px;\"><img loading=\"lazy\" decoding=\"async\" id=\"||CPIMAGE:4067|\" src=\"\/legacy_images\/mar2006\/images\/object-fig1.gif\" border=\"0\" alt=\"undefined\" hspace=\"0\" vspace=\"0\" width=\"335\" height=\"206\" \/><\/p>\n<p><strong>Figure 2.<\/strong> Decimator design requirements<\/p>\n<\/div>\n<p>With this in mind, and given the nature of high level synthesis, \twe decided instead to write a generic description of the filter and \tthe mixer using C++ classes and templates (Note that in this paper \twe discuss only the filter since it is used in most DSP algorithms. \tThe design procedures for the mixer were the same). This template \tcould then be used to create a specialized micro architecture for \teach particular application.<\/p>\n<p>The specialization was performed in two steps. \tFirst, we wrote the filter (or mixer) description \tin such a way that its size, bit width, storage type \t(floating, integer, complex etc.), and coefficients \twere C++ template parameters. Then we used \tthe architectural exploration capabilities of \tthe Catapult C Synthesis algorithmic synthesis \ttool from Mentor Graphics to tune hardware \tresources to the required performance of the \tfilter and the target technology into which the \tfilter was to be implemented.<\/p>\n<p>By following this design approach based \ton higher-level synthesis, we succeeded in \timplementing a large proportion of the RF \tmodulator based on a few lines of C++ code.<\/p>\n<h3>The basic building block:a programmable FIR template<\/h3>\n<p>As mentioned before, RF modulator building blocks contain an FIR \tfilter as a basic building block. A finite impulse response is essentially \ta DSP engine which, for every output sample, produces the dot \tproduct of a state vector times the filter coefficient vector. If N is the \tlength of the filter, the state vector is an array of the current and the \tprevious N-1 inputs presented to the filter. and the coefficient vector \tis the weight of each of the N inputs at the filter&rsquo;s output. The filter&rsquo;s \toutput is described by the following equation:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" id=\"||CPIMAGE:4075|\" src=\"\/legacy_images\/mar2006\/images\/object-inline.gif\" border=\"0\" alt=\"undefined\" hspace=\"0\" vspace=\"0\" width=\"140\" height=\"54\" \/><\/p>\n<p>where x is the input vector and c is the coefficient vector. \tIf infinite precision arithmetic were available, the function of the \tfilter &ndash; low-pass, high-pass, band-pass, or even complex &ndash; would \tbe uniquely determined by the length of the filter and the choice of \tcoefficients. Since all DSP designs have limited precision arithmetic \t(floating point has a very high dynamic range but it is still finite), \tother parameters &mdash; such as the bitwidths \tof the filter and the arithmetic \tin which the filter is implemented &mdash; \tmust be described to achieve the \tdesired quantization noise. \tConsequently, the filter, including its \tquantization noise, can be uniquely \tdefined with the following parameters:<\/p>\n<ul>\n<li> Filter length.<\/li>\n<li>Arithmetic used for the operations \t\t(fixed point, integer, floating \t\tpoint complex, etc).<\/li>\n<li> Precision (number of bits) used \t\tfor the arithmetic representation \t\tof the input, state vector, \t\tcoefficient vector and output.<\/li>\n<li> Value of the filter coefficients, \t\twhich may be programmable.<\/li>\n<li> Algorithm used to implement the \t\tdot product (slight differences \t\tin the coding style will produce \t\tdifferent implementations. e.g., \t\ta shift register versus a circular \t\tbuffer).<\/li>\n<\/ul>\n<p>The C++ template \tcan be used to describe the above \tmentioned parameters. In this template, \tthe length of the filter N is \tdescribed by the N_TAPS parameter.<\/p>\n<p><code> <\/code><\/p>\n<pre>template &lt;int N_TAPS,class I_CLASS,class C_CLASS,class<br \/>O_CLASS&gt;<br \/>class srr_fir_generic {<br \/>\tpublic:<br \/>\t\tsrr_fir_generic ();<br \/>\t\tsrr_fir_generic (C_CLASS initcoef[N_TAPS]);<br \/>\t\tvoid load(C_CLASS incoef[N_TAPS]);<br \/>\t\tO_CLASS exec(I_CLASS input);<br \/>\tprivate:<br \/>\tC_CLASS coef[N_TAPS];<br \/>\tI_CLASS regs[N_TAPS];<br \/>};<br \/><\/pre>\n<p>The arithmetic used in implementing \tthe filter is specified by the choice of \tinput, coefficient and output classes (I_CLASS, C_CLASS, \tand O_CLASS). The precision of the arithmetic operations is also \tspecified by the choice of input, coefficient and output classes. In \taddition, the value of the coefficients can be specified either at compile (synthesis) time by using the following constructor: \tsrr_fir_generic(C_CLASS initcoef [N_TAPS]).<\/p>\n<p>Or the coefficients can be programmed during execution by using \tthe load member function. Finally, the algorithm is coded in \tsuch a way that the filters can be implemented as shift registers \tplus adder trees when synthesized using Catapult C.<\/p>\n<div class=\"floatImageRight\" style=\"width: 344px;\"><img loading=\"lazy\" decoding=\"async\" id=\"||CPIMAGE:4068|\" src=\"\/legacy_images\/mar2006\/images\/object-fig2.gif\" border=\"0\" alt=\"undefined\" hspace=\"0\" vspace=\"0\" width=\"344\" height=\"223\" \/><\/p>\n<p><strong>Figure 3.<\/strong> Block diagram of a decimator<\/p>\n<\/div>\n<p>To determine if the template could be easily specialized for the \tmultiple functions in an RF modulator, the filter template was \tused in a variety of different DSP implementations: a decimator; \tan interpolator using a polyphase filter where the polyphase filter \tis also a template; and in two different versions of a baseband side \tband suppression filter &mdash; one using two &lsquo;real&rsquo; arithmetic filters \tand the second one using &lsquo;complex&rsquo; arithmetic.<\/p>\n<h3>Creating the Decimator<\/h3>\n<p>The bit widths for the filters and the \tcoefficients were estimated based on the \tdynamic range of the coefficient values \twhich uniquely determines the bit width \tof the coefficient vector as well as the \tgain of each individual filter. The \trequirements for the decimator are listed \tin Figure 2 and a schematic of the \tdecimator is shown in Figure 3 .<\/p>\n<p>The latency of the design was estimated \tbased on the ratio of the input sample \trate and the master clock. The C++ \tcode to implement such a decimator is \tvery straightforward.<\/p>\n<p><code> <\/code><\/p>\n<pre>#pragma hls_design top<br \/>sc_int &lt;OWORD2&gt; DECIMATOR_MODULE_NAME(sc_int&lt;IWORD1&gt; input[DECIMATION]) {<br \/>\tstatic sc_int &lt;CWORD12&gt; coefficients[NP1] = {<br \/>\t\t1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,<br \/>\t\t17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,<br \/>\t\t32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,<br \/>\t\t16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1<br \/>\t};<br \/>\t<br \/>\t\/\/ Both filters have the same coefficients.<br \/>\t\/\/ The input, coefficient and output bit widths of both filters are different.<br \/>\t<br \/>\tstatic srr_fir_generic&lt;NP1,sc_int&lt;IWORD1&gt;,sc_int&lt;CWORD12&gt;,sc_int&lt;OWORD1&gt; &gt;<br \/>\t\tfilter1(coefficients);<br \/>\tstatic srr_fir_generic&lt;NP1,sc_int&lt;IWORD2&gt;,sc_int&lt;CWORD12&gt;,sc_int&lt;OWORD2&gt; &gt;<br \/>\t\tfilter2(coefficients);<br \/>\t<br \/>\tsc_int &lt;OWORD1&gt; result1;<br \/>\tsc_int &lt;OWORD2&gt; result2;<br \/>\t<br \/>\tconst int dec = DECIMATION;<br \/>\tconst int mask = DECIMATION \/ 2 - 1; \/\/ Works only for powers of two careful<br \/>\t<br \/>\tint i;<br \/>\tint test;<br \/>\t<br \/>\tfor (i=0;i&lt;dec;i++) {<br \/>\t\tresult1 = filter1.exec(input[i]); \/\/ This is executed at the input rate.<br \/>\t\ttest = i &amp; mask;<br \/>\t\tif( !test ) { \/\/ This is executed at i = 0 and 32.<br \/>\t\t\/\/ The sample rate for this filter is 1\/32 of the input rate<br \/>\t\tresult2 = filter2.exec(result1);<br \/>\t\t}<br \/>\t}<br \/>\t<br \/>\t\/\/ This is executed at the output rate.<br \/>\treturn result2;<br \/>} \/\/ fourth_order_decimator<br \/><\/pre>\n<p>There are several interesting aspects to \tthis block of code. First, notice that the \tdecimator returns an output of type \tsc_int (SystemC integer arithmetic) \tof width OWORD2 where OWORD2 \tis defined as 22 as per the decimator \tspecification.<\/p>\n<p>Second, the input of the decimator is \tan array of DECIMATION words of \tCWORD12 bits. DECIMATION and \tCWORD12 are declared as 64 and 7 as \tper the filter specification. This array will \tbe turned into an input stream (an array \tin time) during high level synthesis.<\/p>\n<p>Third, two instances of the previously created filter class are \tdeclared. The number of taps, as well as the types of the input, \tcoefficient and outputs are declared in a manner consistent with \tthe specification.<\/p>\n<p>Fourth and finally, the body of the decimator is a loop which \texecutes the first filter for each input sample and the second filter \tevery 32 samples as per the specification. This loop defines the \touter control loop of the synthesized hardware. At the end of this \tloop, a single value, the decimated value, is returned.<\/p>\n<div class=\"floatImage\" style=\"width: 326px;\"><img loading=\"lazy\" decoding=\"async\" id=\"||CPIMAGE:4069|\" src=\"\/legacy_images\/mar2006\/images\/object-fig3.gif\" border=\"0\" alt=\"undefined\" hspace=\"0\" vspace=\"0\" width=\"326\" height=\"171\" \/><\/p>\n<p><strong>Figure 5.<\/strong> Analysis of the different decimator solutions automatically generated from the same C++ source code<\/p>\n<\/div>\n<p>The above described code was synthesized using Catapult C. The \tfilter loops were parallelized to meet the latency requirements \tof the decimator. Figure 5 shows the results for different micro \tarchitectures that were synthesized using an FPGA as the target.<\/p>\n<p>The smallest synthesized hardware with a latency of less than 2272 \tclock cycles was chosen after a variety of different architectures \twere explored. The RTL for all of the explored architectures was \tgenerated in a matter of hours rather than weeks.Without C synthesis, \tit would have taken weeks to hand write the RTL for each.<\/p>\n<h3>Interpolator Design<\/h3>\n<p>Once we had created the FIR filter, the next task was to use the \tsame C++ source code to create an interpolator design. An interpolator \tusing similar low pass FIR filters could have been very \teasily written with slight modification of the C++. However, to \tshow how easy it is to re-use a template in the object-oriented \tdesign paradigm, we wrote an interpolator using a polyphase filter.<\/p>\n<p>Use of polyphase filters for an interpolator design is more efficient \tcomputationally than a straightforward implementation of a \tdecimator since computations with the interpolated zeroes are \tnot performed. Essentially, a polyphase filter is built as an array of \tsmaller filters, where the linear dimension of the array is the interpolation \tfactor of the polyphase interpolator: e.g., an interpolator \twith an interpolation ratio of eight where the implemented low pass \tFIR has 64 taps is implemented as an array of eight low pass filters, \teach of them containing 64 taps. To show how the filter class could \tbe re-used, we implemented a polyphase template using an array \tof(N_PHASES) filters as its storage type.<\/p>\n<p>&nbsp;<\/p>\n<pre>template &lt;int N_TAPS,int N_PHASES,class I_CLASS,class C_CLASS,class O_CLASS&gt;<br \/>class srr_fir_polyphase_fir {<br \/>\tpublic:<br \/>\t\tsrr_fir_polyphase_fir ();<br \/>\t\tsrr_fir_polyphase_fir (C_CLASS initcoef[N_PHASES * N_TAPS]);<br \/>\t\tvoid load(C_CLASS incoef[N_PHASES * N_TAPS]);<br \/>\t\tO_CLASS exec(I_CLASS input);<br \/>\t\t<br \/>private:<br \/>\tint state;<br \/>\tsrr_fir_generic&lt;N_TAPS,I_CLASS,C_CLASS,O_CLASS&gt; filter_array[N_PHASES];<br \/>};<br \/><\/pre>\n<p>From this C++ code, it can be clearly seen that, with exception \tof the number of phases (N_PHASES), the parameters of a \tpolyphase filter are identical to the parameters of an ordinary \tFIR filter. Additionally, it can be seen in the private section of \tthe polyphase filter that the storage elements of the polyphase \tclass consists of an array of the finite impulse response filters as \tdefined in the srr_fir_generic template.<\/p>\n<p>When executed the polyphase filter runs one of the FIR phases \tcorresponding to the state of the filter and changes the state of the \tpolyphase filter to the next phase as shown below. \tOnce the polyphase filter class was defined, we wrote a wrapper \tinterpolator function which instantiated two eight-phase polyphase \tfilters which in turn created an interpolation rate of 64. The design \tof this function is much like the interpolator design.<\/p>\n<p>&nbsp;<\/p>\n<pre>O_CLASS srr_fir_polyphase_fir&lt;N_TAPS,N_PHASES,I_CLASS,C_CLASS,O_CLASS&gt;::exec(I<br \/>_CLASS input) {<br \/>\tint i;<br \/>\t<br \/>\tO_CLASS result;<br \/>\t<br \/>\tresult = filter_array[state++].exec(input);<br \/>\tif (state == N_PHASES) {<br \/>\t\tstate = 0;<br \/>\t}<br \/>\t<br \/>\treturn result;<br \/>}<br \/>\/\/ srr_fir_polyphase_fir<br \/><\/pre>\n<h3>Complex Arithmetic Filter<\/h3>\n<div class=\"floatImageRight\" style=\"width: 325px;\"><img loading=\"lazy\" decoding=\"async\" id=\"||CPIMAGE:4070|\" src=\"\/legacy_images\/mar2006\/images\/object-fig4.gif\" border=\"0\" alt=\"undefined\" hspace=\"0\" vspace=\"0\" width=\"325\" height=\"170\" \/><\/p>\n<p><strong>Figure 8.<\/strong> Characteristics of the complex arithmetic filter<\/p>\n<\/div>\n<p>So far, we have only described filter-based designs which work \twith integer or fixed point arithmetic. That might lead one to \tbelieve that we are talking of a very restrictive design style. The \tfollowing example will show that this style is in fact very flexible. \tOne of the architectures considered for the RF modulator that \tmotivated this work was to perform the side band suppression at \tthe baseband using complex arithmetic rather than using a band \tpass filter at the carrier frequency. Such an architecture requires a \tfilter that has a much lower sample rate than a filter in the carrier \tfrequency band. To demonstrate the power of this methodology, \twe chose not to implement the complex arithmetic filter as two \treal arithmetic filters. Instead, we wrote a template which described \tthe basic operations between complex numbers and between &lsquo;real&rsquo; \tand complex numbers, where the &lsquo;real&rsquo; numbers are not necessarily \tfloating point numbers, as in traditional programming, but are \tthe storage class defined in the complex template.<\/p>\n<p>By doing this, a complex class composed of two SystemC or integer \tnumbers could be defined. This class implements fixed point \tcomplex arithmetic which can be used to implement the desired \tfilter. The following lines of code show a complex arithmetic filter \tusing 16 bit SystemC (sc_fixed) arithmetic:<\/p>\n<pre>static srr_fir_generic<br \/>&lt;64,sc_fixed&lt;16,2&gt;, srr_complex&lt;sc_fixed&lt;16,2&gt;&gt;,<br \/>\t                  srr_complex&lt;sc_fixed&lt;16,2&gt;&gt; filter;<br \/><\/pre>\n<p>This specialization defines the following characteristics for the \tfilter shown in Figure 8. The complex arithmetic filter was \tsynthesized and simulated using both floating point and SystemC \tarithmetic. Figure 9 shows how one of the side bands of a 500Hz \ttest tone was effectively eliminated.<\/p>\n<div class=\"floatImage\" style=\"width: 326px;\"><img loading=\"lazy\" decoding=\"async\" id=\"||CPIMAGE:4071|\" src=\"\/legacy_images\/mar2006\/images\/object-fig5.gif\" border=\"0\" alt=\"undefined\" hspace=\"0\" vspace=\"0\" width=\"326\" height=\"220\" \/><\/p>\n<p><strong>Figure 9.<\/strong> Simulation result of a complex arithmetic filter<\/p>\n<\/div>\n<h3>Conclusion<\/h3>\n<p>We have presented three completely different designs based on a \tsingle FIR class. To promote design re-use, various DSP blocks \twere designed from the same base code. A filter template was first \twritten in C++. This template was then re-used in various digital \tdesigns such as a decimator, an interpolator, and the baseband \tfilter of a single sideband modulator.<\/p>\n<p>By re-using the FIR filter design in different contexts, large \tproductivity increases are now possible eliminating days of RTL \thand coding for each of the individual designs. The design \tprocess for each one of these blocks was performed in a matter \tof hours rather than weeks when compared with traditional RTL \tdesign techniques.<\/p>\n<h3>References<\/h3>\n<ol>\n<li> Stroustrup, Bjarne. The C++ programming language. \t\tAddisson-Wesley. 2000.<\/li>\n<li> Elliot, Douglas. Editor. Handbook of Digital Signal Processing \t\tApplications. Academic Press. 1987.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>For years, ASIC and FPGA designers have shared the goal of having totally reusable intellectual property (IP) blocks. This goal has been partially fulfilled, with the introduction of high-level hardware description languages such as VHDL and Verilog, and powerful Register Transfer Level (RTL) synthesis tools in the late 1980s and early 1990s. However, with a [&hellip;]<\/p>\n","protected":false},"author":174,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41,8],"tags":[],"coauthors":[73],"class_list":["post-37","post","type-post","status-publish","format-standard","hentry","category-esl-codesign","category-march-2006"],"_links":{"self":[{"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/posts\/37","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/users\/174"}],"replies":[{"embeddable":true,"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/comments?post=37"}],"version-history":[{"count":0,"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/posts\/37\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/media?parent=37"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/categories?post=37"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/tags?post=37"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.techdesignforums.com\/practice\/wp-json\/wp\/v2\/coauthors?post=37"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}