最易懂的ARM芯片開發科普,建議收藏!

經常有人說,現在做手機芯片就像搭積木,買點IP,連一下,後端外包。等芯片回來,上電,起OS,大功告成。這麼簡單,要不我們也來動手攢一顆吧。

首先,我們跑去ARM,問它有沒有現成的系統。ARM說有啊,A73/G71/視頻/顯示/ISP/總線/系統控制/內存控制器/Trustzone全都幫你集成好了,CPU和GPU後端也做了,還是16nm的,包你性能和功耗不出問題。然後我們再跑到Synopsys或者Cadence買EDA工具,把仿真平臺也一起打包了,順帶捎上週邊IP和PHY。至於基帶,Wifi和藍牙,先不做吧,畢竟是第一次攢,要求不能太高。

在掏了幾億銀子出來後,我們拿到一個系統框圖:

最易懂的ARM芯片开发科普,建议收藏!

A73MP4@3Ghz,[email protected],G71MP8@850Mhz,顯示4K分辨率雙路輸出,視頻4K,支持VR,支持Trustzone,內存帶寬25.6GB/s(LPDDR4x64@3200Gbps)。

本來可以樂呵呵的一手交錢一手交貨的,可我們是來攢機的,不是買整機,我們得知道這個系統到底是怎麼搭起來的,免得被坑。於是ARM給了一個更詳細的圖:

最易懂的ARM芯片开发科普,建议收藏!

