針對C64x+的一些優化經驗

本人做TI DSP優化過程中的一些積累,顯得比較凌亂,但都是比較常用而且非常有必要了解的點,大家可以接在這後面補充自己的經驗

>. 同一EP包中不會出現兩條指令使用同一功能單元。
   使用同一交叉通道的2條指令不能並行.

>. 兩條指令使用同一功能單元,不能在同一cycle內將結果寫出,因爲每個unit僅有一個寫出port.

>. 兩條指令使用同一乘法單元時,它們不能在同一指令週期內向register寫出結果,理由同上,每個unit僅有一個到寄存器文件的寫出port.

>. 每個EP,每條data path下,最多兩個unit能夠通過交叉path(1X, 2X)讀取反向register file中的同一個操作數(假定兩個units讀取同一個操作數).

>. 對C64X/C64X+ CPU,當指令通過cross path讀取一個cycle前被更新的寄存器時,總會產生一個cycle的延時,稱之爲stall, stall時,不需要插入NOP指令,由硬件自動完成插   入,但要注意,如果被cross path讀取的寄存器中的數據是由Load指令更新,或更新時距超過一個cycle,則不會產生stall. 通過合理安排指令流程,儘量在寄存器操作數更新    後一個cycle之後再由cross path訪問之,以避免stall。大部分情況下,TMS320C6000 C編譯器和彙編優化器會自動完成指令調整以避免stall產生.

>. 在同一EP中,不允許兩個load和store指令對同一寄存器文件中的同一源/目的進行操作。且地址寄存器必須與DA所使用的D unit出於同一側.

>. T1,T2支持64-bit load/store, T1/T2與unit同出現在load/store指令中. 相對於C62x DSP,C64x有改進,後者的.D功能單元亦與交叉通道相聯,也可每週期由交叉通道從另一   側寄存器組讀取一個源操作數;且允許一側的多個功能單元由交叉通道從另一側讀數,只要是從另一側的同一個源即可.

>. C64X/C64X+ dsp支持在任何byte邊界使用非對齊的load/store訪問word和doubleword。由此,word和doubleword數據均不需要32-bit或64-bit邊界對齊.
   L/S指令所用的地址指針寄存器必須與所用的.D功能單元處於同一側

>. 當一unit做非對齊的Memory訪問時(通常unit帶T1/T2)時,不允許另一unit同時做memory操作,但允許另一unit同時做非memory訪問的操作.

>. C62x與C67x系列因爲data path共享,故都限制了同時讀和寫的40-bit數據的數目,而C64x/C64x+ cpu因爲每個Unit採用分開的data path,故不存在以上限制.

>. 除條件寄存器外,在同一cycle內,不允許對同一寄存器做4次以上的讀操作.

>. 同一cycle內,兩條指令不能向同一寄存器寫入。具有同一dst寄存器的兩條指令也可以被安排成並行,條件時它們不會在同一cycle內向dst寫入.

>. 使用MVC指令向尋址模式寄存器AMR寫入,如果其後緊跟指令LD,ST,ADDA或SUBA,且此4指令使用了A4-A7,B4-B7寄存器尋址,則會產生一個cycle的stall. 記住,當以    A4~A7,B4~B7爲基址寄存器時,將按照AMR寄存器的內容選擇線性尋址或循環尋址.

>. 同一EP中不允許出現兩條產生多個NOP cycle的指令.

>. 循環尋址方式可用於非對齊的數據訪問,採用循環尋址方式後,地址更新和內存訪問均按byte方式進行,即與相當量的byte序列的尋址訪問相同.

>. 非對齊循環buffer訪問方式適用於對邏輯地址相連內存區域的循環尋址,當非對齊訪問到循環buffer邊界時,將能正確的從buffer的兩端讀取數據,實現邊界處的無縫連接.

>. 對C64x,唯一限制是循環buffer的大小至少與被訪問的數據尺寸相同。如果buffer比被訪問的數據類型小,則非對齊訪問將產生無法預知的錯誤;而對C64x+,循環buffer至少爲32bytes.

