在C/C++算法設(shè)計(jì)中使用任意位寬
開(kāi)發(fā)定點(diǎn)(fixed-point)算法時(shí),通常需要在設(shè)計(jì)功能性、數(shù)字精度建模、及驗(yàn)證(仿真)速度之間取得一個(gè)平衡?,F(xiàn)在,一種新的數(shù)據(jù)類(lèi)可使此過(guò)程簡(jiǎn)單化,由此得到更簡(jiǎn)單精確的建模精度、更好的數(shù)字求精、及更快的驗(yàn)證周期,而ANSI C/C++正是開(kāi)發(fā)這種數(shù)字求精算法的最佳語(yǔ)言。
某此算法天生就適用于操作整數(shù),或那些理想中的實(shí)數(shù)(如數(shù)字濾波器的系數(shù)),它們也可能會(huì)使用浮點(diǎn)或定點(diǎn)類(lèi)型。一般而言,在算法開(kāi)發(fā)的早期階段,會(huì)經(jīng)常用到C語(yǔ)言的float或double浮點(diǎn)類(lèi)型,因?yàn)樗鼈兛商峁┮粋€(gè)非常大的動(dòng)態(tài)數(shù)據(jù)范圍,且對(duì)大多數(shù)程序來(lái)說(shuō)都是適用的。
使用C內(nèi)置的float類(lèi)型來(lái)建模一個(gè)FIR濾波器
算法可進(jìn)行數(shù)字求精,以便使用定點(diǎn)算術(shù)來(lái)降低最終硬件或軟件實(shí)現(xiàn)的復(fù)雜性。在硬件方面,將整數(shù)或定點(diǎn)算術(shù)限制為最小位寬,可在本質(zhì)上滿(mǎn)足性能、空間、能耗的需要;如果實(shí)現(xiàn)中用到了DSP處理器,那么把算法限制為整數(shù)或定點(diǎn)算術(shù),就可為特定程序使用盡可能便宜的處理器。
定點(diǎn)算術(shù)的建模可通過(guò)C語(yǔ)言?xún)?nèi)置的浮點(diǎn)或整數(shù)類(lèi)型來(lái)完成,這做的話(huà),需要顯式編碼并受限于C中浮點(diǎn)數(shù)及整數(shù)可表示的最大數(shù):64位整數(shù)或53位尾數(shù);這些都會(huì)給操作數(shù)的位寬帶來(lái)更多的限制,例如,2個(gè)33位的數(shù)相乘,會(huì)超過(guò)64位C整數(shù)可表示的范圍。圖2演示了一個(gè)FIR濾波器的例子,但temp變量限制為15位的定點(diǎn)精度,其中10位用于整數(shù)位。在這個(gè)實(shí)現(xiàn)中,LSB的右部位被舍棄(量化模型的截?cái)?,而MSB的左部位也被舍棄(包裝的溢出模型),應(yīng)該意識(shí)到,使用float(或double)的模型在精度上是受限的,且不能再次合成(synthesis)。同樣,由于有取整模型的嚴(yán)格位精度定義有先,又由于內(nèi)置浮點(diǎn)類(lèi)型的取整將會(huì)先被應(yīng)用,所以對(duì)除法這樣的操作來(lái)說(shuō),就非常難實(shí)現(xiàn)了。
使用float建模定點(diǎn)行為
當(dāng)許多算法都能依賴(lài)本地C數(shù)據(jù)類(lèi)型的精度來(lái)編寫(xiě)時(shí),對(duì)支持任意長(zhǎng)度的整數(shù)及定點(diǎn)算法,大家就會(huì)抱有極大的期望,而硬件描述語(yǔ)言(HDL)如VHDL,走的也是同一條路。隨著C/C++越來(lái)越多地被用于高級(jí)合成與驗(yàn)證工具(High-Level Synthesis and Verification tools),也證明了這種語(yǔ)言本質(zhì)上有一個(gè)足以滿(mǎn)足當(dāng)前及未來(lái)程序需要的數(shù)據(jù)類(lèi)型庫(kù)。任意長(zhǎng)度類(lèi)型的支持,也可使數(shù)據(jù)類(lèi)型的行為有一個(gè)統(tǒng)一的定義,而統(tǒng)一的語(yǔ)義則避免了人工實(shí)現(xiàn)上的一些限制。
算法C數(shù)據(jù)類(lèi)型
算法C數(shù)據(jù)類(lèi)型是一種基于類(lèi)的C++庫(kù),其實(shí)現(xiàn)了任意長(zhǎng)度的整數(shù)及定點(diǎn)類(lèi)型,而這些可自由訪(fǎng)問(wèn)的類(lèi)型有一系列好處,包括統(tǒng)一及良好定義的語(yǔ)義,還有媲美C/C++內(nèi)置數(shù)據(jù)類(lèi)型的運(yùn)行時(shí)速度,對(duì)比SystemC中相應(yīng)的類(lèi)型,其運(yùn)行速度也超過(guò)10倍以上。這些數(shù)據(jù)類(lèi)型能用于任何符合C++或SystemC規(guī)范標(biāo)準(zhǔn)的程序中,并擁有高度可合成的語(yǔ)義。
語(yǔ)義
語(yǔ)義的統(tǒng)一性與一致性是避免在算法中,發(fā)生功能性錯(cuò)誤的關(guān)鍵,以下的例子,也說(shuō)明了這點(diǎn):
眾所周知,變量ActLength的范圍為1至255,萬(wàn)一編譯器的合成不知道其范圍,就不能進(jìn)行相應(yīng)的優(yōu)化,它的聲明就會(huì)從int變?yōu)楦鼑?yán)格的sc_uint<8>類(lèi)型;雖然合成會(huì)得到更好的結(jié)果,但設(shè)計(jì)就仿真得不正確了。在經(jīng)過(guò)一番調(diào)試之后,找到了問(wèn)題的源頭:在比較表達(dá)式k >= ActLength中,兩個(gè)操作數(shù)變成了一個(gè)signed int與一個(gè)unsigned long long(為64位無(wú)符號(hào)整數(shù),其是sc_uint類(lèi)型的基類(lèi)型)之間的比較。對(duì)此的解釋是:C/C++整數(shù)提升規(guī)則指定了在進(jìn)行比較之前,會(huì)把操作數(shù)int提升為一個(gè)unsigned long long,例如,如果k的值為 -1,在提升為unsigned long long之后,它會(huì)變成2^64 – 1。
像這樣語(yǔ)義中的問(wèn)題一般會(huì)非常難以察覺(jué),且是與位寬相關(guān)的,例如,可能有人想擴(kuò)大某個(gè)現(xiàn)有算法的位寬,只有看到結(jié)果時(shí),才知道是行不通的;這個(gè)問(wèn)題也可能是與特定平臺(tái)相關(guān)的,例如,對(duì)1 << 32(兩個(gè)操作數(shù)都是int類(lèi)型,結(jié)果也是int類(lèi)型)大家期望返回0,但在大多數(shù)平臺(tái)(或編譯器)上,它都會(huì)返回1(沒(méi)有移位,只因?yàn)榈诙€(gè)操作數(shù)較低的五位被計(jì)算進(jìn)來(lái)了);當(dāng)?shù)谝粋€(gè)操作數(shù)是一個(gè)64位整數(shù)時(shí),平臺(tái)依賴(lài)性會(huì)表現(xiàn)得更加明顯及頻繁。主要的問(wèn)題是C/C++標(biāo)準(zhǔn)沒(méi)有指定在32位整數(shù)情況下移位值(第二個(gè)操作數(shù))超出0至31范圍、或在64位整數(shù)情況下移位值超出0至63范圍時(shí)的行為。不幸的是,像sc_int、sc_uint這樣的數(shù)據(jù)類(lèi)型也不能為用戶(hù)避免這類(lèi)平臺(tái)依賴(lài)性的問(wèn)題。
算法C數(shù)據(jù)類(lèi)型被設(shè)計(jì)用于提供統(tǒng)一且一致的語(yǔ)義,因此,它們是可預(yù)測(cè)的,例如,對(duì)有符號(hào)數(shù)混用一個(gè)無(wú)符號(hào)操作數(shù)仍會(huì)產(chǎn)生期望的結(jié)果;這些類(lèi)型的長(zhǎng)度不受限制,所以就不存在所謂的精度問(wèn)題。所有的操作——包括移位和除法——都有完整且一致性的定義,混合不同的類(lèi)型也能得到期望的結(jié)果,如,當(dāng)x為一個(gè)C內(nèi)置類(lèi)型,而y是一個(gè)算法C類(lèi)型時(shí),表達(dá)式x+y和y+x均能返回相同的結(jié)果。
運(yùn)行時(shí)間
我們的目的是為了在支持任意長(zhǎng)度類(lèi)型及避免用戶(hù)碰到前述語(yǔ)義問(wèn)題的前提下,得到使用內(nèi)置類(lèi)型(位寬不超過(guò)64位)手工C/C++編碼優(yōu)化過(guò)的運(yùn)行時(shí)間。算法C類(lèi)型是為快速執(zhí)行及易于合成的語(yǔ)義而設(shè)計(jì)及實(shí)現(xiàn)的,所有操作的位寬由C++編譯器靜態(tài)確定,這就避免了動(dòng)態(tài)內(nèi)存分配,減少了運(yùn)行時(shí)間,也使得語(yǔ)義更加易于合成。另外,實(shí)現(xiàn)也為速度進(jìn)行了優(yōu)化,因此可能會(huì)調(diào)用更多的專(zhuān)用及高效代碼,充分利用了當(dāng)今編譯器的優(yōu)化特性。
表1:規(guī)格化為ac_fixed的運(yùn)行時(shí)間比較
表1是當(dāng)定點(diǎn)算術(shù)用算法C定點(diǎn)類(lèi)型ac_fixed來(lái)建模時(shí),各種不同的運(yùn)行時(shí)比較;float的實(shí)現(xiàn)在圖2中,sc_fixed_fast為SystemC中精度受限的定點(diǎn)數(shù)據(jù)類(lèi)型,sc_fixed為任意精度的定點(diǎn)類(lèi)型。實(shí)際中對(duì)FIR濾波器進(jìn)行10^8次調(diào)用,TRN/WRAP的運(yùn)行時(shí)間為6.5秒,RND/SAT為29秒。其他類(lèi)型的運(yùn)行時(shí)間也能從這張表中依次推出,如sc_fixed TRN/WRAP將花費(fèi)6.5s × 227 = 1476s(將近25分鐘)。作為參考,圖1中的算法(使用無(wú)定點(diǎn)建模的float)花費(fèi)時(shí)間為3.5s(比起使用定點(diǎn)建模的ac_fixed,慢了近兩倍)。
上述的運(yùn)行時(shí)間數(shù)據(jù),均由GCC 4.1.1測(cè)量得來(lái),而在之前版本的GCC或Visual C++ 2005中得到的數(shù)據(jù)大致接近。
另外,運(yùn)行時(shí)間也能通過(guò)整型數(shù)據(jù)類(lèi)型或位操作進(jìn)一步縮短。表2為一個(gè)DCT算法的相應(yīng)結(jié)果,它由一個(gè)每次讀寫(xiě)2位的移位操作得來(lái),與此對(duì)比的運(yùn)行時(shí)間為SystemC精度受限的sc_int與任意長(zhǎng)度的sc_bigint。
結(jié)論
基于通用標(biāo)準(zhǔn)ANSI C++,這種新的整數(shù)與定點(diǎn)算法C類(lèi)型允許算法及系統(tǒng)設(shè)計(jì)者指定任意位寬,從而提供比傳統(tǒng)數(shù)據(jù)類(lèi)型高200倍的仿真效率。這些新數(shù)據(jù)類(lèi)型可成為C-to-RTL設(shè)計(jì)鏈中非常有價(jià)值的一環(huán),及在整個(gè)實(shí)現(xiàn)流程中保證了任意位寬的精度。
【編輯推薦】