개발 환경
Vivado 2014.4 환경에서 ZYNQ 이중 코어 베어메탈 구현 방법에 대해 설명한다.
특정 조건에서의 문제점
전체 DDR 메모리가 512MB를 초과하며, CPU0가 이미 512MB 이상을 사용하고 있는 경우, 다음 절차에 따라 CPU1을正式启动할 수 없다.
원인 분석
이러한 문제는 부트 엔트리 주소 제한으로 인해 발생한다. 기본적으로 MMU 테이블 설정이 512MB 영역으로 제한되어 있기 때문에, CPU0가 512MB 이상의 메모리를 사용하면 CPU1의 부트 영역이 올바르게 매핑되지 않는다.
해결 방법
CPU1의 BSP 소스 파일을 수정하여 MMU 테이블 설정 부분을 주석 처리해야 한다. 다음과 같이 파일을 편집한다:
편집 대상 파일 경로:
cpu1_bsp\ps7_cortexa9_1\libsrc\standalone_v4_2\src\boot.S
다음과 같이 해당 코드를 주석 처리한다:
#if USE_AMP==1
// ldr r3, =0x1ff /* 512 entries to cover 512MB DDR */
// ldr r0, =TblBase /* MMU Table address in memory */
// add r0, r0, #0x800 /* Address of entry in MMU table, for 0x20000000 */
// ldr r2, =0x0c02 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b0 */
//mmu_loop:
// str r2, [r0] /* write the entry to MMU table */
// add r0, r0, #0x4 /* next entry in the table */
// add r2, r2, #0x100000 /* next section */
// subs r3, r3, #1
// bge mmu_loop /* loop till 512MB is covered */
#endif
CPU1 시작 코드 구현
다음은 CPU1을唤醒하고 애플리케이션으로 점프시키는 함수이다:
#defineWAKE_CORE() __asm__("sev")
#define CORE1_BOOT_ADDR 0xFFFFFFF0
#define CORE1_LOAD_ADDR 0x3D000000
void CPU1_Start(void)
{
#if 1
print("Writing CPU1 boot address to hardware register\r\n");
Xil_Out32(CORE1_BOOT_ADDR, CORE1_LOAD_ADDR);
dmb();
print("Sending wake event to CPU1\r\n");
WAKE_CORE();
#endif
}
주요 상수 설명
CORE1_BOOT_ADDR: CPU1의 부트 레지스터 주소로, 하드웨어적으로 고정된 값이다CORE1_LOAD_ADDR: lscript.ld 파일에서 설정한 CPU1의 메모리 시작 주소이다
컴파일러 플래그 설정
프로젝트 빌드 시 다음 컴파일러 플래그를 추가해야 한다:
-DUSE_AMP=1
이 플래그는 AMP(Asymmetric Multi Processing) 모드를 활성화하는 데 사용된다.
CPU0 애플리케이션 코드
#include
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"
int main()
{
init_platform();
while(1)
{
print("CPU 0 : Hello World\r\n");
sleep(2);
}
cleanup_platform();
return 0;
}
CPU1 애플리케이션 코드
#include
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"
int main()
{
init_platform();
while(1)
{
print("CPU 1 : New World\r\n");
sleep(3);
}
cleanup_platform();
return 0;
}
주요 구현 포인트
- 메모리 영역 분리: CPU0와 CPU1이 사용하는 메모리 영역이 중복되지 않도록 명확히 분리해야 한다
- 부트 주소 설정: 0xFFFFFFF0 주소에 CPU1의 시작 주소를 쓰고, SEV 명령어로 CPU1을 깨운다
- 동기화 처리: dmb() 명령어로 메모리 쓰기 작업이 완료되도록 보장한다
참고사항
이 설정은 DDR 메모리가 512MB 이하인 일반적인 경우에는 필요하지 않다. 512MB 이상의 대용량 메모리를 사용하고, CPU0가 512MB 이상을 점유하는 특수한 환경에서만 위의 수정 사항이 필요하다.