>. 程序指令:
    >#pragma MUST_ITERATE(N1,N2, N3)---->向編譯器提供信息,三個參數意義如下:下面的循環至少執行N1次;下面的循環至多執行N2此;循環執行次數必是N3的整數倍,這     三個參數不必全有。這個信息對編譯器使用軟件流水技術非常重要.
    >>_nassert(表達式)---->此內聯函數本身不產生任何代碼,其作用是告訴編譯優化器,其括號內的表達式爲真,因而隱含的提示編譯優化器,某種優化可能會有效.
    >>volatile: 使用此關鍵字後,即使使用-o3編譯選項,編譯器也不會對該變量的訪問做任何優化,以保證程序執行結果正確,也因爲此,不可多用它,一般以下情況要用:
     @凡是2個線程共享的全局變量就需要使用volatile關鍵字; @凡是某個內存地址的內容隨時可能被外部硬件改變就需要使用volatile關鍵字。
    >>restrict: 用此關鍵詞向編譯器標明一個指針是指向一個特定對象的唯一的指針,以提高memory訪問速度。
    >>變量存取方式及far關鍵字:
     C編譯器支持兩種內存模式:大頭模式和小頭模式。不同內存模式主要影響對.bss段中的變量的訪問方式。凡是程序中定義的全局變量(在函數外定義的變量)和靜態變量(用static關鍵字定義的變量)都被編譯器分配在.bss段中。在小頭模式下,要求.bss段小於32K,即上兩種變量總和不可超過32K,此時編譯器將頁指針DP(寄存器B14)指向.bss段的起始,對變量採用直接尋址方式,1條指令就可加載一個變量;而在大頭模式下,對.bss沒有任何限制,編譯器對變量採用寄存器間接尋址方式,需要3條指令加載一個變量。這樣,但定義的量超過32k,而又希望用小頭模式時,可以採用far關鍵詞。對於大的數組定義,使用far關鍵字,這樣,buffer不會佔用.bss段的地址空間,而時被編譯器分配到.far段,對於數組,一般是用DMA訪問或通過軟件流水訪問,不會又存取速度問題。
    >>link文件開頭:
    -c                    :指定運行時初始化全局/靜態變量, 系統調用C初始化函數c_init完成;
      -heap 0x2000         :設置堆的大小
    -stack 0x4000         :設置棧的大小
    >>.text: 編譯器生成的代碼段一般以.text爲段名,所有其他段都可以看做是數據段.   
      >>.bss : 全局變量(函數外定義的變量)和靜態變量(static定義的變量)分配在此段.
      >>.stack: 一般的局部變量(函數內部定義的變量)或是使用寄存器,或是分配在此段.
      >>.const: 常量和字符串在此段
    >>.cinit: 變量初值表,在編譯器生成程序時,會將C程序中初始化的全局/靜態變量的初始值按一定的數據結構放在此段,然後由C初始化函數c_init讀取此段,來初始化.bss段中的變量,可見給變量賦初值的工作仍然要自己完成!!!

>. 使用選項 -k ,令編譯器保留.asm文件,因爲編譯器產生的.asm文件反饋了許多信息,理解這些信息,按它的提示修改C語言程序,對儘快優化代碼有好處.

>. C64x具有雙字讀取與存儲指令,增大了訪問存儲器的帶寬;峯值帶寬可達到每個指令週期128位;增加了無邊界調整的存儲器訪問能力,在沒有32位或64位邊界調整的嚴格限制下,C64x可以在單週期內完成64位數據的讀寫操作.

>. 在一系列嵌套循環中,最內層的循環是唯一可以進行軟件流水的循環。循環不能軟件流水的諸因素:
   >>軟件流水循環可包含intrinsics,但不能包含函數調用.
    >>在循環中不可以有條件終止、使循環提前退出的指令.
    >>循環必須是遞減計數形式且在0時終止。使用-o2 and -o3選項的一個原因就是將儘可能多的循環轉換成遞減計數的循環.
    >>在循環體中修改循環計數,則這個循環不能轉換成遞減計數循環,因而也無法進行流水.
    >>代碼尺寸太大,需要的寄存器數目大於C64xx的64個,這時需要簡化循環或將循環拆成幾個小循環.
    >>如果要求一個寄存器的生命太長,則這個代碼不能進行流水.
    >>如果循環內有複雜的條件代碼,條件代碼需要大於C64xx的6個條件寄存器數,則這個循環不能進行軟件流水.

>. 一般而言,用與源操作數相同字長的數據類型來保存累加和是非常危險的。通常選擇是在計算過程(循環)內用較長的數據類型保存和數,最後根據具體情況選取適當字長。

>. 轉移指令有5個週期的延遲間隙(當前cycle n,到cycle n+6跳轉完畢,並執行指令),即在轉移指令進入流水線後,要再等5個週期才發生跳轉。所以,轉移指令後的5個指令指向包(EP)都進入了CPU流水線,並相繼執行,在寫彙編時要特別注意這一點.

>. !!!!!!!!爲防止數據訪問的bank衝突,優化辦法是將算法中訪問的2個數組定義在不同的bank中,具體做法是定義不同的數據段:L1_data1, L1_data2,並在cmd中將這兩個段定位到不同的兩段內存: L1_data1 > memory1, L1_data2 > memory2; 將函數中用到的兩個數組分別放在不同的存儲塊(要求芯片有一個以上存儲塊blocks);將一個數組的偶元素和奇元素的訪問安排在同一循環週期內。

>. 絕對不能把做了軟件流水編排後輸出的彙編語言程序再次作爲彙編優化器的源程序輸入,否則將導致整個程序編排錯誤。線性彙編語言應按照指令的自然邏輯順序"線性"的安放指令,由彙編優化器對它分析,做出優化安排

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章