ZEDBOARD运行AMP总结

(1)参考XAPP1078,修改FSBL,加入DUMMY。
修改FSBL,支持load多个elf,直到遇到标志LOAD地址后,停止load,并返回。之后运行SSBL。

(2)参考UG1186,使用openAMP。
在linux中支持RPMSG,使得linux在CPU0上面启动后,由linux加载CPU1所需要的elf,并由linux启动CPU1。

(3)参考XAPP1079,下载repo,并放置到VIVADO SDK 2017.4中。
新建FSBL时,选择FSBL for AMP。
需要分别建立两个CPU的APP项目,其中CPU1的向导中要注意处理器选项选择CPU1。
CPU1的BSP SETTING需增加-DUSE_AMP=1。该编译选项将影响到CORE1工程代码里中断控制器SCUGIC的初始化函数以及Cache操作函数的编译,若不增加该选项,可能会出现CORE0和CORE1中断异常和Cache一致性维护异常。
每个CPU的APP项目的src目录中按照自己预想的存储器分配方案修改lscript.ld文件中的内容,千万注意不要让两个CPU的DDR地址重合,因为你APP的ELF文件是加载到DDR中执行的。由于没有OS,ELF肯定是加载到每个CPU的DDR起始地址。如果有重合那么一个CPU的ELF会覆盖另一个的。
一旦我们为内核创建了应用程序,我们需要正确的定义DDR内存的映射地址,因为程序将从这些地址开始执行。我们需要编辑链接脚本,如下图所示显示除了 DDR内存的基地址和大小。这一步很重要,如果我们不能正确的为Core 0和 Core 1定义内存地址和大小,在程序执行的过程中就会产生内核间的冲突,出现段地址错误。

(4)自己动手,移植修改SDK的SRC。(推荐!)
直接在standalone_v6_5源码上进行修改。
通过新建一个工程,并打开System.mss,我们可以发现,在SDK2017.4下,OS type只能选择standalone version 6.5.
所以,我们要移植的standalone_amp,也是复制的6.5版本的源码。
另存为standalone_amp_6_5。并在repo中添加。

然后修改其中的某些文件。

我们的依据,是xapp1078的说明文档。
standalone BSP.
Note: The standalone v4.2 BSP was modified as follows:
- armcc/_sys_write.c, gcc/write.c, printc, xil_printf.c: These changes add a new define ‘STDOUT_REDIR’
that prevents the removal of calls to outbyte() if STDOUT_BASEADDRESS is not defined
- armcc/boot.S, gcc/boot.S: These changes remove remapping of virtual address 0x20000000 to physical
address 0x00000000, configures address 0x00000000-0x2fffffff to be unavailable, and disables sharing
and L2 cache on address 0x30000000-0x3fffffff. The startup code was also modified to allow redirecting
cpu0 or cpu1 to a different starting address (This redirecting ability is not used for xapp1078).
- xtime_l.c: The change to this file prevents re-initializing the global timer.
- asm_vectors.S: Two extra vectors are added at the end of the vector table and are used by the boot.S
redirecting code. (This redirecting ability is not used for xapp1078).

先进入SRC的目录。
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9

(a)STDOUT_REDIR 宏定义
在D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9\armcc_sys_write.c,
在D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\common\gcc\write.c, 中,

D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\common\print.c中,

D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\common\xil_printf.c中,

所有涉及到print打印函数的地方,都增加了对应的宏定义,如:

#if defined STDOUT_BASEADDRESS || STDOUT_REDIR
outbyte( *lp++);
#endif

双核通信过程:cpu1会通过xil_printf()函数将打印消息发送给cpu0,cpu0再通过系统uart1将打印消息发送给显示器。
bsp设置中,Select Overview->standalone and change stdin and stdout to None,没有定义输入输出端设备,即没有STDOUT_BASEADDRESS 宏。为了避免xil_printf()无效,才有了STDOUT_REDIR 宏定义。

(我的配置:在vivado中使能uart0:使用EMIO引脚,使能uart1:使用ps侧标准IO;在cpu1的bsp配置中使用uart0;

因此,不需要定义STDOUT_REDIR,demo也可以正常运行)

(b)D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9\armcc\boot.S
作用:限定cpu1的裸机程序不可访问低内存空间(保留给linux系统专用)
第一:将虚拟地址0x20000000重新映射到物理地址0x00000000 部分的代码注释(注意:sdk软件自带的standalone不会有这段代码,可忽略此步,这段代码可能是xilinx以前增加的)

第二:将地址0x00000000-0x2fffffff(768M)配置为不可用。注意:这里配置的DDR是1G,因此cpu1运行裸机程序的情况下,配置低768M给cpu0使用,cpu1只是用高256M。如果DDR是512M,分为模式应该是:384M+128M。

第三:设置0x30000000-0x3fffffff仅作为CPU1的内部使用。如果DDR是512M,因该是高128M。

//第一步:注释代码
//	/* In case of AMP, map virtual address 0x20000000 to 0x00000000  and mark it as non-cacheable */
//#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
 
	/* In case of AMP, mark address 0x00000000 - 0x2fffffff DDR as unassigned/reserved */
	/* and address 0x30000000 - 0x3fffffff DDR as inner cached only */
 
#if USE_AMP==1
 
//第二步:保留低768M(如果DDR是512M,可将768M修改为384M,cpu0也可以正常运行系统)
	ldr	r3, =0x2ff			  /* 768 entries to cover 768MB DDR */
	ldr	r0, =TblBase			/* MMU Table address in memory */
	ldr	r2, =0x0000			  /* S=b0 TEX=b000 AP=b00, 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 768MB is covered */
 
