ZYNQ的AMP模式下,一种可以在线调试的重启CPU1的方法

本文探讨了ZYNQ AMP模式中CPU1软件复位后的引导问题,详细介绍了如何通过修改特定内存地址的指令,使CPU1在复位后能够进入等待状态(WFE),并通过设置0xFFFFFFF0处的值实现正确的代码跳转,解决了在线调试时FSBL未加载导致的引导难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题背景

ZYNQ的AMP模式开发中,常常会需要对CPU1进行software Reset ,reset之后的引导是一个比较麻烦的问题。

按照官方手册的介绍,software Reset之后,CPU1会跳到0x00地址处执行。正常工作的情况下,0x00处加载的是FSBL的代码,由BSP中的boot.s来实现CPU ID的识别和代码跳转。当需要XSDK通过JTAG在线调试时,FSBL并不会加载,此时0x00处的代码未知,若对CPU1执行Reset,将无法正确实现跳转。

解决思路

按照XAPP1079的处理方式,在POR复位整个系统时,bootrom会使CPU1进入WFE状态,不断检查0xFFFFFFF0处的值是否为0,若不为0则跳转到该值指示的地址执行。所以此时只需向0xFFFFFFF0写入CPU1的代码起始地址并发送sev即可实现CPU1的重新引导。
遗憾的是,Software Reset会使CPU1直接从0x00处执行,并不会走bootrom进入WFE状态。所以思路是模仿bootrom的这一套流程,在Reset CPU1之前,通过用户代码向0x00等区域写入跳转代码,实现重启后进入WFE状态的功能。

具体办法

//重启CPU1之前执行,为进入WFE做准备
void CPU1_WfePre() {
    //向0xFFFFFF00起始的地址写入WFE指令
    Xil_Out32(0xFFFFFF00, 0xe3e0000f);
    Xil_Out32(0xFFFFFF04, 0xe3a01000);
    Xil_Out32(0xFFFFFF08, 0xe5801000);
    Xil_Out32(0xFFFFFF0C, 0xe320f002);
    Xil_Out32(0xFFFFFF10, 0xe5902000);
    Xil_Out32(0xFFFFFF14, 0xe1520001);
    Xil_Out32(0xFFFFFF18, 0x0afffffb);
    Xil_Out32(0xFFFFFF1C, 0xe1a0f002);
    
    //向0x00写入跳转代码指向0xFFFFFF00  
    Xil_Out32(0x00000000, 0xe3e0f0ff);
    
    //清0xFFFFFFF0
    Xil_Out32(0xFFFFFFF0, 0x00000000);
    
    dmb();
}

其中,向0xFFFFFF00处写入数据对应的指令为:

ffffff00:   mvn     r0, #15
ffffff04:   mov     r1, #0
ffffff08:   str     r1, [r0]
ffffff0c:   wfe
ffffff10:   ldr     r2, [r0]
ffffff14:   cmp     r2, r1
ffffff18:   beq     -20     ; addr=0xffffff0c
ffffff1c:   mov     pc, r2
  •  

可见实际就是由这段代码实现的检查0xFFFFFFF0的内容并跳转

重启CPU1的代码,参考XAPP1079即可

{
    	/*
    	 *  Reset and start CPU1
    	 *  - Application for cpu1 exists at 0x00000000 per cpu1 linkerscript
    	 *
    	 */
		#include "xil_misc_psreset_api.h"
		#include "xil_io.h"

    	#define A9_CPU_RST_CTRL		(XSLCR_BASEADDR + 0x244)
		#define A9_RST1_MASK 		0x00000002
		#define A9_CLKSTOP1_MASK	0x00000020
		#define CPU1_CATCH			0x00000024

		#define XSLCR_LOCK_ADDR		(XSLCR_BASEADDR + 0x4)
		#define XSLCR_LOCK_CODE		0x0000767B

    	u32 RegVal;


    	/*
    	 * Setup cpu1 catch address with starting address of app_cpu1. The FSBL initialized the vector table at 0x00000000
    	 * using a boot.S that checks for cpu number and jumps to the address stored at the
    	 * end of the vector table in cpu0_catch and cpu1_catch entries.
    	 * Note: Cache has been disabled at the beginning of main(). Otherwise
		 * a cache flush would have to be issued after this write
    	 */
    	Xil_Out32(CPU1_CATCH, APP_CPU1_ADDR);


    	/* Unlock the slcr register access lock */
    	Xil_Out32(XSLCR_UNLOCK_ADDR, XSLCR_UNLOCK_CODE);

    	//    the user must stop the associated clock, de-assert the reset, and then restart the clock. During a
    	//    system or POR reset, hardware automatically takes care of this. Therefore, a CPU cannot run the code
    	//    that applies the software reset to itself. This reset needs to be applied by the other CPU or through
    	//    JTAG or PL. Assuming the user wants to reset CPU1, the user must to set the following fields in the
    	//    slcr.A9_CPU_RST_CTRL (address 0xF8000244) register in the order listed:
    	//    1. A9_RST1 = 1 to assert reset to CPU0
    	//    2. A9_CLKSTOP1 = 1 to stop clock to CPU0
    	//    3. A9_RST1 = 0 to release reset to CPU0
    	//    4. A9_CLKSTOP1 = 0 to restart clock to CPU0

    	/* Assert and deassert cpu1 reset and clkstop using above sequence*/
    	RegVal = 	Xil_In32(A9_CPU_RST_CTRL);
    	RegVal |= A9_RST1_MASK;
    	Xil_Out32(A9_CPU_RST_CTRL, RegVal);
    	RegVal |= A9_CLKSTOP1_MASK;
    	Xil_Out32(A9_CPU_RST_CTRL, RegVal);
    	RegVal &= ~A9_RST1_MASK;
		Xil_Out32(A9_CPU_RST_CTRL, RegVal);
    	RegVal &= ~A9_CLKSTOP1_MASK;
		Xil_Out32(A9_CPU_RST_CTRL, RegVal);

    	/* lock the slcr register access */
    	Xil_Out32(XSLCR_LOCK_ADDR, XSLCR_LOCK_CODE);
    }

