ZYNQ包括一個 FPGA 和兩個 ARM,多個 ARM 核心相對獨立的運行不一樣的任務,每一個核心可能運行不一樣的操做系統或裸機程序,可是有一個主要核心,用來控制整個系統以及其餘從核心的容許。所以咱們能夠在 CPU0 和 CPU1 中獨立跑不一樣的應用程序,發揮雙核的非對稱性架構的優點和性能。架構
從軟件的角度來看,多核處理器的運行模式主要有三種:app
① AMP(非對稱多進程):多個核心相對獨立的運行不一樣的任務,每一個核心可能運行不一樣的操做系統或裸機程序,可是有一個主要核心,用來控制整個系統以及其它從核心的運行。函數
② SMP(對稱多進程):一個操做系統同等的管理各個內核,例如 PC 機。性能
③ BMP(受約束多進程):與 SMP 相似,但開發者能夠指定將某個任務僅在某個指定內核上執行默認狀況下。優化
裸機程序 ZYNQ 僅運行一個 CPU,這裏主要講解 AMP 模式下,兩個 CPU 同時運行的裸機程序開發方法。spa
1、核間中斷原理(軟中斷SGI)操作系統
軟中斷的 ID 都是從0到15,而且都是上升沿觸發,主要用於核間中斷或者 CPU 本身中斷本身。設計
中斷函數以下:3d
XScuGic_SoftwareIntr(&InterruptController, //指向GIC指針 INTC_CPU0, //須要中斷的CPU ID XSCUGIC_SPI_CPU0_MASK); //使能該CPU會接受中斷
2、ARM啓動過程指針
1.ARM 裏有個 ROM,存儲了一段程序,ROM起來後從 SD 卡讀取數據 2.啓動 FSBL(First Boot Loader)第一啓動項(有模板) 3.加載 bit(FPGA配置程序),同時加載 elf(ARM應用程序),若是是操做系統則 elf 替換成 uBoot
3、搭建軟件 CPU0 和 CPU1 非對稱環境
1.建立 amp_fsbl 用於生成燒寫鏡像的時候加載 core0 和 core1的代碼。
①啓動 Vivado,建立 ZYNQ,勾選 SD卡 和 UART 便可,並加載 SDK 開發環境
②進到 SDK ,點擊 File --- New --- Application Project,命名爲 amp_fsbl 並選擇 CPU0
③選擇 FSBL,finish
④修改 main.c 函數來啓動 core1,須要兩個步驟,首先把 CPU1 應用程序地址寫入到 0xfffffff0地址中,這是啓動 CPU1 命令的地址,而後執行 sev 指令加載 CPU1 應用程序。具體參考 UG585 的啓動代碼章節。
在 main.c 函數的 main 函數上方插入這段代碼:
1 #define sev() __asm__("sev") 2 #define CPU1STARTADR 0xFFFFFFF0 3 #define CPU1STARTMEM 0x2000000 4 5 void StartCpu1(void) 6 { 7 #if 1 8 fsbl_printf(DEBUG_GENERAL,"FSBL: Write the address of the application for CPU 1 to 0xFFFFFFF0\n\r"); 9 Xil_Out32(CPU1STARTADR, CPU1STARTMEM); 10 dmb(); //waits until write has finished 11 fsbl_printf(DEBUG_GENERAL,"FSBL: Execute the SEV instruction to cause CPU 1 to wake up and jump to the application\n\r"); 12 sev(); 13 #endif 14 }
在 main.c 函數的 load鏡像位置加入代碼: StartCpu1();
2.建立 app_cpu0 應用程序
①從新建立一個新的 File --- New --- Application Project,命名爲 app_cpu0,這時選擇的是 CPU0
②選擇 helloworld 模板便可
③將 helloworld.c 更名爲 mian.c,而且用以下代碼替換掉內容
1 #include <stdio.h> 2 #include "platform.h" 3 #include "xil_printf.h" 4 5 #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000)) //無優化無符號長整形地址轉成指針 6 7 int main() 8 { 9 COMM_VAL=0; 10 11 //Disable cache on OCM 12 Xil_SetTlbAttributes(0xFFFF0000,0x14de2); 13 while(1) 14 { 15 print("Hello World cpu0 \n\r"); 16 COMM_VAL =1; 17 while(COMM_VAL == 1) 18 { 19 } 20 } 21 return 0; 22 }
該指針指向的地址爲片上存儲的共享內存(OCM)。能夠指定這裏面的任意一個地址。定義的指針變量以下所示: #define COMM_VAL (*(volatile unsigned long *)(0x00020000)) 該變量CPU0和CPU1均可以在裏面讀寫數據,能夠達到CPU0和CPU1的數據交互。OCM的地址以下圖所示。
④打開 Scr 目錄中的文件 lscript.ld,點擊下方的 Source 作以下修改:CPU0 的代碼空間改成 1E00000
CPU1運行程序的地址改成fsbl裏面指定的起始地址。後面爲長度,有一點須要注意:CPU0的起始地址加上CPU0的長度以後不能超過CPU1的起始地址。也就是兩個CPU佔用的DDR的地址不能重疊。若程序很大,則CPU0須要的LENGTH就大,所以CPU1的起始地址數值就大。DDR地址範圍以下所示:
3.建立 app_cpu1 應用程序
①從新建立一個新的 File --- New --- Application Project,命名爲 app_cpu1,這時選擇的是 CPU1
②選擇 helloworld 模板便可
③將 helloworld.c 更名爲 mian.c,而且用以下代碼替換掉內容
1 #include <stdio.h> 2 #include "platform.h" 3 #include "xil_printf.h" 4 5 #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000)) 6 int main() 7 { 8 //Disable cache on OCM 9 Xil_SetTlbAttributes(0xFFFF0000,0x14de2); 10 while(1) 11 { 12 while(COMM_VAL == 0) 13 { 14 } 15 print("Hello World cpu1 \n\r"); 16 sleep(2); 17 COMM_VAL=0; 18 } 19 return 0; 20 }
④打開 Scr 目錄中的文件 lscript.ld 點擊下方的 Source 作以下修改起始地址改成 0x2000000 長度 0x1F00000
4.增長編譯選項(設置 CPU1 的BSP setting 爲 AMP 模式)
app_cpu1_bps --- 右鍵 --- Board Suport Package Setting,點擊 driver --- ps7_cortexa9_0,添加指令
5.讓雙核跑起來
①點擊 app_cpu0 --- 右鍵 --- Debug As --- Debug Configurations...
② 點擊選項卡的 Application,勾選 0 和 1,而後點擊 Debug,yes
③默認停到第一行,鏈接好串口,選擇APU --- ARM --- #0,單步慢慢走能夠看到有信息打印出,#2也是同樣的。若是讓 #0 和 #1 都一直執行,則串口會一直交替打印。
4、軟中斷的註冊和使用
參考資料:
[1]V3學院FPGA教程
[2]何賓, 張豔輝. Xilinx Zynq-7000嵌入式系統設計與實現[M]. 電子工業出版社, 2016.