//第三步:设置高256M专为CPU1使用(如果DDR是512M,这里的256M需修改为128M)
	ldr	r3, =0x0ff			  /* 256 entries to cover 256MB DDR */
	movw r2, #0x4de6		  /* S=b0 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b1 */
                              //注意:CB为01:表示cpu1的MMU设置为了分段地址管理,不支持cache但支持buffer;mmu域是15;保护标志位为0;访问权限为11:可读可写;在ARMv5以上版本处理器中有定义,如果TEX等于1,表示系统支持写时分配cache,这里没有分配cache;s为0:表示此内存不共享!
	movt r2, #0x3000      /* S=b0, Section start for address 0x30000000 */
mmu_loop1:
	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_loop1			    /* loop till 256MB is covered */

AMP模式禁用L2 cache(必须)
作用:如果是AMP模式,cpu1就需要禁用L2 cache;(这段代码两个sdk源码均有,不需要用户添加)

/* For AMP, assume running on CPU1. Don't initialize L2 Cache (up to Linux) */
#if USE_AMP!=1
	ldr	r0,=L2CCCrtl			/* Load L2CC base address base + control register */
	mov	r1, #0				/* force the disable bit */
	str	r1, [r0]			/* disable the L2 Caches */
 
	ldr	r0,=L2CCAuxCrtl			/* Load L2CC base address base + Aux control register */
	ldr	r1,[r0]				/* read the register */
	ldr	r2,=L2CCAuxControl		/* set the default bits */
	orr	r1,r1,r2
	str	r1, [r0]			/* store the Aux Control Register */
 
	ldr	r0,=L2CCTAGLatReg		/* Load L2CC base address base + TAG Latency address */
	ldr	r1,=L2CCTAGLatency		/* set the latencies for the TAG*/
	str	r1, [r0]			/* store the TAG Latency register Register */
 
	ldr	r0,=L2CCDataLatReg		/* Load L2CC base address base + Data Latency address */
	ldr	r1,=L2CCDataLatency		/* set the latencies for the Data*/
	str	r1, [r0]			/* store the Data Latency register Register */
 
	ldr	r0,=L2CCWay			/* Load L2CC base address base + way register*/
	ldr	r2, =0xFFFF
	str	r2, [r0]			/* force invalidate */
 
	ldr	r0,=L2CCSync			/* need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET */
						/* Load L2CC base address base + sync register*/
......

(c)
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\bsp\standalone_amp_v6_5\src\arm\cortexa9\xtime_l.c修改(必须)
作用:在AMP模式下,global全局定时器肯定会在CPU0的系统中完成初始化,因此避免CPU1启动或是运行过程中CPU1重启时,将global全局定时器reset!

void XTime_SetTime(XTime Xtime)
{
 
#ifdef USE_AMP
	if(Xil_In32(GLOBAL_TMR_BASEADDR + GTIMER_CONTROL_OFFSET) && 0x1) {
		//Timer is already enabled so don't reset it
		return;
	}
#endif
	
	/* Disable Global Timer */
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_CONTROL_OFFSET, 0x0);
 
	/* Updating Global Timer Counter Register */
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_COUNTER_LOWER_OFFSET, (u32)Xtime);
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_COUNTER_UPPER_OFFSET,
		(u32)(Xtime>>32));
 
	/* Enable Global Timer */
	Xil_Out32(GLOBAL_TMR_BASEADDR + GTIMER_CONTROL_OFFSET, 0x1);
}

注意:
其中用到的宏,名字叫做USE_AMP,而网上很多帖子里,介绍FLAG时,是用的DUSE_AMP,有什么区别,还不清楚。

(d)修改FSBL的模板,修改为FSBL_AMP
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl文件夹,复制为D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl_amp。
在新文件夹中,
找到main.c文件打开,在里面添加下面一段代码,用于启动CPU1:

#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0 //这是ZYNQ约定的用来放CPU1的PC的指针地址
#define CPU1STARTMEM 0x20000000 // 这里可以修改为自己的地址
void StartCpu1(void)
{
    fsbl_printf(DEBUG_GENERAL,"FSBL: Write the address of the application for CPU 1 to 0xFFFFFFF0\n\r");
    Xil_Out32(CPU1STARTADR, CPU1STARTMEM);
    dmb(); //waits until write has finished
    fsbl_printf(DEBUG_GENERAL,"FSBL: Execute the SEV instruction to cause CPU 1 to wake up and jump to the application\n\r");
    sev();
}

再找到Load boot image的位置,将CPU1的启动函数,放置于此位置,改动后的代码段如下:

 /*
     * Load boot image
     */
    HandoffAddress = LoadBootImage();

    fsbl_printf(DEBUG_INFO,"Handoff Address: 0x%08lx\r\n",HandoffAddress);
    StartCpu1();   /*add starting cpu1*/

修改tcl和mss。
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl_amp\data\zynq_fsbl.tcl
D:\Xilinx\SDK\2017.4\data\embeddedsw\lib\sw_apps\zynq_fsbl_amp\data\zynq_fsbl.mss
先改名为zynq_fsbl_amp.tcl和zynq_fsbl_amp.mss。
然后修改其中的内容,把里面的“standalone”全部修改为“standAMP”。

修改BSP的SRC,将之前修改的AMP版本的BSP包,放在Thirdparty下。
D:\Xilinx\SDK\2017.4\data\embeddedsw\ThirdParty\bsp\standAMP_v6_5\data下,把文件名全部改为standAMP.*。
打开文件,把里面的"standalone"全部改为"standAMP"。

在preference里面,加入我们复制并修改好的repo。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值