参考:What is the state of CPU1 after a software reset through SLCR.A9_CPU_RST_CTRL

<think>好的,我现在需要回答用户关于在Zynq AMP模式下验证CPU1中断触发正确性的问题。首先,我得回想一下Zynq AMP模式的基本概念。AMP是Asymmetric Multiprocessing,即非对称多处理,两个CPU核心独立运行不同的操作系统或裸机程序,共享部分资源。这时候中断的管理需要特别注意,因为两个核心可能都需要处理中断,但配置不当会导致冲突或者无法触发。 用户的问题是如何验证CPU1的中断触发是否正确。那我得先了解在AMP模式下,中断控制器(GIC)的配置。Zynq的中断分为SPI(共享外设中断)和PPI(私有外设中断)。通常,CPU0和CPU1的中断需要正确分配到各自的核,尤其是当它们运行不同系统时,需要避免中断被错误地路由或屏蔽。 接下来,我应该考虑验证的步骤。首先,确认中断控制器的配置是否正确,比如分配特定的中断源给CPU1。然后,编写测试程序,在CPU1上注册中断服务程序(ISR),并触发该中断,观察是否能正确进入ISR。可能需要使用硬件调试工具,比如逻辑分析仪或者JTAG,来监测中断信号的实际触发情况。同时,软件方面可以通过打印日志或点亮LED来确认中断处理函数的执行。 另外,共享资源的使用需要注意同步机制,比如使用硬件信号量或者内存中的共享区域来协调两个CPU核心的操作,避免竞争条件。例如,在触发中断前,CPU0可能需要设置一个标志位,CPU1在中断处理中检查这个标志位,确保中断是由预期的事件触发的。 还有,用户可能需要知道具体的技术细节,比如如何配置GIC的寄存器,如何设置中断优先级和处理器目标。例如,GIC的Distributor寄存器需要配置来将某个中断分配到CPU1。同时,在CPU1的代码中,需要使能中断,并编写对应的ISR。 可能的验证方法包括软件触发中断,比如通过软件生成中断(SGI),这种中断可以定向到特定的CPU核心,从而测试CPU1的中断响应能力。此外,使用外设如GPIO产生硬件中断,观察CPU1是否能正确处理。 还需要考虑缓存一致性的问题,尤其是在两个核心共享内存时,确保中断触发信号和相关的状态标志在内存中的更新能被正确同步。可能需要使用内存屏障指令或者缓存维护操作。 最后,总结步骤可能包括:配置GIC,编写测试程序,使用软件或硬件触发中断,监控中断响应,验证ISR的执行,以及检查共享资源的同步情况。同时,引用相关的文档或资料,比如Xilinx的UG585手册,来支持这些步骤的正确性。</think>在Zynq AMP模式下验证CPU1的中断触发正确性,需结合硬件配置与软件调试。以下是分步验证方法: --- ### **1. 中断控制器(GIC)配置** - **分配中断源**:在GIC Distributor中,将目标中断(如PPI或SPI)配置为仅由CPU1处理。例如,通过设置`ICDIPTR`寄存器指定中断目标CPU[^1]。 - **使能中断**:在CPU1的中断控制器(GIC CPU Interface)中使能中断响应,例如设置`ICCICR`寄存器。 --- ### **2. 编写测试程序** - **CPU1的中断服务程序(ISR)**:在CPU1的代码中注册ISR,并在其中添加标志位修改或日志输出(如通过UART打印消息)。 ```c void __irq test_isr(void) { // 清除中断标志 *(volatile uint32_t*)INTC_Clear_Reg = 1; // 记录中断触发 printf("CPU1中断触发成功\n"); } ``` - **共享内存同步**:在共享内存中定义状态变量(如`flag`),CPU0触发中断前修改`flag`,CPU1在ISR中验证`flag`值。 --- ### **3. 触发中断** - **软件触发(SGI)**:从CPU0发送软件生成中断(SGI)到CPU1,例如通过写`ICDSGIR`寄存器[^1]。 ```c // CPU0代码 *(volatile uint32_t*)ICDSGIR = (1 << 16) | (IRQ_ID &amp; 0xF); // 发送SGI到CPU1 ``` - **硬件触发**:配置外设(如GPIO)产生中断信号,观察CPU1是否响应。 --- ### **4. 调试与验证** - **逻辑分析仪**:监测中断信号线(如IRQ引脚)的电平变化,确认中断是否被触发。 - **JTAG调试**:通过JTAG连接CPU1,单步执行代码并观察ISR是否被调用。 - **日志输出**:通过UART或共享内存输出调试信息,确认ISR执行路径。 --- ### **5. 同步机制检查** - **信号量/锁**:若使用共享资源(如DDR、外设),需验证硬件信号量(如SLCR寄存器)或原子操作是否避免竞争。 - **缓存一致性**:确保共享内存区域配置为“非缓存”或通过`Xil_DCacheFlush()`同步数据。 --- ### **常见问题** - **中断未触发**:检查GIC配置、中断优先级和CPU1的中断全局使能位。 - **ISR未执行**:确认向量表地址正确,且未因内存保护(如MMU)导致访问异常。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值