學習內容
本文首先介紹了雙核AMP通信的相關內容,接著進行設計AMP雙核通信的工程,完成功能驗證。
開發環境
vivado 18.3&SDK,PYNQ-Z2開發板。
雙核通信
多核處理器從結構上劃分:同構多核: 同構多核處理器是指系統中的處理器在結構上是相同的,在軟硬件設計上較為簡單,通用性高。異構多核: 異構多核處理器是指系統中的處理器在結構上不同的,在特定場合中可以進行加速,提高性能。
Xilinx 的 ZYNQ SOC 融合了這兩種架構, ZYNQ SOC 芯片包含兩個獨立的 Cortex-A9 處理器,這兩個處理器核在結構上是相同的,同時又包括了可編程的邏輯單元( PL),使得 ZYNQ 整體系統成為了一個異構多核系統,同時具有較高的通用性和性能。
多核處理器軟件運行方式
多核處理器的運行模式有 AMP(非對稱多處理)、 SMP(對稱多處理)和 BMP(受約束多處理)三種運行模式。AMP(非對稱多處理): 多個內核相對獨立的運行不同的任務,每個內核相互隔離,可以運行不同的操作系統。SMP(對稱多處理): 多個處理器運行一個操作系統,這個操作系統管理多個內核。BMP(受約束多處理): BMP運行和SMP運行模式類似,開發者可以指定將某個任務僅在某個指定內核上執行。下圖為SMP和AMP的示意圖:
AMP非對稱多處理運行
詳細介紹
由于AMP多用于裸機開發,在兩個CPU上可以運行不同的應用程序,所以本次工程主要使用該方式進行雙核通信。對于AMP的相關設計這里可以參考XAPP1079的文檔進行設計驗證。
ZYNQ-7000 AP SoC 提供兩個共享通用內存和外設的 Cortex-A9 處理器。非對稱多處理 (AMP) 是一種機制,允許兩個處理器運行自己的操作系統或裸機應用程序,并可以通過共享資源松散耦合這些應用程序。
在AMP模式中,每個CPU可以訪問自己獨立的程序任務,但是需要注意的是要防止CPU在共享資源上發生沖突,否則會發生錯誤。
資源分布
對于該架構,CPU會有一些私有資源和共享資源,具體如下:私有資源:
- L1 cache
- Private peripheral interrupts (PPI)(私有外設中斷)
- Memory management unit (MMU)(內存管理單元)
- Private timers
共享資源:
- Interrupt control distributor (ICD)(中斷控制分配器)
- DDR memory(DDR內存)
- On-chip memory (OCM)(片上資源)
- Global timer(全局時鐘)
- Snoop control unit (SCU) and L2 cache
- UART0(串口)
兩個處理器都使用 OCM 來相互通信。與 DDR 內存相比,OCM 提供了非常高的性能和來自兩個處理器的低延遲訪問。通過禁用兩個處理器對 OCM 的緩存訪問,進一步確保了確定性訪問。此設計為防止共享資源出現問題而采取的措施包括:
- DDR 內存:CPU0 使用 0x00100000 到 0x001FFFFF 的內存。CPU1 使用從 0x00200000 到 0x002FFFFF 的內存用于其裸機應用程序。
- L2 緩存:CPU1 不使用L2 緩存。L2 緩存是共享資源,CPU0 擁有此資源。如果 CPU1 使用 L2 緩存,則需要從 CPU0 請求 L2 緩存刷新和失效,而 CPU0 將執行該操作。包含使 CPU1 能夠請求 L2 緩存交互的通信通道超出了本示例設計的范圍。
- ICD:來自PL 內核的中斷被路由到CPU1 的PPI 控制器。通過使用 PPI,CPU1 可以自由地處理中斷,而無需訪問 ICD。
- 定時器:CPU1 使用專用定時器。
- OCM:每個CPU 都非常小心地處理對OCM 的訪問以防止爭用。單個 OCM 地址位置用作標志以在兩個處理器之間進行通信。CPU0 在啟動 CPU1 之前將標志初始化為 0。當標志為零時,CPU0 擁有 UART。當標志不為零時,CPU1 擁有 UART。只有 CPU0 設置標志,只有 CPU1 清除它。
參考設計
參考設計為賽靈思的官方文檔xapp1079,這個文檔設計的AMP架構是運行在ISE軟件下,但是對我們進行AMP架構開發依舊有參考意義。
參考設計硬件部分
PL塊包含一個自定義的嵌入式核心,連接到ChipScope分析儀VIO核心的同步輸出。VIO核心為用戶提供了與ChipScope分析儀硬件交互的機制。
在這個設計中,當VIO產生一個脈沖時,自定義核心將一個中斷轉發給PS Core1_nlRQ引腳。核心還連接到PS主通用端口(M AXI_GP0),通過一個允許CPU0和CPU1訪問核心內的控制寄存器的AXI互連。在中斷服務程序期間,CPU1訪問控制寄存器以清除中斷請求(IRQ)。CPU0可以選擇使用控制寄存器來創建一個指向CPU1的中斷。Core1_nlRQ引腳直接連接到CPU1 PPI塊,因此不需要修改共享ICD的配置。還包括一個ChipScope分析儀axis監視器核心,允許用戶測量正在服務的IRQ的延遲。
參考設計軟件設計
該軟件可以分為三個部分:
- 第一階段引導加載程序(FSBL)
- 用于CPU0的裸機應用程序
- 用于CPU1的裸機應用程序
FSBL總是在CPU0上運行,是PS上電復位后第一個運行的軟件應用程序。FSBL負責編程PL,并將應用程序可執行文件和可鏈接格式(ELF)文件復制到DDR內存。在將應用程序加載到DDR內存后,FSBL然后開始執行加載的第一個應用程序。
參考設計讓CPU0和CPU1運行它們自己的裸機應用程序代碼。CPU0負責初始化共享資源并且啟動CPU1。CPU0的應用程序位于從地址0x00100000開始的內存中。鏈接器腳本用于設置起始地址。CPU0的設計步驟:
- 配置MMU對0xFFFF0000 ~ oxfffffe地址范圍內的OCM訪問關閉緩存功能。OCM的地址映射是不變的,所以OCM存在于地址0x00000000到0x0002FFFF和地址0xFFFF0000到0XFFFFFFFF。示例設計只使用了高64kb的OCM,因此在地址0xFFFFo000到oxfffffe上禁用緩存。
- 初始化ICD;
- CPU1開始啟動;
- 打印到UART;
- 在OCM中設置一個用作信號量標志的內存位置;
- 等待OCM中用作信號量標志的內存位置被清除。CPUO應用程序無限期地重復步驟3到步驟6。
PS啟動后,內部 boot ROM完成執行,CPU1被重定向到0xFFFFFE00的OCM中的一小段代碼。這段代碼是一個連續循環,它等待一個事件,檢查地址位置0xFFFFFFF0的非零值,然后繼續循環。如果0xFFFFFFF0包含一個非零值,CPU1將跳轉到獲取的地址。
CPU0通過將Ox00200000的值寫入地址0xFFFFFFF0,然后運行Set Event (SEV)命令來啟動CPU1(兩者都運行裸機程序)。SEV喚醒CPU1,從地址0xFFFFFFF0讀取值0x00200000,然后跳轉到地址0x00200000。FSBL負責將CPU1 ELF放置在0x00200000。
CPU1應用程序位于從地址Ox00200000開始的內存中。鏈接器腳本用于設置起始地址。CPU1應用程序執行以下操作:
- 配置MMU對地址范圍為0xFFFF0000 --0XFFFFFFFF的OCM訪問關閉緩存功能。OCM的地址映射是不變的,因此OCM存在于地址0x00000000到0x0002FEEF和地址0xFFEF0000到xFFFFFFFE。這個應用程序筆記只使用了OCM的高64kb,所以緩存在地址0xFFFF0000到0XFFFFFFFF上被禁用。
- 初始化PPl中斷控制器和中斷子系統。
- 等待OCM中用于設置信號量標志的內存位置。
- 打印到UART。打印的字符串的選擇取決于中斷服務例程是否增加了一個全局變量。如果全局變量irq_count不為零,CPU1將該值設置為零
- 清除OCM中用作信號量標志的內存位置。CPU1應用程序無限期地重復步驟3到步驟5。
一些細節
啟動CPU1
CPU 0負責在CPU 1上啟動代碼執行。BootROM將CPU 1設置為Wait for Event模式。什么都沒有啟用,只有少數通用寄存器被修改,以將其置于等待WFE指令的狀態。
CPU0在CPU1上啟動應用程序需要少量的協議。CPU 1收到系統事件后,立即讀取地址0xFFFFFFF0的內容并跳轉到該地址。如果SEV在更新目的地址位置(0xFFEEFFE0)之前發出,CPU1繼續處于WFE狀態,因為0xFFFFFFF0將WFE指令的地址作為安全網。如果編寫0xFFFFFFF0地址的軟件無效或指向未初始化的內存,則結果是不可預測的。
CPU 1上的初始跳轉只支持Arm-32 ISA代碼。在跳轉的目的地不支持Thumb和Thumb-ll代碼。這意味著目的地址必須是32位對齊的,并且必須是有效的Arm-32指令。如果不滿足這些條件,結果是不可預測的。CPU0在CPU1上啟動應用的步驟如下:
- 將cpu1的應用程序地址寫入0xFFFFFFF0。
- 執行SEV指令,喚醒CPU1并跳轉到應用程序。
地址范圍0xFFFFEE00到0xFFFFFFF0是保留的,在第1階段或以上的應用程序完全可用之前不能使用。在第二個CPU成功啟動之前對這些區域的任何訪問都會導致不可預測的結果。
軟件中斷
前面提到兩個處理器都使用 OCM 來相互通信。而OCM屬于兩個CPU共用的資源,如果同時調用會出現問題,所以為了防止共享資源出現問題,可以進行使用中斷的辦法進行控制。也即讓CPU0在完成對OCM的相關操作并完成釋放OCM后,產生軟件中斷,CPU1接收到軟件中斷即可知道CPU0完成對OCM的操作,即可進行CPU1的對OCM的相關操作。
每個CPU都有一組私有外設中斷(PPls),它們使用存儲的reqisters進行私有訪問。PPls包括全局定時器、私有看門狗定時器、私有定時器和來自PL的FIQ/IRQ。軟件生成的中斷(SGIs)被路由到一個或兩個cpu。SGIs是通過寫入通用中斷控制器(GIC)中的寄存器而生成的。共享外圍中斷(SPls)是由PS和PL中的各種I/O和內存控制器產生的。它們被路由到其中一個或兩個cpu。來自PS外圍設備的SPI中斷也被路由到PL。
通過一個SGI (software generated interrupt,軟件生成中斷),每個CPU可以中斷自己,也可以中斷另一個CPU,也可以中斷兩個CPU。軟件生成中斷共有16個,如表所示。
通過將SG中斷號寫入ICDSGIR寄存器并指定目標CPU,生成一個SGl。這個寫操作通過CPU自己的私有總線進行。每個CPU都有自己的一組SGl寄存器,用于生成16個軟件生成的中斷中的一個或多個。通過讀取ICCIAR(中斷確認)寄存器或在ICDICPR(中斷清除等待)寄存器的相應位寫一個1來清除中斷。所有的SGis都是邊緣觸發。sgl的靈敏度類型是固定的,不能改變;ICDICFRO寄存器是只讀的,因為它指定了所有16個sgl的敏感類型。
OCM
OCM模塊包含256kb的RAM和128kb的ROM (BootROM)。它支持兩個64位的axis從接口端口,一個專用于通過APU snoop控制單元(SCU)的CPU/ACP訪問,另一個由處理系統(PS)和可編程邏輯(PL)中的所有其他總線主共享。BootROM內存只被引導進程使用,用戶不可見。
OCM分布
OCM分布在兩個區域,一個是地址的開始端,有連續的3個64k字節的存儲空間,另外一個在最后,用戶可以根據自己的傳輸交互的數據量大小進行選擇使用哪一塊存儲空間。
程序設計
見下篇 ZYNQ-雙核AMP通信(二)。