双核运行原理
zynq是一种主从关系的amp架构,通过松散耦合共享资源,允许两个处理器同时运行自己的操作系统或者裸机应用程序,在各自运行自己的程序或者系统的时候,可以通过共享内存进行双核之间的交互。双核启动中,cpu0完成系统的初始化,与cpu1进行通信,读写共享内存。
共享资源防止冲突
1. ddr的内存使用,cpu0使用内存地址为0x00100000-0x001fffff,cpu1的使用地址应该避开这段地址,使用地址设为0x00200000-0x003fffff;
2. cpu1不使用l2内存,仅仅cpu0使用;
3. cpu1从核心在pl的中断路由到ppi控制器,通过使用ppi将中断路由到核心,而cpu0通过icd路由到核心;
4. 当cpu0访问共享内存的时候,cpu1不访问,同理,cpu1访问共享内存的时候,cpu0不访问。
双核运行的过程
zynq是一个可扩展平台,就是有fpga作为外设的a9双核处理器,它的启动流程与fpga完全不同,而与传统的arm处理器类似,zynq的启动配置需要多个处理步骤,通常情况,需要包含以下3个阶段:
1. 阶段1:在芯片上电运行后,处理器自动开始stage0-boot,就是片内的boorrom中的代码,上电复位或者热复位后,处理器执行不可修改的代码;
2. 阶段2:boorrom初始化cpu和一些外设后,读取下一个阶段所需的程序代码fsbl(first stage boot loader),它是可以由用户修改控制的代码;
3. 阶段3:这是用户基于bsp(板级支持包),也可以是操作系统的启动引导程序,这个阶段完全是在用户的控制下实现的。
系统上电启动后,第0阶段启动代码判断启动模式,将第一阶段启动代码fsbl下载到ddr中并且执行。fsbl会配置硬件比特流文件,加载cpu0可执行文件和cpu1可执行文件到ddr对应的链接地址,在这一阶段,所有代码在cpu0中执行,在执行cpu0程序的时候,把cpu1上将要执行的应用程序执行地址写入到ocm的0xfffffff0地址,然后执行 sev汇编指令,激活cpu1,cpu1激活后,将会到ocm的0xfffffff0地址读取其数值,其数值就是cpu1执行可执行程序的地址,cpu1将从该地址执行。
双核运行的配置
建立工程的区别
核0建立工程和以前一样,但是核1建立工程与以前不同,需要单独建立一个板级支持包bsp。建立cpu1的板级支持包步骤:
1. 在sdk主界面主菜单下,选择file->new->board support package;
2. 出现“new board support package project”对话框,如图1所示;
图1 新建cpu1板级支持包
点击finish建立好支持包后,出现“board support package settings”对话框,在界面左侧窗口中,展开overview,在展开项中,找到并展开drivers,找到ps_cortexa9_1,并选择它;
在右侧的configuration for os界面中,找到名字为extra_compiler_flags一行,将其对应的value一列的值改为-g –duse_amp_ = 1,如图2所示;
图2 板级开发包的属性设置
建立好板级开发包后,建立cpu1的sdk工程,该工程的配置与和0也有不同,就是在新建工程对话框的参数配置要与核0不同,其核心选择核心1,板级支持包选择刚刚建立的cpu1的板级支持包(proccessor:ps7_cortexa9_1;borad support package:app_cpu1_bsp),建立好双核的应用工程和板级开发包后,进行软件的设计。
软件设计
1. cpu0的软件,在fsbl启动cpu0程序后,其程序需要增加启动cpu1的流程代码;
2. cpu0和cpu1的软件需要有一片共享内存,该内存不能被cache化;
3. 通过共享内存的分时访问,设计两个cpu的程序流程。
增加启动cpu1的代码如下:
#define sev() __asm__(sev)
#define cpu1startaddr 0xfffffff0
#define cpu1startmem 0x10000000
void startcpu1(void)
{
xil_out32(cpu1startaddr,cpu1startmem);
dmb();
sev();
}
禁用共享内存的代码:
#define comm_val (*(volatile unsigned long *)(0xffff0000))
xil_settlbattributes(0xffff0000,0x14de2);
双核源码与测试
利用共享内存做通讯的例子
cpu0代码:
#include stdio.h
#include xil_io.h
#include xil_mmu.h
#include xil_exception.h
#include xpseudo_asm.h
#include sleep.h
#define comm_val (*(volatile unsigned long *)(0xffff0000))
#define sev() __asm__(sev)
#define cpu1startaddr 0xfffffff0
#define cpu1startmem 0x10000000
void startcpu1(void)
{
xil_out32(cpu1startaddr,cpu1startmem);
dmb();
sev();
}
int main(void)
{
xil_settlbattributes(0xffff0000,0x14de2);
startcpu1();
comm_val = 0;
while(1)
{
print(cpu0:hello world cpu0/r/n);
sleep(2);
comm_val = 1;
while(comm_val == 1);
}
return 0;
}
cpu1代码:
#include stdio.h
#include xil_io.h
#include xil_mmu.h
#include xil_exception.h
#include xpseudo_asm.h
#include xparameters.h
#include sleep.h
#define comm_val (*(volatile unsigned long *)(0xffff0000))
int main(void)
{
xil_settlbattributes(0xffff0000,0x14de2);
while(1)
{
while(comm_val == 0);
print(cpu1:hello world cpu1/r/n);
sleep(2);
comm_val = 0;
}
return 0;
}
测试结果:
将上述程序生成boot.bin文件,然后下载到flash,启动后通过串口助手可以收到cpu0与cpu1的打印信息,每间隔两秒打印一次,如图3所示。
图3 程序测试
利用软件中断做通讯的例子
该例子中,cpu0和cpu1都注册两个软件中断,将1号软件中断注册给cpu1,表示cpu0发送中断给cpu1,将2号软件中断注册给cpu0,表示cpu1发送中断给cpu0;然后在程序运行时,cpu0触发1号软件中断,此时cpu1正在运行主程序被该中断中断,进入中断服务函数,其处理完中断后触发2号软件中断,此时该中断会中断cpu0,进入中断服务函数,cpu0处理完中断后回到主函数,再触发1号软件中断,往复运行。
cpu0代码:
/*
* app_cpu0.c
*
* created on: 2019年3月27日
* author: dz
*/
#include xil_cache.h
#include xparameters.h
#include xil_mmu.h
#include xil_misc_psreset_api.h
#include xil_exception.h
#include xscugic.h
#include xuartps.h
#include stdio.h
#include sleep.h
volatile u8 software_intr_received = 0;
#define core0_to_core1_intr_id 0x01
#define core1_to_core0_intr_id 0x02
void sys_intr_init(void);
void setup_intr_exception(xscugic * intcinstanceptr);
void scu_intr_init(xscugic* intanceptr,int scu_int_id);
void init_software_intr(xscugic *gicinstanceptr, xil_interrupthandler intrhanedler, u16 softwareintrid, u8 cpuid);
void gen_software_intr(xscugic *gicinstanceptr, u16 softwareintrid, u32 cpuid);
void cpu0_intr_hanedler(void *callback);
void cpu1_intr_hanedler(void *callback);
xscugic scugic;
void delay(unsigned int count)
{
int i = 0;
for(i = 0;i
}
int main(void)
{
sys_intr_init();
xil_printf(cpu0 start!/r/n);
while(1)
{
if(xpar_cpu_id == 0)
gen_software_intr(&scugic, core0_to_core1_intr_id, xscugic_spi_cpu1_mask);
/*gen_software_intr(&scugic, core0_to_core1_intr_id, xscugic_spi_cpu0_mask);*/
else
gen_software_intr(&scugic, core1_to_core0_intr_id, xscugic_spi_cpu0_mask);
delay(200000000);
if(1 == software_intr_received)
{
xil_printf(cpu0_main/r/n);
software_intr_received = 0;
}
}
return 0;
}
void sys_intr_init(void)
{ scu_intr_init(&scugic,xpar_scugic_single_device_id);
// if(xpar_cpu_id == 0)
init_software_intr(&scugic, cpu0_intr_hanedler, core0_to_core1_intr_id, 0);
// else
init_software_intr(&scugic, cpu1_intr_hanedler, core1_to_core0_intr_id, 1);
setup_intr_exception(&scugic);
}
void setup_intr_exception(xscugic * intcinstanceptr)
{
//connect hardware interrupt
xil_exceptioninit();
xil_exceptionregisterhandler(xil_exception_id_int,(xil_exceptionhandler)xscugic_interrupthandler,(void *)intcinstanceptr);
//enable hardware interrupt
xil_exceptionenable();
}
void scu_intr_init(xscugic* intanceptr,int scu_int_id)
{
xscugic_config *scuconfigptr;
//find device
scuconfigptr = xscugic_lookupconfig(scu_int_id);
//config scuint
xscugic_cfginitialize(intanceptr, scuconfigptr,scuconfigptr->cpubaseaddress);
}
void cpu0_intr_hanedler(void *callback)
{
xil_printf(receive interrupt from core1!/r/n);
software_intr_received = 1;
}
void cpu1_intr_hanedler(void *callback)
{
xil_printf(receive interrupt from core0!/r/n);
software_intr_received = 1;
}
void init_software_intr(xscugic *gicinstanceptr, xil_interrupthandler intrhanedler, u16 softwareintrid, u8 cpuid)
{
int status;
// xscugic_setprioritytriggertype(gicinstanceptr, softwareintrid, 0xb0, 0x2);
xscugic_setprioritytriggertype(gicinstanceptr, softwareintrid, 0xd0, 0x3);
status = xscugic_connect(gicinstanceptr, softwareintrid,
(xil_interrupthandler)intrhanedler, null);
if (status != xst_success) {
xil_printf(core%d: interrupt %d set fail!/r/n, xpar_cpu_id, softwareintrid);
return;
}
xscugic_interruptmaptocpu(gicinstanceptr, cpuid, softwareintrid); //map the the software interrupt to target cpu
xscugic_enable(gicinstanceptr, softwareintrid);//enable the interrupt for the software interrupt at gic
}
void gen_software_intr(xscugic *gicinstanceptr, u16 softwareintrid, u32 cpuid)
{
int status;
status = xscugic_softwareintr(gicinstanceptr, softwareintrid, cpuid);
if (status != xst_success) {
xil_printf(core%d: interrupt %d gen fail!/r/n, xpar_cpu_id, softwareintrid);
return;
}
}
cpu1代码:
/*
* app_cpu0.c
*
* created on: 2019年3月27日
* author: dz
*/
#include xil_cache.h
#include xparameters.h
#include xil_mmu.h
#include xil_misc_psreset_api.h
#include xil_exception.h
#include xscugic.h
#include xuartps.h
#include stdio.h
#include sleep.h
volatile u8 software_intr_received = 0;
#define core0_to_core1_intr_id 0x01
#define core1_to_core0_intr_id 0x02
void sys_intr_init(void);
void setup_intr_exception(xscugic * intcinstanceptr);
void scu_intr_init(xscugic* intanceptr,int scu_int_id);
void init_software_intr(xscugic *gicinstanceptr, xil_interrupthandler intrhanedler, u16 softwareintrid, u8 cpuid);
void gen_software_intr(xscugic *gicinstanceptr, u16 softwareintrid, u32 cpuid);
void cpu0_intr_hanedler(void *callback);
void cpu1_intr_hanedler(void *callback);
xscugic scugic;
void delay(unsigned int count)
{
int i = 0;
for(i = 0;i
;
}
int main(void)
{
sys_intr_init();
// gen_software_intr(&scugic, core1_to_core0_intr_id, xscugic_spi_cpu1_mask);
xil_printf(cpu1 start!/r/n);
while(1)
{
if(1 == software_intr_received)
{
software_intr_received = 0;
if(xpar_cpu_id == 0)
gen_software_intr(&scugic, core0_to_core1_intr_id, xscugic_spi_cpu1_mask);
/* gen_software_intr(&scugic, core0_to_core1_intr_id, xscugic_spi_cpu0_mask);*/
else
gen_software_intr(&scugic, core1_to_core0_intr_id, xscugic_spi_cpu0_mask);
delay(200000000);
xil_printf(cpu1_main/r/n);
}
}
return 0;
}
void sys_intr_init(void)
{ scu_intr_init(&scugic,xpar_scugic_single_device_id);
// if(xpar_cpu_id == 0)
init_software_intr(&scugic, cpu0_intr_hanedler, core0_to_core1_intr_id, 0);
// else
init_software_intr(&scugic, cpu1_intr_hanedler, core1_to_core0_intr_id, 1);
setup_intr_exception(&scugic);
}
void setup_intr_exception(xscugic * intcinstanceptr)
{
//connect hardware interrupt
xil_exceptioninit();
xil_exceptionregisterhandler(xil_exception_id_int,(xil_exceptionhandler)xscugic_interrupthandler,(void *)intcinstanceptr);
//enable hardware interrupt
xil_exceptionenable();
}
void scu_intr_init(xscugic* intanceptr,int scu_int_id)
{
xscugic_config *scuconfigptr;
//find device
scuconfigptr = xscugic_lookupconfig(scu_int_id);
//config scuint
xscugic_cfginitialize(intanceptr, scuconfigptr,scuconfigptr->cpubaseaddress);
}
void cpu0_intr_hanedler(void *callback)
{
xil_printf(receive interrupt from core1!/r/n);
software_intr_received = 1;
}
void cpu1_intr_hanedler(void *callback)
{
xil_printf(receive interrupt from core0!/r/n);
software_intr_received = 1;
}
void init_software_intr(xscugic *gicinstanceptr, xil_interrupthandler intrhanedler, u16 softwareintrid, u8 cpuid)
{
int status;
xscugic_setprioritytriggertype(gicinstanceptr, softwareintrid, 0xb0, 0x2);
// xscugic_setprioritytriggertype(gicinstanceptr, softwareintrid, 0xd0, 0x3);
status = xscugic_connect(gicinstanceptr, softwareintrid,
(xil_interrupthandler)intrhanedler, null);
if (status != xst_success) {
xil_printf(core%d: interrupt %d set fail!/r/n, xpar_cpu_id, softwareintrid);
return;
}
xscugic_interruptmaptocpu(gicinstanceptr, cpuid, softwareintrid); //map the the software interrupt to target cpu
xscugic_enable(gicinstanceptr, softwareintrid);//enable the interrupt for the software interrupt at gic
}
void gen_software_intr(xscugic *gicinstanceptr, u16 softwareintrid, u32 cpuid)
{
int status;
status = xscugic_softwareintr(gicinstanceptr, softwareintrid, cpuid);
if (status != xst_success) {
xil_printf(core%d: interrupt %d gen fail!/r/n, xpar_cpu_id, softwareintrid);
return;
}
}
将上述程序生成boot.bin文件,然后下载到flash,启动后通过串口助手可以收到cpu0与cpu1的打印信息,每间隔两秒打印一次,如图4所示。
图4 测试结果
研究人员已开发出一种低温集成电路来控制量子比特
网络安全系统是云计算时代的基础设施,保卫网络安全不可避免
电子设备防护雷电的基本方法介绍
泰科电子研发新一代小型化混合型标准线对板连接器
英特尔支持PCIe 4.0的SSD样本,测试只能用AMD的CPU?
ZYNQ开发双核运行原理及过程
诺基亚3310复刻版上手 贪吃蛇玩起来怎么样?
Tower花费5000万美元来提升以色列的晶圆厂产量
可穿戴设备市场难道只是看上去很美,或者只是昙花一现?
怎样用XBox控制器通过wifi控制RC汽车
KUKA机器人2轴平衡配重拆卸技巧
物联网发展还远远没有到大数据的阶段
风力发电液压刹车系统位移传感器IGS-DAB系列
我的天科技AR商标将新型科技和传统商标结合将产生无限的可能
太空机器人在空间站会干什么
南湖区领导莅临赛思总部考察指导工作
利雅得开春大戏剧情剖析
伯克利大学教授说:相对于传统的加密货币,比特币“极不稳定”
iic china展IMS分析师解读今年LED市场机会与挑战
VR全景技术将助力打造虚拟现实智慧城市