建立一个helloworld工程,确保可以打印并可以实现下载到flash断电不丢失
然后取消勾选ddr,
ZYNQ 无DDR 启动
1 fsbl_bsp 相关修改
1.1 Translation_table.s
该文件位于E: …\fsbl_bsp\ps7_cortexa9_0\libsrc\standalone_v7_0\src 目录下
在文件第203-206 行内容屏蔽掉 并添加两段代码
原内容如下:
.rept 0x0020 /* 0xfc000000 - 0xfdffffff (Linear QSPI - XIP) */
.word SECT + 0xc0a /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b0 */
.set SECT, SECT+0x100000
.endr
修改后文本内容如下:
#if 0
.rept 0x0020 /* 0xfc000000 - 0xfdffffff (Linear QSPI - XIP) */
.word SECT + 0xc0a /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b0 */
.set SECT, SECT+0x100000
.endr
#endif
.rept 0x0007 /* 0xfc000000 - 0xfc6fffff (Linear QSPI - XIP) */
.word SECT + 0xc0a /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0019 /* 0xfc700000 - 0xfdffffff (Linear QSPI - XIP) */
.word SECT + 0x15de2 /* S=b0 TEX=b101 AP=b11, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
增加的代码使用了QSPI内部的存储空间,用于执行FSBL,这里将QSPI配置为线性模式,分为2段XIP,7MB和25MB。这与后面提到的产生BIN文件时使用XIP模块相对应,同时0XFC000000这个地址将会用在fsbl的lscript.ld中。
1.2 xil_exception.c
向向量表条目添加了XVtable 属性。
该文件第93行
原内容为:
XExc_VectorTableEntry XExc_VectorTable[XIL_EXCEPTION_ID_LAST + 1] =
添加 XVtable 属性 修改后如下:
XExc_VectorTableEntry XExc_VectorTable[XIL_EXCEPTION_ID_LAST + 1] __attribute__ ((section("XVtable"))) =
以上为 fsbl_bsp 修改内容
2 fsbl 相关修改
2.1main.c
原文第138行 添加头文件
#include "xil_cache_l.h"
#include "xl2cc.h"
2.1.2 添加 preload_func 和 copy 函数及一些宏定义等 具体内容如下:
添加在 221 行 main() 函数前面即可 该函数将应用程序代码加载到缓存中并锁定它。
添加内容如下:
#ifdef DDRLESS_SYSTEM
#define XPAR_PS7_DDR_0_S_AXI_BASEADDR
#define WAY_SIZE 65536
#define MAX_NUM_WAYS 8
/*****************************************************************************/
/**
*
* This function is used to preload and lock data in to L2 Cache.
*
*
* @param None.
*
* @return
* - XST_SUCCESS to indicate success
* - XST_FAILURE.to indicate failure
*
* @note
*
****************************************************************************/
int preload_funct(unsigned int uiSrcAddress, unsigned int uiSize)
{
// static unsigned int uiAlreadyProgrammed;
unsigned int i=0;
// unsigned int uiNumofWays=0;
// unsigned int uiVariable=0;
// unsigned int uiValue0=0;
// unsigned int uiValue1=0;
fsbl_printf(DEBUG_GENERAL,"\n\rInside Preload Functions \n\r");
// Disable FIQ and IRQ interrupt
Xil_ExceptionDisableMask(XIL_EXCEPTION_ALL);
/*
* UnLock Data and Instruction from way 1 to7 and unlock Data and instruction for Way 0.
* The PL310 has 8 sets of registers, one per possible CPU.
*/
for(i=0;i<8;i++)
{
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_DLCKDWN_0_WAY_OFFSET + (i*8)) ), (0x00000000));
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_ILCKDWN_0_WAY_OFFSET + (i*8)) ), (0x00000000));
}
/* Flush the Caches */
Xil_DCacheFlush();
Xil_DCacheInvalidate();
fsbl_printf(DEBUG_GENERAL,"\n\r Invalidate D cache \n\r");
/*Preload instruction from section starts from 0x31000000 to Cache Way 0*/
fsbl_printf(DEBUG_GENERAL,"Preload instructions uiSrcAddress = 0x%8x\n\r", uiSrcAddress);
fsbl_printf(DEBUG_GENERAL,"Preload instructions uiSize = 0x%8x\n\r", uiSize);
{
// Copy Applciation source adress to ro register
asm volatile ("mov r0,%0":: "r"(uiSrcAddress));
//Copy application size to r1 register
asm volatile ("mov r1,%0":: "r"(uiSize));
// Offset register i.e. r2
asm volatile ("mov r2, #0");
// Label
asm ("preload_inst:");
// Load r4 register from the r0+r2 (Source address + offset)
// This step create an valid entry of the address (Source address + offset) in L2 cache
asm volatile ("ldr r4, [r0,r2]");
// Increment the offset by one cache line
asm volatile ("add r2,r2,#4");
// Compare the offset with the Application size.
asm volatile ("cmp r1, r2");
// If not equal jump to Label
asm volatile ("bge preload_inst");
}
// lock both Data and instruction caches from Way 1 to 7.
// Lock Data and Instruction Caches for Way 0
for(i=0;i<8;i++)
{
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_DLCKDWN_0_WAY_OFFSET + (i*8)) ), 0xffff);
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_ILCKDWN_0_WAY_OFFSET + (i*8)) ), 0xffff);
}
fsbl_printf(DEBUG_GENERAL,"Lock both Data and instruction caches from Way 1 to 7\n\r");
// Enable all the Interrupts
Xil_ExceptionEnableMask(XIL_EXCEPTION_ALL);
// uiAlreadyProgrammed=uiVariable;
return - XST_SUCCESS;
}
#endif
extern char _image_start, _dataLMA, _dataVMA_start, _dataVMA_end, _vectorscopy, __vectors_start, __vectors_end;
extern char _dataXVtableLMA, _dataXVtableVMA_start,_dataXVtableVMA_end;
extern unsigned int _ncSTART_ADDR;
static void copy(char *src, char *dstStart, char *dstEnd) {
/* ROM has data at end of text; copy it. */
while (dstStart < dstEnd) {
*dstStart++ = *src++;
}
}
#define WRITE_VEC_BASE_ADDR(value) mtcp(XREG_CP15_VEC_BASE_ADDR,value)
#define READ_VEC_BASE_ADDR(value) value = mfcp(XREG_CP15_VEC_BASE_ADDR)
以上添加完毕后会有一些报错 是因为 lscript.ld 文件还未修改 因此一些变量还未定义 所以不必关心!!!!
添加在mian() 函数中 变量定义后 原文本第 242 行 上面的修改后在第 355行
添加的文本如下:
copy(&_dataLMA,&_dataVMA_start,&_dataVMA_end);
copy(&_dataXVtableLMA,&_dataXVtableVMA_start,&_dataXVtableVMA_end);
以上添加完毕后会有一些报错 是因为 lscript.ld 文件还未修改 因此一些变量还未定义 所以不必关心!!!!
main() 函数中
上面的内容添加后在第 411行
添加的文本如下
/*
* Print the FSBL Banner
*/
fsbl_printf(DEBUG_GENERAL,"\n\rXilinx First Stage Boot Loader \n\r");
fsbl_printf(DEBUG_GENERAL,"Release %d.%d %s-%s\r\n",
SDK_RELEASE_YEAR, SDK_RELEASE_QUARTER,
__DATE__,__TIME__);
/*****************************以下为添加的内容********上面是原来就有的*********************/
//fsbl_printf(DEBUG_GENERAL,"_image_start \t= 0x%8x\n\r", &_image_start);
fsbl_printf(DEBUG_GENERAL,"_dataLMA \t= 0x%8x\n\r", &_dataLMA);
fsbl_printf(DEBUG_GENERAL,"_dataVMA_start \t= 0x%8x\n\r", &_dataVMA_start);
fsbl_printf(DEBUG_GENERAL,"_dataVMA_end \t= 0x%8x\n\r", &_dataVMA_end);
//fsbl_printf(DEBUG_GENERAL,"_vectorscopy \t= 0x%8x\n\r", &_vectorscopy);
//fsbl_printf(DEBUG_GENERAL,"__vectors_start \t= 0x%8x\n\r", &__vectors_start);
//fsbl_printf(DEBUG_GENERAL,"__vectors_end \t= 0x%8x\n\r", &__vectors_end);
fsbl_printf(DEBUG_GENERAL,"_dataXVtableLMA \t= 0x%8x\n\r", &_dataXVtableLMA);
fsbl_printf(DEBUG_GENERAL,"_dataXVtableVMA_start \t= 0x%8x\n\r", &_dataXVtableVMA_start);
fsbl_printf(DEBUG_GENERAL,"_dataXVtableVMA_end \t= 0x%8x\n\r", &_dataXVtableVMA_end);
main() 函数中
上面的内容修改后 在第425 行
添加 DDRLESS_SYSTEM 条件
#ifndef DDRLESS_SYSTEM
#endif
添加后 内容如下:
#ifndef DDRLESS_SYSTEM
/*
* DDR Read/write test
*/
Status = DDRInitCheck();
if (Status == XST_FAILURE) {
fsbl_printf(DEBUG_GENERAL,"DDR_INIT_FAIL \r\n");
/* Error Handling here */
OutputStatus(DDR_INIT_FAIL);
/*
* Calling FsblHookFallback instead of Fallback
* since, devcfg driver is not yet initialized
*/
FsblHookFallback();
}
#endif
main() 函数中:
上面内容添加后在 该文件第535 行
文本如下:
FlashReadBaseAddress = XPS_QSPI_LINEAR_BASEADDR;
添加后 内容如下:
#ifdef MMC_SUPPORT
/*
* To support MMC boot
* QSPI boot mode detection ignored
*/
if (BootModeRegister == QSPI_MODE) {
BootModeRegister = MMC_MODE;
}
#endif
if (BootModeRegister == QSPI_MODE) {
fsbl_printf(DEBUG_GENERAL,"Boot mode is QSPI\n\r");
InitQspi();
MoveImage = QspiAccess;
FlashReadBaseAddress = XPS_QSPI_LINEAR_BASEADDR;//添加语句!!!!!!!在这里
fsbl_printf(DEBUG_INFO,"QSPI Init Done \r\n");
} else
#endif
main() 函数中
上面内容添加后在该文件第 703 行
添加内容如下:
Xil_L1DCacheEnable();
Xil_L1ICacheEnable();
Xil_L1DCacheInvalidate();
Xil_L1ICacheInvalidate();
fsbl_printf(DEBUG_GENERAL,"-> FsblFallback\n\r");
//OutputStatus(NO_DDR);
添加后 文本如下:
/*
* Load boot image
*/
HandoffAddress = LoadBootImage();
Xil_L1DCacheEnable();
Xil_L1ICacheEnable();
Xil_L1DCacheInvalidate();
Xil_L1ICacheInvalidate();
2.1.8 main() 最后去掉 OutputStatus(NO_DDR);
main() 函数中:
以上内容修改后 在文件第 726 行 在该函数最后 return 之前
原内容如下:
#else
OutputStatus(NO_DDR);
FsblFallback();
#endif
return Status;
修改后如下:
#else
fsbl_printf(DEBUG_GENERAL,"-> FsblFallback\n\r");/* 还添加了一个debug 语句 可以不要 */
//OutputStatus(NO_DDR);/* 这句话 !!! 屏蔽掉 */
FsblFallback();
#endif
return Status;
FsblHandoff() 函数中!!!!!
以上内容修改后 在该文件第 912 行
原内容如下:
Status = FsblHookBeforeHandoff();
修改后如下 添加了一个传入的参数 该修改后 也会报错!!!! 因为原函数还未更改!!!
Status = FsblHookBeforeHandoff(FsblStartAddr);
以上 至此 main.c文件修改完成
2.2 fsbl.h
该文件 537 行
main() 函数中添加了 preload_funct() 函数 该函数在其它文件中有调用 所以 添加一下 函数声明
添加内容如下:
int preload_funct(unsigned int uiSrcAddress, unsigned int uiSize);/* __attribute__ ((section ("ncmemory")));*/
2.3 fsbl_handoff.S
因为程序不在DDR中执行,需要修改FsblHandoffExit段
源文件第85 行 140 行 198行 该文件中有三处对 FsblHandoffExit段的定义 不知道具体用哪一个 就全部都修改了吧
修改后 文本如下:
FsblHandoffExit:
#ifdef DDRLESS_SYSTEM
mov lr, r0 /* move the destination address into link register */
bx lr /* force the switch, destination should have been in r0 */
#else
mov lr, r0 /* move the destination address into link register */
mcr 15,0,r0,cr7,cr5,0 /* Invalidate Instruction cache */
mcr 15,0,r0,cr7,cr5,6 /* Invalidate branch predictor array */
dsb
isb /* make sure it completes */
ldr r4, =0
mcr 15,0,r4,cr1,cr0,0 /* disable the ICache and MMU */
isb /* make sure it completes */
bx lr /* force the switch, destination should have been in r0 */
#endif
.Ldone: b .Ldone /* Paranoia: we should never get here */
.end
就是添加了一个
#ifdef DDRLESS_SYSTEM
mov lr, r0 /* move the destination address into link register */
bx lr /* force the switch, destination should have been in r0 */
#else
.......
#endif
不做任何处理 直接跳转
!!!!!! 三段 都修改!!!!
2.4 fsbl_hooks.c
mian() 函数中 FsblHookBeforeHandoff() 的使用添加了一个传入的参数 在该文件中修改 FsblHookBeforeHandoff 函数
源文件 在 第 126 行
该函数 原本内容如下:
u32 FsblHookBeforeHandoff(void)
{
u32 Status;
Status = XST_SUCCESS;
/*
* User logic to be added here.
* Errors to be stored in the status variable and returned
*/
fsbl_printf(DEBUG_INFO,"In FsblHookBeforeHandoff function \r\n");
return (Status);
}
修改后 该函数内容如下:
u32 FsblHookBeforeHandoff(u32 FsblStartAddr) {
u32 Status;
u32* ptr;
u32 i;
ptr = (u32*) FsblStartAddr;
Status = XST_SUCCESS;
/*
* User logic to be added here.
* Errors to be stored in the status variable and returned
*/
fsbl_printf(DEBUG_INFO, "In FsblHookBeforeHandoff function \r\n");
for (i = 0; i < 8; i++) {
fsbl_printf(DEBUG_INFO, "*(0x%x) = 0x%x\r\n", ptr, *(ptr));
ptr++;
}
fsbl_printf(DEBUG_INFO,
"Returning from FsblHookBeforeHandoff function \r\n");
return (Status);
}
这里还是会报错 因为 头文件中该函数的声明与 函数原型不符 下面就去头文件修改 该函数的声明
2.5 fsbl_hooks.h
文件第 68 行 函数修改了之后也要修改一下头文件中的函数声明
修改后内容如下:
u32 FsblHookBeforeHandoff(u32 FsblStartAddr);
2.6 image_mover.c
#include "xil_cache.h"
#include "xil_cache_l.h"
LoadBootImage() 函数中
以上修改后第 335 行
就是添加一个
#ifndef DDRLESS_SYSTEM
......
#endif
修改后 内容如下:
#ifndef DDRLESS_SYSTEM
/*
* Partition owner should be FSBL to validate the partition
*/
if ((PartitionAttr & ATTRIBUTE_PARTITION_OWNER_MASK) !=
ATTRIBUTE_PARTITION_OWNER_FSBL) {
/*
* if FSBL is not the owner of partition,
* skip this partition, continue with next partition
*/
fsbl_printf(DEBUG_INFO, "Skipping partition %0lx\r\n",
PartitionNum);
/*
* Increment partition number
*/
PartitionNum++;
continue;
}
#endif
LoadBootImage() 函数中
以上修改后在文件第 421 行
还是添加一个
#ifndef DDRLESS_SYSTEM
......
#endif
修改后内容如下:
/*
* Load address check
* Loop will break when PS load address zero and partition is
* un-signed or un-encrypted
*/
#ifndef DDRLESS_SYSTEM
if ((PSPartitionFlag == 1) && (PartitionLoadAddr < DDR_START_ADDR)) {
if ((PartitionLoadAddr == 0) &&
(!((SignedPartitionFlag == 1) ||
(EncryptedPartitionFlag == 1)))) {
break;
} else {
fsbl_printf(DEBUG_GENERAL,
"INVALID_LOAD_ADDRESS_FAIL\r\n");
OutputStatus(INVALID_LOAD_ADDRESS_FAIL);
FsblFallback();
}
}
if (PSPartitionFlag && (PartitionLoadAddr > DDR_END_ADDR)) {
fsbl_printf(DEBUG_GENERAL,
"INVALID_LOAD_ADDRESS_FAIL\r\n");
OutputStatus(INVALID_LOAD_ADDRESS_FAIL);
FsblFallback();
}
#endif
将内容注释掉即可 但 DDRLESS_SYSTEM 宏 我们还未定义 不要着急 在后面有定义
LoadBootImage() 函数中
以上修改后在文件第 472 行
修改后内容如下
#ifdef DDRLESS_SYSTEM
Xil_L2CacheEnable();
Xil_L1DCacheDisable();
Xil_L1ICacheDisable();
#endif
Status = PartitionMove(ImageStartAddress, HeaderPtr);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE_FAIL\r\n");
OutputStatus(PARTITION_MOVE_FAIL);
FsblFallback();
} else {
fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE Successful\r\n");/* 这里添加了一个 debug 打印 不添加也可以 */
}
其中
#ifdef DDRLESS_SYSTEM
Xil_L2CacheEnable();
Xil_L1DCacheDisable();
Xil_L1ICacheDisable();
#endif
......
else {
fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE Successful\r\n");/* 这里添加了一个 debug 打印 不添加也可以 */
}
为添加部分
PartitionMove() 函数中
以上修改后在文件 1081 行
该函数的变量声明部分 添加一个变量 ExecuionAddr 并给该变量赋值
添加
......
u32 ExecuionAddr;
......
ExecuionAddr = Header->ExecAddr;
修改后内容如下:
u32 SourceAddr;
u32 Status = 0;
u8 SecureTransferFlag = 0;
u32 LoadAddr;
u32 ImageWordLen;
u32 DataWordLen;
u32 ExecuionAddr;
SourceAddr = ImageBaseAddress;
SourceAddr += Header->PartitionStart<<WORD_LENGTH_SHIFT;
LoadAddr = Header->LoadAddr;
ImageWordLen = Header->ImageWordLen;
DataWordLen = Header->DataWordLen;
ExecuionAddr = Header->ExecAddr;
PartitionMove() 函数中
以上修改后在文件 1134 行
添加
#ifdef DDRLESS_SYSTEM
fsbl_printf(DEBUG_GENERAL,"Source Address %x\n\r",(FlashReadBaseAddress + SourceAddr));
fsbl_printf(DEBUG_GENERAL,"DataWordLen %x\n\r",(DataWordLen << WORD_LENGTH_SHIFT));
fsbl_printf(DEBUG_GENERAL,"LoadAddr %x\n\r",LoadAddr);
if(ExecuionAddr &&(LoadAddr && FlashReadBaseAddress))
{
Status=preload_funct((FlashReadBaseAddress + SourceAddr), (ImageWordLen << WORD_LENGTH_SHIFT));
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "preload_funct failed\r\n");
return XST_FAILURE;
}
}
#else
......
#endif
修改后内容如下:
/*
* CPU is used for data transfer in case of non-linear
* boot device
*/
if (!LinearBootDeviceFlag) {
/*
* PL partition copied to DDR temporary location
*/
if (PLPartitionFlag) {
LoadAddr = DDR_TEMP_START_ADDR;
}
#ifdef DDRLESS_SYSTEM
fsbl_printf(DEBUG_GENERAL,"Source Address %x\n\r",(FlashReadBaseAddress + SourceAddr));
fsbl_printf(DEBUG_GENERAL,"DataWordLen %x\n\r",(DataWordLen << WORD_LENGTH_SHIFT));
fsbl_printf(DEBUG_GENERAL,"LoadAddr %x\n\r",LoadAddr);
if(ExecuionAddr &&(LoadAddr && FlashReadBaseAddress))
{
Status=preload_funct((FlashReadBaseAddress + SourceAddr), (ImageWordLen << WORD_LENGTH_SHIFT));
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "preload_funct failed\r\n");
return XST_FAILURE;
}
}
#else
Status = MoveImage(SourceAddr,
LoadAddr,
(ImageWordLen << WORD_LENGTH_SHIFT));
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Move Image Failed\r\n");
return XST_FAILURE;
}
/*
* As image present at load address
*/
SourceAddr = LoadAddr;
#endif
}
PartitionMove() 函数中
以上修改后在文件 1201 行 在该函数定义的最后部分 return 前面
添加
SourceAddr += FlashReadBaseAddress;
修改后内容如下:
/*
* Load Bitstream partition in to fabric only
* if checksum and authentication bits are not set
*/
if (PLPartitionFlag && (!(SignedPartitionFlag || PartitionChecksumFlag))) {
SourceAddr += FlashReadBaseAddress;/* 就这里添加了一句话 修改 SourceAddr 地址*/
Status = PcapLoadPartition((u32*)SourceAddr,
(u32*)Header->LoadAddr,
Header->ImageWordLen,
Header->DataWordLen,
EncryptedPartitionFlag);
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "PCAP Bitstream Download Failed\r\n");
return XST_FAILURE;
}
}
return XST_SUCCESS;
以上 至此 image_mover.c 文件修改完毕
2.7 pcap.c
2.7.1 PcapLoadPartition() 函数中 屏蔽错误检查
源文件中第354 行
添加
#ifndef DDRLESS_SYSTEM
......
#endif
添加后内容如下
#ifndef DDRLESS_SYSTEM
/*
* Check for errors
*/
IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) {
fsbl_printf(DEBUG_INFO,"Errors in PCAP \r\n");
return XST_FAILURE;
}
#endif
以上修改后源文件第 793 行
添加
#ifndef DDRLESS_SYSTEM
......
#endif
添加后 该函数 内容如下:
int XDcfgPollDone(u32 MaskValue, u32 MaxCount)
{
int Count = MaxCount;
u32 IntrStsReg = 0;
/*
* poll for the DMA done
*/
IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
while ((IntrStsReg & MaskValue) !=
MaskValue) {
IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
Count -=1;
#ifndef DDRLESS_SYSTEM
if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) {
fsbl_printf(DEBUG_INFO,"FATAL errors in PCAP %lx\r\n",
IntrStsReg);
PcapDumpRegisters();
return XST_FAILURE;
}
#endif
if(!Count) {
fsbl_printf(DEBUG_GENERAL,"PCAP transfer timed out \r\n");
return XST_FAILURE;
}
if (Count > (MAX_COUNT-100)) {
fsbl_printf(DEBUG_GENERAL,".");
}
}
fsbl_printf(DEBUG_GENERAL,"\n\r");
XDcfg_IntrClear(DcfgInstPtr, IntrStsReg & MaskValue);
return XST_SUCCESS;
}
2.8 qspi.c
该函数在源文件中 217 行 修改较多 建议直接全部复制粘贴
修改后 该函数如下:
u32 InitQspi(void)
{
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR
u32 QspiControlReg = 0;
u32 QspiDelayReg = 0;
u32 Prescaler = XQSPIPS_CLK_PRESCALE_8;
/* Fix for CR #664560 */
QspiControlReg = Xil_In32((XPS_QSPI_BASEADDR + XQSPIPS_CR_OFFSET));
/* Change the baud rate to DIV/8 prescaler value */
QspiControlReg &= ~XQSPIPS_CR_PRESC_MASK;
QspiControlReg |= (u32) (Prescaler & XQSPIPS_CR_PRESC_MAXIMUM) <<
XQSPIPS_CR_PRESC_SHIFT;
Xil_Out32((XPS_QSPI_BASEADDR + XQSPIPS_CR_OFFSET), QspiControlReg);
/*
* Set the USE loopback bit
* Fix for the CR #664560
* Delay DLY1 = 0
* Delay DLY0 = 0
*/
QspiDelayReg = Xil_In32((XPS_QSPI_BASEADDR +
XQSPIPS_LPBK_DLY_ADJ_OFFSET));
QspiDelayReg &= FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY_VALUE;
Xil_Out32((XPS_QSPI_BASEADDR + XQSPIPS_LPBK_DLY_ADJ_OFFSET),
QspiDelayReg);
fsbl_printf(DEBUG_INFO, "QSPI initialized with Control value = 0x%x \n \r",
Xil_In32(XPS_QSPI_BASEADDR +
XQSPIPS_CR_OFFSET));
fsbl_printf(DEBUG_INFO, "QSPI loopback register value = 0x%x \n \r",
Xil_In32(XPS_QSPI_BASEADDR +
XQSPIPS_LPBK_DLY_ADJ_OFFSET));
#endif
return XST_SUCCESS;
}
修改后会有报错 因为 该宏还未定义 之后会修改 qspi.h 文件
以上修改后 该函数位于 文件第 412 行
修改较多
也建议直接复制粘贴修改后 函数如下:
u32 QspiAccess( u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes)
{
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR
u32 Data;
u32 Count;
u32 *SourceAddr;
u32 *DestAddr;
/* Check for non-word tail, add bytes to cover the end */
if ((LengthBytes%4) != 0){
LengthBytes += (4 - (LengthBytes & 0x00000003));
}
SourceAddr = (u32 *)(SourceAddress + FlashReadBaseAddress);
DestAddr = (u32 *)(DestinationAddress);
/* Word transfers, endianism isn't an issue */
for (Count=0; Count < (LengthBytes / 4); Count++){
Data = Xil_In32((u32)(SourceAddr));
SourceAddr++;
Xil_Out32((u32)(DestAddr), Data);
DestAddr++;
}
#endif
return XST_SUCCESS;
}
2.9 qspi.h
添加 在文件第 116 行 添加 qspi.c 文件中用到的宏
添加内容如下:
#define FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY1 0
#define FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY2 0
#define FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY_VALUE (FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY1 | \
FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY2)
2.10 lscript.ld
该文件为生成.elf过程中的链接文件,主要修改MEMORY地址,如下。
MEMORY
{
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x0002FF00
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0x0002FF00, LENGTH = 0x0000100
FLASH : ORIGIN = 0xFC000000 + 0x1700, LENGTH = 0x2FE000
}
!!! 重要!!!
需要为该程序文件添加程序头!!! 使用下面的命令。
ENTRY(_vector_table)
PHDRS { text PT_LOAD; }/*!!! 添加 !!!重要!!!*/
修改后连接脚本文件如下:
注:主要是将一些文件直接写在Flash 中
并添加 XVtable 段。一定要添加
.XVtable(NOLOAD) : {
_dataXVtableVMA_start = .;
*(XVtable)
_dataXVtableVMA_end = .;
} > ps7_ram_1_S_AXI_BASEADDR AT> FLASH
_dataXVtableLMA = LOADADDR(.XVtable);
并且需要注意 data 段中的段头尾改变了 main() 函数中使用的就是这个 改完就不会再报错了 这个也一定要更改
.data : {
_dataVMA_start = .;
*(.data)
*(.data.*)
*(.data1)
*(.data1.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
_dataVMA_end = .;
} > ps7_ram_0_S_AXI_BASEADDR AT> FLASH
_dataLMA = LOADADDR(.data);
修改后的该文件全部 内容如下:
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x6000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000;
_RSA_AC_SIZE = DEFINED(_RSA_AC_SIZE) ? _RSA_AC_SIZE : 0x1000;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
/* Define Memories in the system */
MEMORY
{
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x0002FF00
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0x0002FF00, LENGTH = 0x0000100
FLASH : ORIGIN = 0xFC000000 + 0x1700, LENGTH = 0x2FE000
}
/* Specify the default entry point to the program */
ENTRY(_vector_table)
PHDRS { text PT_LOAD; }
SECTIONS
{
.text : {
*(.vectors)
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > FLASH : text /* !!! : text !!! 也需要添加 重要 */
.init : {
KEEP (*(.init))
} > FLASH
.fini : {
KEEP (*(.fini))
} > FLASH
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.rodata1)
*(.rodata1.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > FLASH
.data : {
_dataVMA_start = .;
*(.data)
*(.data.*)
*(.data1)
*(.data1.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
_dataVMA_end = .;
} > ps7_ram_0_S_AXI_BASEADDR AT> FLASH
_dataLMA = LOADADDR(.data);
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s.*)
*(.gnu.linkonce.s2.*)
__sdata_end = .;
} > ps7_ram_0_S_AXI_BASEADDR AT> FLASH
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > ps7_ram_0_S_AXI_BASEADDR AT> FLASH
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > FLASH
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > FLASH
.got : {
*(.got)
} > FLASH
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > FLASH
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
___DTORS_END___ = .;
} > FLASH
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > FLASH
.eh_frame : {
*(.eh_frame)
} > FLASH
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > FLASH
.gcc_except_table : {
*(.gcc_except_table)
} > FLASH
.mmu_tbl (ALIGN(0x4000)): {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > FLASH
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > FLASH
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > FLASH
.rsa_ac : {
. = ALIGN(64);
__rsa_ac_start = .;
. += _RSA_AC_SIZE;
__rsa_ac_end = .;
} > FLASH
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > FLASH
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > ps7_ram_0_S_AXI_BASEADDR
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > ps7_ram_0_S_AXI_BASEADDR
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > ps7_ram_0_S_AXI_BASEADDR
.bss (NOLOAD) : {
__bss_start = .;
__bss_start__ = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
__bss_end = .;
__bss_end__ = .;
} > ps7_ram_0_S_AXI_BASEADDR
/*
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
*/
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > ps7_ram_0_S_AXI_BASEADDR
.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _STACK_SIZE;
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > ps7_ram_0_S_AXI_BASEADDR
.XVtable(NOLOAD) : {
_dataXVtableVMA_start = .;
*(XVtable)
_dataXVtableVMA_end = .;
} > ps7_ram_1_S_AXI_BASEADDR AT> FLASH
_dataXVtableLMA = LOADADDR(.XVtable);
_end = .;
}
通过查看fsbl.elf文件,可以查看目前sections的分配,对于其中具有READONLY属性的section,可以放在QSPI FLASH中运行,即XIP模式。
其它的放在 ps7_ram_0_S_AXI_BASEADDR 中即可
2.11 添加宏定义
代码修改完后,在fsbl工程中添加两个宏定义。
至此 fsbl 文件全部修改完毕
接下来修改应用文件
3 application
3.1 application.c
该文件中添加代码
添加在 main() 函数上面即可
添加内容如下:
#define XPS_L2CC_EVNT_CNTRL_OFFSET 0x0200
#define XPS_L2CC_EVNT_CNT1_CTRL_OFFSET 0x0204
#define XPS_L2CC_EVNT_CNT0_CTRL_OFFSET 0x0208
#define XPS_L2CC_EVNT_CNT1_VAL_OFFSET 0x020C
#define XPS_L2CC_EVNT_CNT0_VAL_OFFSET 0x0210
#define QSPI_BaseAddress 0xE000D000
extern char _image_start, _dataLMA, _dataVMA_start, _dataVMA_end, _vectorscopy, __vectors_start, __vectors_end;
extern char _dataXVtableLMA, _dataXVtableVMA_start,_dataXVtableVMA_end;
static void copy(char *src, char *dstStart, char *dstEnd) {
/* ROM has data at end of text; copy it. */
while (dstStart < dstEnd)
{
*dstStart++ = *src++;
asm volatile ("dsb sy");
}
}
void Xil_Write32(unsigned int OutAddress, unsigned int Value)
{
*(volatile unsigned int *) OutAddress = Value;
}
unsigned int Xil_Read32(unsigned int Addr)
{
return *(volatile unsigned int *) Addr;
}
并在main() 函数中 添加数据段拷贝函数
//copy the data section from FLASH(load region) to OCM(Execution region) memory region.
copy(&_dataLMA,&_dataVMA_start,&_dataVMA_end);
//Copy the Interrupt vector table from FLASH(load region) to OCM(Execution region) memory region.
copy(&_dataXVtableLMA,&_dataXVtableVMA_start,&_dataXVtableVMA_end);
添加完成后和fsbl 的mian() 函数一样也会报错 也是因为 lscript.ld 中的数据段中还未更改
3.2 lscript.ld
该文件修改与fsbl 文件中的 lscript.ld 一样 注意点也是一样的 就不在赘述了 具体哪些放在FLASH 中 哪些放在 OCM 内存中也是看 application.elf 文件 !!!!!
修改完成后该文件内容如下
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
/* Define Memories in the system */
MEMORY
{
FLASH : ORIGIN = 0xFC700000, LENGTH = 0x100000
ps7_ram_0 : ORIGIN = 0x00010000, LENGTH = 0x0001FF00
ps7_ram_1 : ORIGIN = 0x0002ff00, LENGTH = 0x00000100
}
/* Specify the default entry point to the program */
ENTRY(_vector_table)
PHDRS { text PT_LOAD; }
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.text : {
KEEP (*(.vectors))
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > FLASH :text
.init : {
KEEP (*(.init))
} > FLASH
.fini : {
KEEP (*(.fini))
} > FLASH
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > FLASH
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > FLASH
.data : {
_dataVMA_start = .;
*(.data)
*(.data.*)
*(.data1)
*(.data1.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
_dataVMA_end = .;
} > ps7_ram_0 AT> FLASH
_dataLMA = LOADADDR(.data);
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > ps7_ram_0 AT> FLASH
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > ps7_ram_0 AT> FLASH
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > ps7_ram_0 AT> FLASH
.got : {
*(.got)
} > FLASH
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > FLASH
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
___DTORS_END___ = .;
} > FLASH
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > FLASH
.eh_frame : {
*(.eh_frame)
} > FLASH
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > FLASH
.gcc_except_table : {
*(.gcc_except_table)
} > FLASH
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > FLASH
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > FLASH
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > FLASH
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > FLASH
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > FLASH
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > FLASH
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > ps7_ram_0
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > ps7_ram_0
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > ps7_ram_0
.bss (NOLOAD) : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
__bss_end = .;
} > ps7_ram_0
/*
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
*/
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > ps7_ram_0
.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
. = ALIGN(16);
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _IRQ_STACK_SIZE;
. = ALIGN(16);
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > ps7_ram_0
.XVtable : {
_dataXVtableVMA_start = .;
*(XVtable)
_dataXVtableVMA_end = .;
} > ps7_ram_1
_dataXVtableLMA = LOADADDR(.XVtable);
_end = .;
}
4 生成BOOT.BIN
生成boot.bin需要使用bif文件,需要注意设置xip模式
修改过后的该文件内容如下 注意需要添加 xip_mode 和 offset !!! 重要!!!
//arch = zynq; split = false; format = BIN
the_ROM_image:
{
[bootloader, xip_mode,offset = 0x1700]E:\chen\zynq\J5RPY_HF_CLY\J5RPY_HF_CLY\02_Pro\J5RPY_HF.sdk\fsbl\Debug\fsbl.elf
[offset = 0x200000]E:\chen\zynq\J5RPY_HF_CLY\J5RPY_HF_CLY\02_Pro\J5RPY_HF.sdk\ARM_Core_wrapper_hw_platform_0\ARM_Core_wrapper.bit
[offset = 0x700000]E:\chen\zynq\J5RPY_HF_CLY\J5RPY_HF_CLY\02_Pro\J5RPY_HF.sdk\hello_world\Debug\hello_world.elf
}
**注:需要使用一个正常的 未修改过 lscript.ld 的fsbl.elf 将 生成的BOOT.Bin文件烧录到板子里 !!! **
最后会有一些报错
Description Resource Path Location Type
fsbl.elf: section `.data' can't be allocated in segment 0 fsbl C/C++ Problem
但这个报错不影响 所以不用管