有了這張圖,我們就可以對每個模塊的性能,功耗,面積還有系統性能進行詳細分析了。本文會涉及到一些基本概念,之前的文章(https://zhuanlan.zhihu.com/p/24878742?refer=c_70349842)介紹過,這篇裡就不重複了。

首先是大核模塊,這是一個手機芯片最受人關注的焦點。我們這裡A73MP4的PPA如下:

工藝:TSMC16FFLL+

頻率:2.1GHz@SSG/0.72C/0C, 2.5GHz@TT/0.8V/85C,3GHz@TT/1.0C/85C

MP4靜態功耗:251mW@TT/0.8V/85C

動態功耗:200mW@TT/0.8V/85C

面積:6.7mm,MP4, 64KB L1D, 2MB L2, No ECC, with NEON&FP

跑分:835/Ghz SPECINT2K

也就是說,跑在極限3Ghz的時候,動態功耗是200x1.25x1.25x3=937mW,四核得上4W,而手機SoC最多也就能穩定跑在3W。跑在2.5G時候,動態功耗是200x2.5=500mW,MP4總功耗2.25W,可以接受。

A53的如下:

工藝:TSMC16FFLL+

頻率:1.5GHz@SSG/0.72C/0C, 1.6GHz@TT/0.8V/85C

MP4靜態功耗:63mW@TT/0.8V/85C

動態功耗:88mW@TT/0.8V/85C

面積:3.9mm,MP4, 32KB L1D, 1MB L2, No ECC, with NEON&FP

跑分:500/Ghz SPECINT2K

四核跑在1.6Ghz時功耗463毫瓦,加上A73MP4,一共2.7瓦。

這裡的緩存大小是可以配置的,面積越大,性能收益其實是遞減的,可以根據需要自行選取。

A53的:

最易懂的ARM芯片开发科普,建议收藏!

A73的:

最易懂的ARM芯片开发科普,建议收藏!

作為CPU,集成到SoC中的時候,一個重要的參數是訪存延遲。有個數據,在A73上,每減少5ns的訪存時間,SPECINT2K分數就可以提高1%。總的延遲如下:

最易懂的ARM芯片开发科普,建议收藏!

上圖只是一個例子,頻率和參考設計並不一樣。在上圖,我們可以算出,訪存在CPU之外,也就是總線和DDR上總共需要58.7ns,這個時間也就是靜態延時,在做系統設計時可以控制。要縮短它,一個是提高時鐘頻率,一個是減少路徑上的模塊。在ARM給的系統中總線使用了CCI550,如果跑在1Ghz,一個Shareable的傳輸從進去到DDR打個來回需要10cycle,也就是10ns(上圖是CCI500跑在800Mhz,所以是12.5ns)。CCI550和CPU之間還需要一個異步橋,來隔絕時鐘,電源和電壓域。這個異步橋其實也很花時間,來回需要7.5ns,6個cycle,快趕上總線延遲了。但是沒辦法,它是省不掉的,只有通過增加總線頻率來減少絕對延遲。只有一種情況例外,就是異步橋連接的兩端時鐘頻率是整數倍,比如這裡的內存控制器和CCI之間頻率相同,那可以去掉。

有的設計會把CCI550以及它上面的CPU,GPU作為一個子網掛在NoC下,由NoC連到內存控制器。這樣的好處是可以把交織和調度交給NoC,壞處是憑空增加額外一層總線10-20ns的延遲,CPU的跑分就要低了2-4%。在ARM的方案中,交織由CCI直接完成,而調度交給內存控制器。既然所有主設備的訪問都需要到DDR,那由DMC來調度更合適。再加上沒有采用兩層總線的鏈接方式,一共可以去掉兩層異步橋,省掉12個cycle,已經快佔到整個通路靜態延遲的五分之一了。所以,現在我看到的主流總線拓撲,都是把CCI直接連內存控制器。那可不可以直接把CPU連內存控制器?只要DMC的端口夠多,也沒什麼不可以,但是這樣一來大小核就不能形成硬件支持的SMP了,功能上不允許。

路徑上還有DMC和PHY的延遲,也是將近15ns,20cycle,這部分挺難降低。如果實現Trustzone,還要加上DMC和CCI之間的TZC400延遲,還會再多幾個cycle。至於DDR顆粒間的延遲(行選擇,命令和預充電),可以通過準確的DMC預測和調度來減少,稍後再講。

靜態延遲算完,我們來看帶寬和動態延遲。

CCI和CPU/GPU之間是ACE口相連,數據寬度讀寫各128bit,16Byte。如果總線跑在800Mhz,單口的理論讀或者寫帶寬分別是10.8GB/s。這個速度夠嗎?可以通過CPU端和總線端的Outstanding Transaction個數來判斷。A73的手冊上明確指出,ACE接口同時支持48個Cacheable的讀請求,14x4(CPU核數量)設備和non-Cacheable的TLB/指令讀,7x4+16寫,這是固定的。而對應的CCI550的ACE接口支持OT數量是可配置的,配多大?有個簡單公式可以計算。假設從CPU出來的傳輸全都是64字節的(Cacheable的一定是,而non-Cacheable的未必),而我們的帶寬是10.8GB/s(假設是讀),而一個傳輸從進入ACE到離開是51.3ns(按照上圖計算),那麼最大OT數是10.8x51.3/64=8.也就是說,只要8個OT就可以應付CPU那裡100多個讀的OT,多了也沒用,因為總線數據傳輸率在那。從這點看,瓶頸在總線的頻率。

那為什麼不通過增加總線的數據位寬來移除這個瓶頸呢?主要是是位寬增加,總線的最大頻率相應的會降低,這是物理特性。同時我們可能會想,真的有需要做到更高的帶寬嗎,CPU那裡發的出來嗎?我們可以計算一下。先看單個A73核,A73是個亂序CPU,它的讀來自於三類方式,一個是讀指令本身,一個是PLD指令,一個是一級緩存的預取。A73的一級緩存支持8路預取,每路預取範圍+/-32,深度是4,預取請求會送到PLD單元一起執行,如下圖。所以他們同時受到BIU上Cacheable Linefill數目的限制,也就是8.此外還有一個隱含的瓶頸,就是A73的LSU有12個槽,讀寫共享,所有的讀寫請求(包括讀寫指令,PLD和反饋過來的預取)都掛在這12個槽中獨立維護。

最易懂的ARM芯片开发科普,建议收藏!

言歸正傳,假設系統裡全是讀請求,地址連續;此時A73每一條讀指令的延遲是3個cycle(PLD可能只需要1個cycle,我不確定)跑在3Ghz的A73,一每秒可以發出1G次讀,每個8字節(LDM)的話,就是8GB/s帶寬,相當於每秒128M次Linefill請求,除以BIU的8個Linefill數量,也就是每個請求可以完成的時間是60ns這和我們看到的系統延遲接近。此時一級緩存預取也會起作用,所以8個Linefill肯定用滿,瓶頸其實還是在在BIU的Linefill數量,按照50ns延遲算,差不多是10GB/s。假設都是寫,指令一個週期可以完成,每cycle寫8字節(STM),帶寬24GB/s。如果寫入的地址隨機,會引起大量的Linefill,於是又回到BIU的Linefill瓶頸。地址連續的話,會觸發Streaming模式,在BIU內部只有一個傳輸ID號,由於有競爭,肯定是按次序的,所以顯然這裡會成為寫的瓶頸。由於寫的確認來自於二級緩存,而不是DDR(是cacheable的數據,只是沒分配一級緩存),延遲較小,假設是8個cycle,每秒可以往外寫64B/8=8GB的數據。總的來說,A73核內部,瓶頸在BIU。

到了二級緩存這,預取可以有27次。當一級緩存的BIU發現自己到了4次的極限,它可以告訴二級緩存去抓取(Hint)。單個核的時候,4+27<48,瓶頸是在一級緩存的BIU;如果四個核同時發多路請求,那就是4x8=32個OT,再加上每路都可以請求二級緩存,其總和大於ACE的48個Cacheable讀請求。按照帶寬算,每核是10GB/s,然後CPU的ACE口的讀是48*64B/50ns=60GB/s。雖然60GB/s大於4x10GB/s,看上去像是用不滿,但是一級緩存會提示二級緩存自動去預取,所以,綜合一級二級緩存,簇內的瓶頸還是在ACE接口上,也意味著總線和核之間的瓶頸在總線帶寬上,並且60GB/s遠高於10.8GB/s。

A53是順序執行的,讀取數據支持miss-under-miss,沒有A73上槽位的設計,就不具體分析了。

這裡我簡單計算下各個模塊需要的帶寬。

CPU簇x2,每個接口理論上總線接口共提供讀寫43.2GB/s帶寬(我沒有SPECINT2K時的帶寬統計)。

G71MP8在跑Manhattan時每一幀需要370M帶寬(讀加寫未壓縮時),850Mhz可以跑到45幀,接近17GB/s,壓縮後需要12GB/s。

4K顯示模塊需要4096x2160x4(Bytes)x60(幀)x4(圖層)的輸入,未壓縮,共需要8GB/s的帶寬,壓縮後可能可以做到5GB/s。這還都是單向輸入的,沒有計算反饋給其他模塊的。

視頻需求帶寬少些,解壓後是2GB/s,加上解壓過程當中對參考幀的訪問,壓縮後算2GB/s。

還有ISP的,拍攝視頻時會大些,算2GB/s。

當然,以上這些模塊不會全都同時運行,複雜的場景下,視頻播放,GPU渲染,CPU跑驅動,顯示模塊也在工作,帶寬需求可以達到20GB/s。

而在參考設計裡,我們的內存控制器物理極限是3.2Gbpsx8Bytes=25.6GB/s,這還只是理論值,有些場景下系統設計不當,帶寬利用率只有50%,那隻能提供13GB/s的帶寬了,顯然不夠。

而我們也不能無限制的增加內存控制器和內存通道,一個是內存顆粒成本高,還有一個原因是功耗會隨之上升。光是內存控制和PHY,其功耗就可能超過1瓦。所以我們必須走提高帶寬利用率的路線。

在這個前提下,我們需要分析下每個模塊數據流的特徵。

對於CPU,先要保證它的延遲,然後再是帶寬。

對於GPU,需要保證它的帶寬,然後再優化延遲,低延遲對性能跑分也是有提高的。

對於視頻和ISP,帶寬相對來說不大,我們要保證它的實時性,間接的需要保證帶寬。

對於顯示模塊,它的實時性要求更高,相對於應用跑的慢,跳屏可能更讓人難以容忍。

其餘的模塊可以相對放在靠後的位置考慮。

在CCI550上,每個端口的帶寬是讀寫共21.6GB/s,大小核簇各需要一個端口,GPU每四個核也需要一個端口。顯示和視頻並沒有放到CCI550,原因稍後解釋。CCI550的結構如下:

最易懂的ARM芯片开发科普,建议收藏!

它一共可以有7個ACE/ACE-Lite進口,讀寫通道分開,地址共用,並且會進行競爭檢查,每cycle可以仲裁2個地址請求。之前我們只計算了獨立的讀寫通道帶寬,那共用的地址會是瓶頸嗎?算一下就知道。對於CPU和GPU,所有從端口出來的傳輸,無論是不是Cacheable的,都不超過64字節,也就是16x4的突發。一拍地址對應四拍數據,那就是可以同時有八個端口發起傳輸,或者4個通道同時發起讀和寫。假設在最差情況下,CPU+GPU同時發起shareable讀請求,並且,讀回去的數據全都引起了eviction,造成同等數量的寫。此時數據通道上不衝突,地址通道也正好符合。如果是CPU+GPU同時發起shareable寫請求,並且全都命中別人的緩存,引起invalidate,讀通道此時空閒,但是invalidate佔用地址,造成雙倍地址請求,也符合上限。到DMC的地址不會成為瓶頸,因為共四個出口,每週期可以出4個。這裡,我們使用的都是shareable傳輸,每次都會去Snoop Filter查找,每次可能需要兩個對TAG RAM的訪問(一次判斷,一次更新標誌位,比如Invalidate),那就是每cycle四次(地址x2)。而我們的Tagram用的是2cycle訪問延遲的2塊ram,也就是說,需要同時支持8個OT。這一點,CCI550已經做到了。在以上的計算中,DMC是假設為固定延遲,並且OT足夠,不成為瓶頸。實際情況中不會這麼理想,光是帶寬就不可能滿足。

在CCI550中,有兩處OT需要計算,一個是入口,每個端口獨立,一個是做Snooping的時候,所有通道放在一起。之前我們計算過,如果靜態延遲是50ns,單口的讀需要8個OT。但是,上面的靜態延遲算的是DDR命中一個打開的bank,並且也不需要預充電。如果加上這兩步,延遲就需要85ns,而CCI必須為最差的情況作考慮。這樣,OT就變成了10.8x85/64= 15。寫的話需要的更少,因為寫無需等待數據返回,只需要DMC給Early response就可以,也就是穿過CCI550(10cycle)加上少於DMC的靜態延遲(10cycle),不超過20ns,OT算3。所以,單口OT就是18,意味著需要4x18=72個來存儲請求(四個入口)。

在出口,如果是shareable的傳輸,會需要去查表實現snooping,此時所有的請求會放在一起,它的大小按照四個出口,每個帶寬2x10.8GB/s,共86.4GB/s。但是,由於我們DDR最多也就25.6GB/s,計算OT時候延遲按照讀的75ns(85-10,CCI本身的延遲可以去掉了,寫延遲小於讀,按照讀來計算),75x25.6/64=30。如果是non-shareable傳輸,那就還是使用入口的OT。

上面計算出的OT都是用來存儲讀寫請求的,其數據是要暫存於CCI550內部的buffer。對於寫來說如果數據不能暫存,那就沒法給上一級early response,減少上一層的OT;對於讀,可以在亂序地址訪問時,提高效率。由於DMC會做一定程度的調度,所以CCI550發送到DMC的讀寫請求,很多時候不是按照讀請求的次序完成的,需要額外的緩衝來存儲先返回的數據。下面是讀buffer大小和帶寬的關係圖。我們可以看到,對於隨機地址,buffer越深帶寬越高。而對於順序地址訪問,幾乎沒有影響。這個深度根據隊列原理是可以算出來的,我們這裡就不寫了。

最易懂的ARM芯片开发科普,建议收藏!

同樣,增加緩存也可以減少總線動態延遲,下圖一目瞭然:

最易懂的ARM芯片开发科普,建议收藏!

至於設置buffer的大小,根據隊列原理,由於受到DMC調度的影響,數據回到CCI500的延遲期望值不容易計算,而直接設比較大的值又有些浪費(面積相對請求緩衝較大),比較靠譜的方法是跑仿真。

關於CCI550的資源配置,還有最後一項,即tag ram的大小。CCI550的特點就是把各個主設備內部的緩存標誌位記錄下來提供給Snooping操作,那這個tag ram的大小該如何定。理論上,最大的配置是等同於各級exclusive緩存的tag ram總合。如果小於這個值,就需要一個操作,叫做back invalidation,通知相應的緩存,把它內部的標誌位去掉,免得標誌位不一致。這個是由於tag ram本身的大小限制引入的操作,在執行這個操作過程中,同地址是有競爭的,這個競爭是多餘的,並且會阻塞所有緩存對這一地址的snooping操作,所以需要儘量避免。ARM定義了一個CCI550中的tag ram和原始大小的比例,使得back invalidation保持在1-2%以下,參考下圖:

最易懂的ARM芯片开发科普,建议收藏!

簡單來說,可以用所有exclusive cache總大小的10%,把back invalidation限制在1%以下。

其他的配置參數還有地址線寬度,決定了物理地址的範圍,這個很容易理解。還有傳輸ID的寬度,太小的話沒法支持足夠的OT。

到這裡為止,我們已經設置好了硬件資源的大小,儘量使得動態延遲接近靜態延遲。下圖是全速運行時的帶寬和功耗(這裡移除了內存的瓶頸)。

最易懂的ARM芯片开发科普,建议收藏!
最易懂的ARM芯片开发科普,建议收藏!

在這裡,讀寫比例是2:1,也就是說出口收到的請求最多64+32=96GB/s。但我們可以看到有時是可以做到超越100GB/s的,為什麼呢?因為有相當部分是命中了內部的tag,轉而從緩存進行讀操作。我們之前算過,Snooping操作在CCI550內部訪問tag ram是足夠的,但是如果命中,就需要從別人的緩存讀數據,而這就收到上級緩存訪問窗口的限制。所以我們看到當命中率是100%,總帶寬反而大大下降,此時的瓶頸在訪問上級緩存。所幸的是,對於SMP的CPU,通常命中率都在10%以下,正處於帶寬最高的那段。至於通用計算,是有可能超過10%的,等到GPU之後再討論。

第二副圖顯示了動態功耗,在25GB/s時為110毫瓦,還是遠小於CPU的功耗,可以接受。靜態功耗通常是10-20毫瓦,對於待機功耗其實並不低,而且tag ram是沒法關閉的(300KB左右),只要有一個小核在運作,就必須打開。所以CCI550的靜態功耗會比CCI400高一些,這就是性能的代價,需要有部分關閉tag ram之類的設計來優化。

不過,一個沒法避免的事實是,總線的入口帶寬是86.4GB/s,出口卻只能是25.6GB/s。我們需要一些方法來來達到理論帶寬。在總線上,可以使用的方法有調度和交織。

調度之前已經提到過,使用亂序來提高不存在競爭問題的讀寫傳輸,CCI550自已有內嵌策略,不需要配置。

而交織在之前的文章中也提過。 在CCI550上,只接了CPU和GPU,而他們發出的所有傳輸都不會超過64字節,也就是一個緩存行長度。只有一種可能的例外,就是exclusive傳輸,在spin lock中會用到。如果有一個變量跨緩存行,那麼就有可能產生一個128字節的傳輸。而由於這類可能存在的傳輸,CCI550可以設置的最小粒度是128字節,來避免它被拆開到兩個內存控制器,破壞原子性。不過到目前為止,CPU/GPU都不會發出128字節傳輸,如果有跨緩存行的變量,直接切斷。這樣雖然會造成軟件邏輯上的錯誤,但這錯誤是軟件不遵守規範引起的,ARM軟件規範裡明確禁止了這類問題。

對於視頻和顯示模塊,它們並沒有連在CCI550。因為CCI550內部只有兩個優先級,不利於QoS。QoS我們稍後再討論,先看系統中的NIC400總線。參考設計中NIC400鏈接了視頻/顯示和DMC,但其實NIC400並沒有高效的交織功能,它的交織必須把整個物理地址空間按照4KB的頁一個個寫到配置文件。此外,它也沒有調度和緩衝功能,所以在複雜系統中並不推薦使用。NIC400更適合簡單的系統,比如只有一個內存控制器,可以用更低的功耗和麵積實現互聯。在這裡我們可以使用NoC來替換。NoC還有一個適合傳輸長數據的功能,就是分割,可以把265字節甚至4KB的突發傳輸隔成小塊,更利於交織。

這裡就引出了一個問題,到底我們交織的粒度是多少合適?粒度越大,越不容易分散到各個DMC,而粒度越小,越不容易形成對某個DMC和DDR Bank的連續訪問。

在四個通道的DMC上,CCI550使用了這樣一個哈希變換,來使得各個模塊的傳輸能夠平均分佈:

◦Channel_Sel[0] = Addr[8] ^ Addr[10] ^ Addr [13] ^ Addr [21]

◦Channel_Sel[1] = Addr[9] ^ Addr [11] ^ Addr [16] ^ Addr[29]

然後在DMC,使用了這樣的變化來使訪問分散到各個Bank:

◦For four channel memory: Addr[29:0] = {Addr[31:10], Addr[7:0]}

經過哈希化後,在CPU的順序地址上效果如下:

最易懂的ARM芯片开发科普,建议收藏!

在顯示模塊的上效果如下:

最易懂的ARM芯片开发科普,建议收藏!

顯然,在256字節的交織顆粒時效果最好,尤其是對於連續地址。對於隨機地址,有個細節我們可以注意下,在顆粒度64/128字節的時候最好,這其實也符合預期。

剛剛我們提到了在DMC中的哈希優化。DMC最重要的功能是調度,這是提高帶寬利用率的關鍵。ARM的DMC可以做到在多個主設備的64字節隨機地址訪問時做到94%的利用率(讀),寫也可以到88%。我們可以通過一些參數的設置來影響它的調度判斷:讀寫操作切換時間,Rank(CS信號)切換時間以及頁內連續命中切換閾值,高優先超時切換時間等,這些看名字就能理解,不詳細解釋了。

調整完這麼多參數,還有一個最根本的問題沒有解決:DDR理論帶寬也只有25.6GB/s,各個主設備一起訪問,總會有擁擠的時候。這時該採取什麼策略來最大程度上保證傳輸?答案是QoS。QoS的基本策略是設置優先級,其次還有一些輔助策略,比如動態優先級調整,整流等。

最易懂的ARM芯片开发科普,建议收藏!

上圖是優先等級表,左邊是總線的(包括CCI和NoC/NIC),高低依次是顯示模塊>視頻>CPU>GPU>PCIe>DMA,基帶跳過。在CCI550內部,實際上只有高和第兩種優先級,CPU高,GPU低,沒法區分更多的主設備。CCI550的優先級高低是給外部用的,可以拿來給DMC,讓DMC定一個閾值,告訴CCI哪些級別之上優先發送,哪些暫緩。

當中的表是DMC內部對QoS優先級的重映射。DMC500支持把某個模塊的優先級提高,並動態調整。這裡,CPU在每秒發送1.6GB之後,優先級會被降低,和外部總線一樣。下圖中,我們可以看到在沒有QoS的時候,CPU的延遲最大(最左邊noqos),有了QoS,由於CPU的優先級相對較高,延遲大大降低(qos_only)。而用了重映射之後,在1.6GB之下,延遲又進一步較大降低。

最易懂的ARM芯片开发科普,建议收藏!

讓我們再看一個例子,更好的說明如何通過調整優先級來在有限的帶寬下保證實時性:

最易懂的ARM芯片开发科普,建议收藏!

在上圖,我們看最右邊,由於顯示和視頻總帶寬需求不高,所以都能滿足。

最易懂的ARM芯片开发科普,建议收藏!最易懂的ARM芯片开发科普,建议收藏!

而這2張圖裡面,帶寬需求上升,我們看到Video的帶寬反而下降,而CPU不變。可在我們設置的表裡,CPU的優先級是低於視頻模塊的。於是我們利用DMC的門限,告訴CCI不要送低優先級的,並把CPU中小核的優先級降低到門限之下,這樣只要有視頻流,CCI送到DMC的數據就會減少,如下圖:

最易懂的ARM芯片开发科普,建议收藏!

當然,我們也可以通過別的機制來達到類似的效果,比如限流等。攢機是個細緻活,功夫夠了肯定能調好,就是需要耐心和積累。

到這裡才把CPU和總線,內存控制器考慮了,其他的GPU,多媒體,顯示,系統控制和調度,傳感器,安全,ISP,VR,通用計算,還沒開始解釋呢,以後有空慢慢更新吧。

R

eading


分享到:


相關文章: