到實(shí)戰(zhàn))
做FPGA上的除法和做乘法真的不是一回事。乘法有DSP硬核一拍就能拿到結(jié)果除法呢你一拍、兩拍、三四拍都未必能算完而且綜合出來(lái)動(dòng)不動(dòng)就是一片LUT。我之前在一個(gè)圖像縮放項(xiàng)目里需要把像素坐標(biāo)做歸一化處理隨手寫(xiě)了一個(gè)組合邏輯除法器結(jié)果一跑實(shí)現(xiàn)LUT直接爆掉時(shí)序報(bào)告里飄紅一片。后來(lái)老老實(shí)實(shí)改用Vivado里的Divider Generator IP從Radix2到Fractional模式挨個(gè)試了一圈才把整個(gè)配置鏈路吃透。這篇文章就把我實(shí)際踩過(guò)坑之后總結(jié)的配置思路、原理細(xì)節(jié)和調(diào)試技巧完整寫(xiě)出來(lái)如果你也在用Vivado做除法運(yùn)算并且正被IP核的各個(gè)參數(shù)搞得頭暈?zāi)沁@篇應(yīng)該能幫你省下不少時(shí)間。先說(shuō)清楚這個(gè)IP能干什么Divider Generator IP是Xilinx官方提供的除法器生成器只需要配置好被除數(shù)與除數(shù)的位寬、有符號(hào)還是無(wú)符號(hào)、采用哪種除法算法以及輸出余數(shù)還是小數(shù)它就能自動(dòng)生成一個(gè)時(shí)序收斂、面積可控的除法器模塊。整個(gè)過(guò)程不需要你手工設(shè)計(jì)任何除法邏輯也避開(kāi)了組合邏輯除法器的時(shí)序?yàn)?zāi)難。適合的人至少有以下幾類(lèi)正在做定點(diǎn)運(yùn)算的算法工程師、需要用坐標(biāo)變換或比例運(yùn)算的FPGA開(kāi)發(fā)者、以及所有在Vivado里被除法器時(shí)序問(wèn)題折磨過(guò)的同學(xué)。1. 為什么不用組合邏輯除法而是用IP核1.1 組合邏輯與IP核的本質(zhì)差別先用一句話(huà)把問(wèn)題點(diǎn)透FPGA上的除法不是一個(gè)“一拍算完”的操作。加法器和乘法器都有專(zhuān)用硬件資源除法則沒(méi)有對(duì)應(yīng)的DSP硬核它本質(zhì)上是一個(gè)迭代過(guò)程每算出一位商都要做一次減法、移位和比較所以天然需要消耗多個(gè)時(shí)鐘周期。如果你用組合邏輯硬寫(xiě)這串迭代邏輯會(huì)被展開(kāi)成一條極長(zhǎng)的組合鏈路路徑延遲會(huì)隨著被除數(shù)位寬線性增長(zhǎng)跑到100MHz以上通常就開(kāi)始時(shí)序違例。我自己用Verilog寫(xiě)過(guò)16bit除以8bit的組合除法器綜合后在Artix-7上最好的結(jié)果也只有大概87MHz而且LUT占用高得離譜。換用Divider Generator IP的Radix2模式同樣的位寬自動(dòng)生成PPA功耗、性能、面積均衡的電路運(yùn)行到150MHz一點(diǎn)問(wèn)題都沒(méi)有LUT消耗反而下降了一大截。這才理解為什么官方IP核值得優(yōu)先選擇因?yàn)樗鼉?nèi)部使用了移位減法結(jié)構(gòu)和流水線寄存器的合理排布把迭代過(guò)程分布到多個(gè)周期里從根上把時(shí)序問(wèn)題解決了。1.2 Divider Generator IP能替你解決哪些事這個(gè)IP核幫你封裝的東西遠(yuǎn)不止“除法”這一步。第一它處理了輸入數(shù)據(jù)的符號(hào)擴(kuò)展和位寬對(duì)齊尤其是在有符號(hào)模式下負(fù)數(shù)的二進(jìn)制補(bǔ)碼處理如果手工寫(xiě)很容易出錯(cuò)第二它自動(dòng)加入了合適的流水線級(jí)數(shù)你只需要在配置界面里選擇一個(gè)Latency總周期數(shù)內(nèi)部每一級(jí)寄存器的位置都由Xilinx幫你排好第三它還提供了AXI4-Stream接口的封裝版本帶tvalid/tready握手信號(hào)可以在數(shù)據(jù)流系統(tǒng)中直接接入省去了一大堆跨模塊同步邏輯。更重要的是這個(gè)IP在面對(duì)“被零除”或是“運(yùn)算中間產(chǎn)生溢出”這類(lèi)異常情況時(shí)輸出行為是確定的、可預(yù)測(cè)的。相比自己寫(xiě)的除法邏輯這些邊緣情況其實(shí)是最容易翻車(chē)的點(diǎn)而IP核已經(jīng)在硬件上做了專(zhuān)門(mén)定義?;谶@些原因我后來(lái)的項(xiàng)目里凡是出現(xiàn)除法的地方一律走IP核不再手搓。2. 打開(kāi)配置界面之前先想清楚三件事2.1 算法類(lèi)型Radix2還是High RadixVivado的Divider Generator IP在“Algorithm Type”一欄提供了多個(gè)選項(xiàng)坐標(biāo)上一般分成Radix2和High Radix兩大陣營(yíng)。Radix2是最傳統(tǒng)的逐位除法算法每次迭代只會(huì)計(jì)算出1bit的商實(shí)現(xiàn)簡(jiǎn)單資源占用少但延遲周期數(shù)偏大High Radix則包括Radix4、Radix8、Radix16一次迭代能算出2bit、3bit或4bit商延遲會(huì)縮短但代價(jià)是內(nèi)部查找表和判斷邏輯變多面積上升。實(shí)際選型時(shí)怎么權(quán)衡我的經(jīng)驗(yàn)是如果被除數(shù)位寬在16bit以?xún)?nèi)Radix2完全夠用延遲差那么幾個(gè)周期對(duì)整體系統(tǒng)影響不大如果被除數(shù)達(dá)到32bit甚至更高同時(shí)系統(tǒng)對(duì)延遲敏感那就毫不猶豫選High Radix的高基數(shù)模式。還有一個(gè)補(bǔ)充角度——資源緊張的項(xiàng)目?jī)?yōu)先Radix2速度敏感的項(xiàng)目?jī)?yōu)先Radix4以上。2.2 數(shù)據(jù)格式有符號(hào)還是無(wú)符號(hào)這里的“有符號(hào)”和“無(wú)符號(hào)”直接決定IP內(nèi)部使用原碼還是補(bǔ)碼運(yùn)算。無(wú)符號(hào)場(chǎng)景最簡(jiǎn)單所有輸入輸出都按二進(jìn)制正整數(shù)處理有符號(hào)場(chǎng)景下被除數(shù)和除數(shù)都以二進(jìn)制補(bǔ)碼形式進(jìn)入輸出商也是補(bǔ)碼。最容易踩坑的是位寬擴(kuò)展。無(wú)符號(hào)模式下輸入位寬就是你配置的位寬有符號(hào)模式下為了保留符號(hào)位被除數(shù)通常需要在實(shí)際數(shù)據(jù)位寬基礎(chǔ)上額外增加一位符號(hào)位。比如你要做的是兩個(gè)16bit有符號(hào)數(shù)相除配置界面里的Dividend Width最好填17而不是16否則計(jì)算結(jié)果很容易在正負(fù)邊界上出錯(cuò)。這個(gè)點(diǎn)很多人都會(huì)忽略我一開(kāi)始就直接用了16bit結(jié)果發(fā)現(xiàn)負(fù)數(shù)除法結(jié)果全部不對(duì)后來(lái)查手冊(cè)才明白是符號(hào)位處理的問(wèn)題。2.3 輸出形式余數(shù)還是小數(shù)用過(guò)C語(yǔ)言取模的都知道整數(shù)除法帶一個(gè)余數(shù)。在FPGA的除法器里你可以選擇把余數(shù)作為輸出Remainder模式也可以選擇輸出帶小數(shù)位的結(jié)果Fractional模式兩者只能選一個(gè)。Remainder模式的輸出由兩個(gè)字段組成商和余數(shù)。商取整余數(shù)同符號(hào)這在做取模運(yùn)算、循環(huán)隊(duì)列索引、校驗(yàn)算法時(shí)非常有用。Fractional模式則會(huì)把余數(shù)繼續(xù)算下去輸出一個(gè)帶有小數(shù)位寬的定點(diǎn)數(shù)適用于PID控制、坐標(biāo)歸一化、比例系數(shù)計(jì)算等場(chǎng)景。一個(gè)小提醒如果你只要一個(gè)浮點(diǎn)小數(shù)的整數(shù)近似不想輸出余數(shù)Fractional模式比Remainder模式更符合直覺(jué)因?yàn)楹罄m(xù)不需要再做任何余數(shù)換算。3. Radix2模式配置實(shí)戰(zhàn)從界面參數(shù)到例化驗(yàn)證3.1 界面入口與核心參數(shù)逐項(xiàng)拆解在Vivado里打開(kāi)IP Catalog搜索“Divider Generator”即可找到。雙擊進(jìn)入配置界面后建議把“Show Disabled Ports”勾上這樣能看到所有可選端口方便后續(xù)連接。界面上第一頁(yè)關(guān)心的是這幾個(gè)參數(shù)。Component NameIP核在工程里的實(shí)例名建議起一個(gè)能看懂的名字比如divider_u16_s16后面引用時(shí)找起來(lái)方便。Algorithm Type選擇Radix2。Divisor Width除數(shù)的位寬填實(shí)際輸入位寬即可注意有符號(hào)時(shí)要包含符號(hào)位。Dividend Width被除數(shù)的位寬有符號(hào)場(chǎng)景下記得加符號(hào)位。Remainder Type選擇Remainder這里控制輸出的是余數(shù)而非小數(shù)。Remainder Fractional Width只在Fractional模式時(shí)生效Remainder模式下是置灰狀態(tài)。Signed or Unsigned下拉選擇是否帶符號(hào)。這些參數(shù)全部設(shè)置好以后界面上會(huì)立即計(jì)算出一個(gè)Latency值。Radix2模式下這個(gè)值不是隨便生成的它大概等于內(nèi)部迭代級(jí)數(shù)加上輸入輸出寄存器的級(jí)數(shù)你可以把它理解為從輸入有效到輸出有效之間的固定時(shí)鐘周期數(shù)。拿到這個(gè)數(shù)值后后續(xù)寫(xiě)代碼做握手等待時(shí)直接引用即可。3.2 延遲周期的計(jì)算邏輯關(guān)于Latency這個(gè)參數(shù)我想多說(shuō)幾句因?yàn)楹芏嗳嗽栽谶@里。Radix2除法器的Latency不完全等于被除數(shù)位寬它還包含取整、符號(hào)擴(kuò)展以及流水線輸出階段帶來(lái)的額外周期。Xilinx官方給出的計(jì)算公式大概思路是基本迭代周期取決于除數(shù)和被除數(shù)的相對(duì)位寬關(guān)系再加上輸入級(jí)和輸出級(jí)各若干拍。如果配置界面選擇“Automatic”工具會(huì)給出一個(gè)針對(duì)當(dāng)前參數(shù)優(yōu)化后的周期數(shù)如果選擇“Manual”也可以手工加大延時(shí)代價(jià)是增加寄存器資源。實(shí)操中我一般直接采用Automatic生成的Latency值在驗(yàn)證平臺(tái)上用計(jì)數(shù)器等待這個(gè)值之后再去采樣輸出數(shù)據(jù)。如果發(fā)現(xiàn)采樣點(diǎn)不對(duì)再往回倒退查數(shù)據(jù)對(duì)齊。手動(dòng)調(diào)大延遲通常只在timing緊張插流水線寄存器后需要對(duì)齊路徑時(shí)才用得到。3.3 例化模板與Verilog連接方式配置完成后IP核會(huì)在工程里生成一個(gè)例化模板。右鍵IP核選擇“Open IP Example Design”官方會(huì)生成一個(gè)完整的測(cè)試工程。這里我貼一段精簡(jiǎn)版的例化代碼方便理解信號(hào)連接關(guān)系我是按AXI4-Stream接口方式使用的divider_u16_s16 u_divider ( .aclk (clk ), // 輸入時(shí)鐘 .s_axis_dividend_tvalid (dividend_valid ), // 被除數(shù)有效 .s_axis_dividend_tdata (dividend_data ), // 被除數(shù)數(shù)據(jù) .s_axis_divisor_tvalid (divisor_valid ), // 除數(shù)有效 .s_axis_divisor_tdata (divisor_data ), // 除數(shù)數(shù)據(jù) .m_axis_dout_tvalid (result_valid ), // 輸出有效 .m_axis_dout_tdata (result_data ) // 商與余數(shù)拼接輸出 );需要注意AXI4-Stream接口下輸出總線m_axis_dout_tdata里通常同時(shí)打包了商和余數(shù)具體的位段劃分規(guī)則會(huì)隨IP版本不同略有差異最穩(wěn)妥的做法是查看IP核生成的例化文件里注釋中的位段說(shuō)明或者打開(kāi)仿真波形對(duì)照輸入輸出做一次對(duì)齊確認(rèn)。我第一次用的時(shí)候默認(rèn)商是低字節(jié)余數(shù)在高字節(jié)結(jié)果反了折騰了一個(gè)下午。3.4 仿真測(cè)試把Radix2模式的邊界情況全測(cè)一遍寫(xiě)測(cè)試平臺(tái)時(shí)我建議至少覆蓋這些測(cè)試向量同號(hào)正數(shù)相除、同號(hào)負(fù)數(shù)相除、異號(hào)相除、最大正數(shù)除以1、最小負(fù)數(shù)除以1、任意數(shù)除以自身以及除數(shù)為0的情況。除數(shù)為0時(shí)輸出結(jié)果會(huì)有明確行為有的版本會(huì)拉高一個(gè)division_by_zero標(biāo)志有的版本則將商置為全1。知道這個(gè)行為后后續(xù)在代碼里做異常保護(hù)就簡(jiǎn)單得多。測(cè)試平臺(tái)上我習(xí)慣用一個(gè)計(jì)數(shù)器從拉高輸入有效信號(hào)開(kāi)始計(jì)數(shù)計(jì)數(shù)到Latency值時(shí)檢查輸出有效信號(hào)。如果tvalid為高則讀回?cái)?shù)據(jù)否則報(bào)錯(cuò)。整個(gè)過(guò)程用$display打印關(guān)鍵數(shù)據(jù)方便追蹤。實(shí)測(cè)下來(lái)Radix2模式的輸出與C語(yǔ)言整數(shù)除法結(jié)果完全一致只要位寬配置正確誤差為零。4. Fractional模式深度解析輸出小數(shù)位的關(guān)鍵配置4.1 為什么需要Fractional模式很多算法場(chǎng)景里除法的結(jié)果不希望被截?cái)喑烧麛?shù)比如PID控制器里的誤差比例項(xiàng)、圖像處理里的歸一化坐標(biāo)、電機(jī)控制里的占空比換算。這些場(chǎng)景如果只保留整數(shù)部分整個(gè)控制精度會(huì)大打折扣。Radix2或High Radix配合Remainder模式雖然能拿到余數(shù)但余數(shù)還要你自己換算成小數(shù)麻煩且易錯(cuò)。Fractional模式下IP核直接幫你把余數(shù)繼續(xù)迭代計(jì)算輸出一個(gè)定點(diǎn)格式的小數(shù)很大程度上簡(jiǎn)化了后續(xù)處理。4.2 配置要點(diǎn)Remainder Type選擇Fractional在IP核配置界面里把“Remainder Type”從Remainder切換到Fractional隨后“Remainder Fractional Width”會(huì)變成可配置項(xiàng)。這個(gè)寬度就是小數(shù)的二進(jìn)制位寬它直接決定小數(shù)的精度。比如Fractional Width設(shè)為8那么小數(shù)部分就有8bit精度換算成十進(jìn)制精度大約是1/256也就是0.0039左右對(duì)于大多數(shù)電機(jī)控制和圖像處理場(chǎng)景已經(jīng)足夠。需要理解的是這里的輸出并不是IEEE754浮點(diǎn)數(shù)而是一種定點(diǎn)數(shù)表示。把商視作一個(gè)定點(diǎn)數(shù)整數(shù)部分占前若干位小數(shù)部分占Fractional Width位。假設(shè)Dividend Width是16Divisor Width是8Fractional Width是8那么輸出總位寬約等于整數(shù)商位寬加上8位小數(shù)位寬。使用的時(shí)候你把結(jié)果當(dāng)成一個(gè)左移了8位的整數(shù)去理解后續(xù)做乘法或加法時(shí)要記得小數(shù)點(diǎn)對(duì)齊。4.3 一個(gè)坐標(biāo)歸一化的實(shí)際案例拿我做過(guò)的一個(gè)例子來(lái)說(shuō)圖像縮放模塊里需要把像素坐標(biāo)從原始分辨率映射到目標(biāo)分辨率計(jì)算公式是 dst_x src_x * src_width / dst_width。如果src_width是1920dst_width是1080直接整數(shù)除法會(huì)丟掉很多精度。我當(dāng)時(shí)的做法是配置一個(gè)Fractional模式除法器Dividend Width設(shè)為22實(shí)際需要19bit表示坐標(biāo)加上符號(hào)位Divisor Width設(shè)為12Fractional Width設(shè)為16。這樣每次算出來(lái)的結(jié)果直接就是帶16bit小數(shù)的定點(diǎn)值后面做乘法再右移16位就得到最終坐標(biāo)整個(gè)過(guò)程只用了兩次乘法一次除法精度完全夠用而且時(shí)序穩(wěn)定跑在200MHz。換成我自己寫(xiě)的組合邏輯除法器想都不敢想。4.4 Fractional模式與Radix2的性能差異同樣位寬下Fractional模式的延遲會(huì)比Remainder模式稍微大一些因?yàn)樾?shù)部分的額外迭代需要更多周期。具體延遲數(shù)值在配置界面會(huì)實(shí)時(shí)顯示建議把這一列數(shù)值記錄下來(lái)用于后續(xù)時(shí)序約束。資源方面小數(shù)位寬越大迭代級(jí)數(shù)越多LUT占用也會(huì)緩慢增加所以Fractional Width不是越大越好夠用就行。我的原則是如果小數(shù)部分精度需求在1/1000以?xún)?nèi)8bit就夠如果要在1/100000附近則需要17bit以上。定這個(gè)位寬之前最好先做一次數(shù)學(xué)換算別盲目填大。5. 仿真驗(yàn)證、調(diào)試技巧與常見(jiàn)錯(cuò)誤排查5.1 輸出有效信號(hào)的正確等待方式在所有除法器模塊里最容易讓新手困惑的就是什么時(shí)候去取輸出數(shù)據(jù)。Divider Generator IP的輸出端有一個(gè)m_axis_dout_tvalid信號(hào)這個(gè)信號(hào)拉高一個(gè)周期意味著當(dāng)前時(shí)鐘沿上m_axis_dout_tdata總線上的內(nèi)容是有效結(jié)果。不要在你輸入數(shù)據(jù)valid拉高后的下一拍就去采數(shù)據(jù)而應(yīng)該等待tvalid信號(hào)從低到高的跳變。實(shí)際操作中還有一種情況數(shù)據(jù)連續(xù)輸入時(shí)tvalid會(huì)連續(xù)拉高多個(gè)周期每個(gè)周期對(duì)應(yīng)一組輸出數(shù)據(jù)。此時(shí)可以直接把它當(dāng)作數(shù)據(jù)有效的門(mén)控信號(hào)把結(jié)果和源數(shù)據(jù)流對(duì)齊。如果業(yè)務(wù)邏輯需要一個(gè)“運(yùn)算完成”的中斷可以直接把tvalid引到中斷控制器里省得自己數(shù)延遲周期數(shù)。5.2 仿真波形里看到全X態(tài)怎么辦這是我在調(diào)試中遇到最多的問(wèn)題之一。全X態(tài)通常出現(xiàn)的原因是輸入數(shù)據(jù)在有效信號(hào)拉高時(shí)還是未知態(tài)或者IP核的復(fù)位時(shí)序不對(duì)。Divider Generator IP有可選復(fù)位端口如果不接復(fù)位內(nèi)部寄存器上電后默認(rèn)值是0問(wèn)題不大但如果例化時(shí)端口懸空某些版本會(huì)導(dǎo)致仿真器識(shí)別為X態(tài)。解決方法是把復(fù)位端口啟用并在測(cè)試平臺(tái)初始化階段拉低復(fù)位至少一個(gè)時(shí)鐘周期后再釋放。另一個(gè)常見(jiàn)原因是輸入被除數(shù)或除數(shù)的位寬和實(shí)際連接數(shù)據(jù)不一致比如你把一個(gè)16bit端口接到了12bit的reg上Vivado綜合時(shí)可能報(bào)warning仿真時(shí)則會(huì)出現(xiàn)高bit位長(zhǎng)度不匹配導(dǎo)致的X態(tài)。這種情況建議把連接信號(hào)的位寬顯式寫(xiě)清楚不要依賴(lài)隱式截?cái)唷?.3 時(shí)序違規(guī)實(shí)現(xiàn)階段紅字怎么辦如果時(shí)序報(bào)告里出現(xiàn)除法器相關(guān)路徑違規(guī)最優(yōu)先的解決思路不是去調(diào)整布局布線而是回到IP核配置界面把Latency調(diào)大或者手動(dòng)打開(kāi)“Additional Pipeline Stages”選項(xiàng)。增加流水級(jí)的作用是把關(guān)鍵路徑拆短雖然輸出延遲增大但時(shí)鐘頻率能顯著提升。如果調(diào)大延遲后timing還是紅的下一步檢查除法運(yùn)算是否處在過(guò)長(zhǎng)的組合邏輯鏈路中。比如除法器的輸入來(lái)自一個(gè)大位寬減法器輸出又接了一個(gè)大位寬乘法器這會(huì)形成三連楊組合邏輯鏈最終導(dǎo)致關(guān)鍵路徑過(guò)長(zhǎng)。解決辦法是在除法器前后各加一組寄存器打斷鏈路確保任何組合邏輯路徑上都只出現(xiàn)一個(gè)較重的運(yùn)算模塊。5.4 典型配置錯(cuò)誤速查表錯(cuò)誤現(xiàn)象直接原因解決辦法負(fù)數(shù)除法結(jié)果出錯(cuò)有符號(hào)模式下位寬未加符號(hào)位Dividend Width和Divisor Width增加1bit輸出商與預(yù)期完全相反商和余數(shù)位段順序弄反查看IP例化模板注釋確認(rèn)位段排列輸出一直為0輸入有效信號(hào)未正確拉高檢查s_axis_*_tvalid連接不能懸空tvalid信號(hào)一直不拉高Latency未到達(dá)或復(fù)位未釋放等待Latency周期確認(rèn)復(fù)位時(shí)序?qū)崿F(xiàn)階段除法路徑時(shí)序紅延遲配置過(guò)小流水級(jí)不足調(diào)大Latency或增加Additional Pipeline Stages6. 資源占用對(duì)比與速度評(píng)估選錯(cuò)模式會(huì)差多少6.1 不同模式的資源占用實(shí)測(cè)以一個(gè)Dividend Width 16、Divisor Width 8的除法器為例在Artix-7器件上做對(duì)比Radix2模式配合Remainder輸出LUT占用大約在200到300之間FF占用在100到200之間沒(méi)有使用DSP同樣的位寬切到Radix4LUT會(huì)增加到350到450FF基本持平如果選Radix16LUT可能直接翻倍到600以上。這說(shuō)明如果資源緊張Radix2是更穩(wěn)妥的選擇。再來(lái)看High Radix帶來(lái)的性能收益。使用Radix4相比Radix2Latency通常能減少20%到30%Radix16則能減少40%以上。但提升的代價(jià)就是LUT用量上升明顯。如果你是那種邏輯資源幾乎用滿(mǎn)的項(xiàng)目?jī)?yōu)先保資源選Radix2配足夠流水級(jí)如果是做高速接口類(lèi)應(yīng)用邏輯資源還有富余那就用Radix4或Radix8不用追求極致Radix16。6.2 DSP數(shù)量的誤解與說(shuō)明很多第一次使用Divider Generator IP的人會(huì)問(wèn)除法器能不能像乘法器那樣用DSP實(shí)現(xiàn)答案是不能。除法器的核心迭代邏輯是減法加比較這種結(jié)構(gòu)不適合映射到乘法器專(zhuān)用的DSP48E片上硬件單元里因此整體實(shí)現(xiàn)完全依賴(lài)LUT和FF。在評(píng)估工程資源占用時(shí)不要為除法器預(yù)留DSP資源要預(yù)留的是邏輯資源和相應(yīng)的布線資源。如果你的設(shè)計(jì)里DSP資源非常緊張可以把所有乘法和除法放在同一個(gè)IP里單獨(dú)評(píng)估別混在綜合報(bào)告里看。綜合報(bào)告在資源占用表里會(huì)把LUT邏輯、LUTRAM、FF、DSP分開(kāi)顯示除法的占用只會(huì)出現(xiàn)在LUT和FF兩列里如果你看到DSP列有數(shù)值那大概率是復(fù)用了其他運(yùn)算模塊。6.3 多路除法復(fù)用思路當(dāng)系統(tǒng)中有多路數(shù)據(jù)同時(shí)需要除法運(yùn)算時(shí)不要草率地例化多個(gè)IP核那樣LUT會(huì)成倍上漲。更好的思路是采用時(shí)分復(fù)用配置一個(gè)位寬最大、延遲固定的除法器多路數(shù)據(jù)通過(guò)一個(gè)仲裁器輪流送入每路數(shù)據(jù)在輸出端等待對(duì)應(yīng)的Latency周期后取結(jié)果。這個(gè)方法能顯著降低邏輯資源占用代價(jià)是各路數(shù)據(jù)的運(yùn)算吞吐率下降。我這里實(shí)際處理過(guò)一個(gè)8路并行的比例控制任務(wù)原本計(jì)劃例化8個(gè)除法器評(píng)估下來(lái)LUT要占4000多根本放不下。后來(lái)改成1個(gè)除法器加一個(gè)8路輪詢(xún)仲裁LUT消耗降到了600左右運(yùn)算周期從原來(lái)的幾十拍變成兩三百拍但對(duì)于控制周期十幾微秒的系統(tǒng)來(lái)說(shuō)完全夠用。這又是一個(gè)“資源與速度”之間的經(jīng)典取舍。7. 工程實(shí)現(xiàn)中的幾個(gè)隱藏技巧與個(gè)人經(jīng)驗(yàn)7.1 復(fù)位策略與跨時(shí)鐘域處理Divider Generator IP的時(shí)鐘只有一個(gè)aclk因此只要保證所有輸入數(shù)據(jù)的時(shí)鐘域和aclk一致就不需要做額外的跨時(shí)鐘域處理。但也有例外如果你的上游模塊工作在另一個(gè)時(shí)鐘域輸入數(shù)據(jù)在進(jìn)入除法器之前必須經(jīng)過(guò)異步FIFO或兩級(jí)寄存器同步。直接跨時(shí)鐘域送數(shù)據(jù)會(huì)導(dǎo)致采樣不確定最終除法結(jié)果出現(xiàn)偶發(fā)性錯(cuò)誤排查起來(lái)極度痛苦。復(fù)位策略上我建議用到復(fù)位引腳而不是懸空。雖然IP核內(nèi)部結(jié)構(gòu)對(duì)復(fù)位要求不算苛刻但在仿真階段有復(fù)位信號(hào)控制會(huì)讓行為更清晰尤其是要測(cè)試“復(fù)位后首筆運(yùn)算”這類(lèi)場(chǎng)景時(shí)。復(fù)位釋放之后建議等上兩三個(gè)時(shí)鐘周期再送第一筆有效數(shù)據(jù)給內(nèi)部狀態(tài)機(jī)一個(gè)穩(wěn)定的啟動(dòng)時(shí)間。7.2 與Vivado工程集成的細(xì)節(jié)把IP核加入工程后Vivado會(huì)自動(dòng)生成對(duì)應(yīng)的.xci文件和所有相關(guān)仿真模型。完成后compile order會(huì)自動(dòng)更新不需要手動(dòng)添加任何文件。如果你的工程使用Tcl腳本自動(dòng)化構(gòu)建也可以用命令方式生成IP核并設(shè)置參數(shù)這樣做的好處是方便版本管理和批量配置。下面是我常用的Tcl配置片段供參考create_ip -name div_gen -vendor xilinx.com -library ip -version 5.1 -module_name div_fixed set_property -dict [list \ CONFIG.algorithm_type {Radix2} \ CONFIG.dividend_width {16} \ CONFIG.divisor_width {8} \ CONFIG.remainder_type {Fractional} \ CONFIG.fractional_width {8} \ CONFIG.operand_sign {Unsigned} \ ] [get_ips div_fixed]使用Tcl腳本配置IP核的好處是以后換項(xiàng)目或換版本時(shí)只需要修改參數(shù)重新跑一次腳本就能得到結(jié)構(gòu)完全一致的除法器不會(huì)因?yàn)榻缑娌僮髀c(diǎn)某個(gè)選項(xiàng)導(dǎo)致前后行為不一致。7.3 從仿真到上板驗(yàn)證的最后一步仿真正確不代表上板就一定能跑通至少要注意兩個(gè)問(wèn)題第一IP核默認(rèn)生成的是仿真模型綜合實(shí)現(xiàn)時(shí)會(huì)自動(dòng)切換為網(wǎng)表實(shí)現(xiàn)兩者行為幾乎一致但個(gè)別情況下網(wǎng)表對(duì)復(fù)位釋放時(shí)序更敏感上板前最好在硬件環(huán)境里做一個(gè)最小驗(yàn)證第二上板后如果發(fā)現(xiàn)輸出數(shù)據(jù)偶發(fā)異常優(yōu)先用ILA抓內(nèi)部信號(hào)重點(diǎn)看tvalid和tdata的對(duì)齊關(guān)系很多時(shí)候問(wèn)題是出在數(shù)據(jù)源側(cè)而不是除法器本身。我個(gè)人的習(xí)慣是在每個(gè)用到除法器的模塊里都預(yù)留一組ILA探針平時(shí)不使能占資源極少但一旦出現(xiàn)問(wèn)題時(shí)能直接抓波形分析。對(duì)比幾次之后你就會(huì)發(fā)現(xiàn)大量看似“除法器有問(wèn)題”的現(xiàn)象最后其實(shí)都是輸入數(shù)據(jù)時(shí)序沒(méi)對(duì)齊、位寬沒(méi)匹配、或者復(fù)位不一致導(dǎo)致的真正除法器本身的故障非常少見(jiàn)。另外還想分享一個(gè)經(jīng)驗(yàn)?zāi)玫絀P核后建議花半天時(shí)間把官網(wǎng)提供的Product Guide翻一遍重點(diǎn)看Timing Diagrams那一章。很多我上面列出的“坑”比如商和余數(shù)的位段順序、tvalid的精確拉高時(shí)刻文檔里其實(shí)都有明確說(shuō)明只是平時(shí)沒(méi)人愿意靜下心看。你把這章消化掉之后用任何Xilinx的算術(shù)類(lèi)IP都會(huì)順手很多。