microblaze与zynq共存情形(之一) - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
mb的cache配置为ocm_remap区域,并且ic/dc只使用M_AXI_DC/IC => S_AXI_HP0 =>OCM_remap区域。这个时候mb到zynq的总线访问路径如下。
测试结果:
-
a. ddr运行:可以正确运行。ps_uart不能打印,符合预期,因为没有从mb的m_axi_dp到zynq的s_axi_gp0的路径。(这个时候led灯的闪烁速度很正常,跟以前在ddr中运行结果不一样)。从axi_uartlite打印的结果看,ocm_lower_addr可以读写,ocm_high_addr不能读写,甚至连ocm3的地址都不能读写。
-
b. local memory运行:可以正确运行。ps_uart不能打印,符合预期。 也是一样,从axi_uartlite打印的结果看,ocm_lower_addr可以读写,ocm_high_addr不能读写,甚至连ocm3的地址都不能读写。
-
c. ocm_higher_addr运行:完全不能运行。分析:这个从前面a,b的结果,已经可以看出端倪了。无论是否配置ocm_remap,ocm_higher_addr都不能正确读写,也就意味着,用ocm_higher_addr运行代码是不可行的。
-
d. ocm_lower_addr运行:可以运行,无论是否用zynq做ocm_remap都可以运行。分析:这个从前面a,b的结果,已经可以看出端倪了,由于无论是否配置ocm_remap, ocm_lower_addr都可以正确读写,因此意味着从ocm_lower_addr运行代码是可能的。实际确实如此
-
e. 以上有一个很有意思的点。虽然我们在地址分配中,没有给ddr分配地址,但是实际效果是它是可以读/写/执行程序。
以上分别是a, b, d的运行结果。因为c完全不能运行,所以没有结果。
mb的cache配置为ocm_remap区域,并且ic使用M_AXI_IC => S_AXI_HP0 =>OCM_remap区域,而dp使用M_AXI_DP => S_AXI_HP0 => OCM_remap。这个时候mb到zynq的总线访问路径如下。
这种情形,可以理解:只有Icache,没有Dcache。另外,指令走HP通道,而数据走GP通道。 测试结果:
-
a. ddr运行:可以正确运行。ps_uart可以打印。ocm_lower_addr可以读写,ocm_high_addr不能读写,甚至连ocm3的地址都不能读写。这个情况与前面一样
-
b. local memory运行:可以正确运行。结果与情况a完全一样。
-
c. ocm_higher_addr运行:完全不能运行。与前面的情况一样。
-
d. ocm_lower_addr运行:可以运行,结果与前面一样。
-
e. 这个例子说明了,dp和dc都可以用来执行程序和读写数据。在功能上没有什么差别,当然在性能上肯定有差别
在总线上,去掉dp,用dc去连接axi_gpio和axi_uartlite,是否可以?
为什么ocm_higher_addr不能用?与什么有关系?
有了前面基础,现在可以考虑,去掉local memory,是否可以运行了?
如果地址分配,HP与GP都指向同一个地址区域,那么将是错误的。如上图所示。也就是说,对于mb来说,dp和dc接口都可以读写数据,他们不允许指向同一个地址区间。
mb的程序
#include <stdio.h>
#include "xparameters.h"
#include "xgpio.h"
#include "sleep.h"
#include "xil_cache.h"
#define GPIO_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID // 根据实际硬件配置修改
#define LED_CHANNEL 1
void test_ddr(UINTPTR addr, u32 length, u8 mode)
{
for(UINTPTR p=addr; p<addr+length; p+=4){
Xil_Out32(p,0x11223344);
}
for(UINTPTR p=addr; p<addr+length; p+=4){
int v= Xil_In32(p);
if(mode==0){
xil_printf("%p->%x\r\n",p,v);
}
else if(mode==1 && v!=11223344){
xil_printf("%p\r\n",p);
}
}
}
int main() {
XGpio gpio;
int Status;
usleep(50000);
Xil_DCacheDisable();
xil_printf("Microblaze GPIO test!\r\n");
// 初始化GPIO
Status = XGpio_Initialize(&gpio, GPIO_DEVICE_ID);
if (Status != XST_SUCCESS) {
printf("GPIO Initialization failed\n");
return XST_FAILURE;
}
// 设置GPIO为输出
XGpio_SetDataDirection(&gpio, LED_CHANNEL, 0x00);
while (1) {
// scanf("%c",&c);
// while(c!='c');
xil_printf("Microblaze Print Now!\r\n");
//test_ddr(0x10000000,16,0); //test ddr
test_ddr(0xfffc0000,16,0); //test ocm, remap模式才可以访问
test_ddr(0xfffd0000,16,0); //test ocm, remap模式才可以访问
test_ddr(0xfffe0000,16,0); //test ocm, remap模式才可以访问
test_ddr(0xffff0000,16,0); //test ocm, remap模式才可以访问
test_ddr(0x00000000,16,0); //test ocm0, 默认非remap模式可以访问
test_ddr(0x00010000,16,0); //test ocm1, 默认非remap模式可以访问
test_ddr(0x00020000,16,0); //test ocm2, 默认非remap模式可以访问
test_ddr(0xFFFF0000,16,0); //test ocm3, 默认非remap模式可以访问
// 依次翻转四个GPIO引脚
XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0001);
usleep(500000/10); // 等待500毫秒
XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0010);
usleep(500000/10);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0100);
usleep(500000/10);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b1000);
usleep(500000/10);
}
return 0;
}
zynq的程序, 只负责ocm_remap_to_higher_addr
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
void Xil_Remap_OCM(void)
{
xil_printf("%x\r\n",Xil_In32(0xf8000910)); //read slcr.ocm_cfg
Xil_Out32(0xf8000000+0x08,0xdf0d); //slcr.unlock
Xil_Out32(0xf8000910,0x000f); //slcr.ocm_cfg(remap ocm from 0x00000000->0xfffc0000)
Xil_Out32(0xf8000000+0x08,0x0); //slcr_unlock
xil_printf("%x\r\n",Xil_In32(0xf8000910)); //read slcr.ocm_cfg again
}
int main()
{
init_platform();
Xil_Remap_OCM();
cleanup_platform();
return 0;
}