# Lab2 - FIR_AXI4-Master v.s. FIR_AXI4-Stream :::warning [TOC] ::: ## Resource [bol-edu github:course-lab_2](https://github.com/bol-edu/course-lab_2) ## FIR_AXI4-Master Block Diagram ![螢幕擷取畫面 2024-09-20 141947](https://hackmd.io/_uploads/HJJ1SG66R.png) ## FIR_AXI4-Stream Block Diagram ![螢幕擷取畫面 2024-09-20 141725](https://hackmd.io/_uploads/HJmgrzTT0.png) ## Introduction Lab2為 FIR(Finite Impulse Response)在兩個不同傳輸資料的port level protocol(m_axi、 axis)硬體 (PYNQ Z2)實作 。透過Vitis_hls撰寫 pragma或設定directive來定義輸入與輸出透過何種program I/O來傳輸,並使用先前寫好的testbench對於主程式進行 C simulation。在 Simulation後,進行 Synthesis並觀察在主視窗跳出的synthesis report並分析其timing和area的information。接著進行 C Testbench和RTL的Cosimulation觀察波型,並輸出RTL code供Vivado進行下一步動作。 由Vitis_hls所匯出的IP匯入Vivado,並對其進行block design。加入在Vitis_hls做完的Kernel並加入ZYNQ7 Processing System作為host端,在不同的port level protocol中適當加入需要的硬體資源(如在axis部分加入AXI DMA(Directed Memory Address))並透過auto connection完成block design。進行完block design後,對其進行wrapper以利後續Bitstream的生成。最後將Bitstream輸出的.bit檔、Meta Data .hwh檔和python host program上傳至OnlineFPGA的Jupyter Notebook中,在PYNQ上進行運算,並與先前Vitis_hls的C Simulation結果進行比較。 ## Observation & Learning ## Vitis_hls ### 程式碼理解 在.cpp部分,兩個不同port level protocol硬體的行為皆相同,皆為在第幾個的輸出為當下時序前每一個輸入乘上每一個輸入對應到的權重的總和。而在port level protocol部分,兩種硬體的定義方式不同。在m_axi部分,其透過directive方式對於top module和I/O的interface進行定義,而在axis部分,則是使用pragma如Lab1的方式進行定義。 圖(1) m_axi定義port level protocol方式(directive) ![image](https://hackmd.io/_uploads/BymYYzapR.png) 圖(2) axis定義port level protocol方式(pragma) ![image](https://hackmd.io/_uploads/rJ3YtMTTR.png) 表(1) 兩個不同program I/O所使用所有的Interface | | m_axi(AXI4-Master) | axis(AXI4-Stream) | |:------------------------:|:----------------------------:|:-----------------------:| | pn32HPInput/pstrmInput | m_axi,depth=600,offset=slave | axis,register mode:both | | pn32HPOutput/pstrmOutput | m_axi,depth=600,offset=slave | axis,register mode:both | | an32Coef | s_axilite | s_axilite | | regXferLeng | s_axilite | s_axilite | 上表為本次實驗中兩個使用不同port level protocol所有的Interface設定。在testbench部分匯入head檔後,將輸入信號寫入input array當中提供代入top module產生資料所用。 有了input array後,可將input、tabs和要傳送的資料長度引入top module,運算後的結果將寫入out.dat,最後將out.dat與已知的out_gold.dat內所有資料比對得到結果,若完全相同,則印出”Test Passed!”,否則印出”Test Failed!”。 ### C Simulation 在了解程式碼的運作方式後對於其進行 C Simulation,可透過testbench對於C code進行behavior的驗證,如下兩張圖所示。 圖(3) m_axi的C Simulation Result ![image](https://hackmd.io/_uploads/B1iqFM6p0.png) 圖(4) axis的C Simulation Result ![image](https://hackmd.io/_uploads/HkHiFz6aC.png) ### C Synthesis #### Utilization 在進行完成C simulation後,將對於C code進行Synthesis。 圖(5) m_axi的Utilization ![image](https://hackmd.io/_uploads/Bkx2tfapA.png) 圖(6)axis的Utilization ![image](https://hackmd.io/_uploads/rkw2tfpp0.png) 在Utilization部分,m_axi部分共使用了33個DSP(Digital System Processing)、3800個FF(Flip-Flop)和2838個LUT(Look Up Table)來建構此運算需要的resource。在axis部分, 共使用了33個DSP(Digital System Processing)、2988個FF(Flip-Flop)和1333個LUT(Look Up Table)來建構此運算需要的resource。由結果可推論,在運算部分(DSP),兩者使用的硬體資源相同,而在記憶體存儲部分,axis在硬體資源的使用上相較m_axi可以更加節省。 #### Configuration Register 圖(7) m_axi的s_axilite configuration register ![image](https://hackmd.io/_uploads/SJgRtG6aR.png) 圖(8) m_axi的s_axilite configuration register ![image](https://hackmd.io/_uploads/S1TCYfpaR.png) 在C synthesis的部分,也可以觀察兩個不同program I/O所使用Interface在合成出的s_axilite configuration register差異,如圖(7)和圖(8)所示。 ### C & RTL Co-simulation 在完成C Synthesis後,分別對於m_axi和axis進行分析。 #### m_axi(AXI4-Master) 進行C和RTL的Co-simulation時,可得整個系統的Waveform,如下圖所示。 圖(9) block level protocol of m_axi ![image](https://hackmd.io/_uploads/rJ9xcMTTR.png) 圖(9)為m_axi 的block level protocol的Waveform,綠色波型依序為ap_start、ap_done、ap_idle、ap_ready。當Host Side將ap_start program為1,ap_idle離開idle狀態由1轉為0。當Kernel Side完成Task時,ap_done由0抬升為1同時將ap_ready由0抬升至1,代表Kernel Side可以接受下一個Host Side的Task Request。 圖(10) axi_master waveform (1) ![image](https://hackmd.io/_uploads/rkBmofpTA.png) 圖(11) axi_master waveform (2) ![image](https://hackmd.io/_uploads/rJ0moG6TA.png) 圖(10)和圖(11)為axi_master讀寫資料的波型圖。可觀察到在1650ns時,axi_master每10ns讀取一筆資料,並資料由000000讀取至ffffff,而在寫入部分則是在1945ns開始寫入,axi_master每10ns寫入一筆資料,然而寫入無特定順序。 圖(12) port level protocol of m_axi ![image](https://hackmd.io/_uploads/rkiBjGaTR.png) 圖(12)為port level protocol的Waveform,可觀察到在ARVALID部分都為0,故都沒有讀取任何的資料且可觀察到RDATA都為高阻抗。在寫入部分,可觀察到AWREADY先由0抬升至1等待AWVALID為1準備handshake,並在AWVALID由0抬升至1開始handshake得到要寫入的address。WVALID部分,則是先由0抬升至1等待得到要寫入的address。當AWVALID和AWREADY都變成negedge時,WREADY由0抬升至1開始寫入資料。完成資料寫入後,WVALID和WREADY降至0。 圖(13) Latency of m_axi ![image](https://hackmd.io/_uploads/rkitofp6A.png) 上圖為m_axi的Co-sim結果,得到平均延遲、最小延遲和最大延遲如圖(13)。 #### axis(AXI4-Stream) 圖(14) block level protocol of axis ![image](https://hackmd.io/_uploads/HJdcjGa6R.png) 圖(14)為axis的block level protocol的Waveform,綠色波型依序為ap_start、ap_done、ap_idle、ap_ready。當Host Side將ap_start program為1,ap_idle離開idle狀態由1轉為0。當ap_ready由0抬升至1,ap_done也隨之升起,此時Master端與Slave端開始handshake。當Kernel Side完成Task時,ap_done由0抬升為1同時將ap_ready由0抬升至1,代表Kernel Side可以接受下一個Host Side的Task Request。axis與m_axi的波型近乎完全相同,差別在於整體完成測試時間。 圖(15) output of axis(1) ![image](https://hackmd.io/_uploads/ByDSnMTTR.png) 圖(16) output of axis(2) ![image](https://hackmd.io/_uploads/rJy8hG6pR.png) 圖(15)和圖(16)為axis output的相關資訊,可觀察到當t = 1.925us時,資料開始輸出,並且每0.1us輸出一筆資料直至資料完整輸出。 圖(17) input of axis (1) ![image](https://hackmd.io/_uploads/BJ4vhfT6A.png) 圖(18) input of axis (2) ![image](https://hackmd.io/_uploads/rkMu3Gap0.png) 圖(17)和圖(18)為axis input的相關資訊,可觀察到起始時TREADY先由0抬升至1,等待TVALID為1做資料的handshake,如同老師上課所述的前面有著FIFO Buffer存放資料,使得TREADY可以叫TVALID先抬升至1。由圖(17)下半部分可觀察出當完成輸入一筆資料時,TREADY就會有一個pluse,並且每0.11us輸入一筆資料。 圖(19) Latency of axis ![image](https://hackmd.io/_uploads/BJAK3MT6R.png) 上圖為axis的Co-sim結果,得到平均延遲、最小延遲和最大延遲如圖(19)。 ### Export RTL 在完成C和RTL的Co-simulation後,匯出RTL code供Vivado進一步分析使用。 ## Vivado 由Vitis_hls匯出的RTL code,在Vivado中可建立其block design。 在block design中,加入Vitis_hls設定好的做完Kernel端和ZYNQ7 Processing System作為host端,在不同的port level protocol中適當加入需要的硬體資源(如在axis部分加入AXI Directed Memory Address)並透過auto connection完成block design。進行完block design後,對其進行wrapper以利後續Bitstream的生成。 ## Jupyter Notebook 由Vivado輸出的BitStream中的.bit檔、.hwh檔與寫好的.ipynb檔,將其上傳至OnlineFPGA的Jupyter Notebook中並在PYZQ Z2上進行運算得到結果。 在.ipynb檔中,須將axi\_dma\_out_1改為在Vivado block design 階段我們所設計的AXI Direct Memory Address(axi\_dma\_out_0),否則會編譯失敗。 ### Execution Results #### m_axi(AXI4-Master) 圖(20) Jupyter Notebook Execution Result of AXI4-Master ![image](https://hackmd.io/_uploads/B1WdpzppR.png) #### axis(AXI4-Stream) 圖(21) Jupyter Notebook Execution Result of AXI4-Stream ![image](https://hackmd.io/_uploads/HJ_KTM6pC.png)