企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
` `Zynq7021有1G的DDR,PS和PL都可以对DDR进行访问。PS端对DDR的读写,在Xil_io.h文件中,使用Xil_Out函数可以向 DDR写入数据,使用Xil_In函数可以从DDR读取数据。但是要注意ARM的二级缓存问题。 ## 大端存储和小端存储 ` `在CPU内部的地址总线和数据总线是与内存的地址总线和数据总线连接在一起的。当一个数从内存中向CPU传送时,有时是以字节为单位,有时又以字(4字节)为单位。传过来是放在寄存器里(一般是32字节),在寄存器中,一个字的表示是右边应该属于低位,左边属于高位,如果寄存器的高位和内存中的高地址相对应,低位和内存的低地址相对应,这就属于小端存储。反之则称为大端存储。大部分处理器都是小端存储的。 ` `因为十六进制的2位正好是1字节,所以选十六进制0x0A0B0C0D为例,如图2-1所示,对小端存储,低位是0x0D,应存入低位地址,所以存入的顺序是`0x0D 0x0C 0x0B 0x0A `。反之,对于大端存储则为`0x0A 0x0B 0x0C 0x0D `。 ![](https://img.kancloud.cn/f4/7e/f47e5e2d4a028a7d97d3b959f951092e_1249x765.png) ## zynq的存储方式 ` `验证zynq存储方式: ``` /** * PS对DDR的读写,以及验证设备是属于大端存储还是小端存储 */ void DDR_PS_TEST() { Xil_Out32(0x30000000,0x12345678); u32 data1 = Xil_In8(0x30000000); u32 data2 = Xil_In8(0x30000000 + 1); u32 data3 = Xil_In8(0x30000000 + 2); u32 data4 = Xil_In8(0x30000000 + 3); printf("地址:%x 8位数据:%x\n",0x30000000,data1); printf("地址:%x 8位数据:%x\n",0x30000001,data2); printf("地址:%x 8位数据:%x\n",0x30000002,data3); printf("地址:%x 8位数据:%x\n",0x30000003,data4); while(1)usleep(1000000); } ``` ![](https://img.kancloud.cn/1c/72/1c721152c4cd9028de482cde45c36c8a_302x149.png) ` `可以看到在zynq中是属于小端存储。因此使用PL端AXI总线实现写入8位的数据的示例代码: ``` module module ( input clk, output reg [31:0]addr, output reg [31:0]data ); reg [7:0]new_byte; always@(posedge clk) begin data <= data{data[23:0],new_byte}; addr <= addr + 1; new_byte <= new_byte + 1'b1; end endmodule ``` ` ` 同理可得,写入16位的数据如下: ``` module ( input clk, output reg [31:0]addr, output reg [31:0]data ); reg [15:0]new_word; always@(posedge clk) begin data <= data{data[15:0],new_word}; addr <= addr + 2; new_word <= new_word + 1'b1; end endmodule ``` ` `采用这种方式,必须在一种数据类型的最高地址后空出3的地址,避免后续数据被覆盖。 ## C语言中与存储有关的情况 ` `下面,分享一道有趣的编程题,加深印象,此题来自> 在32位的X86系统下,输出的值为: ``` #include <stdio.h> int main() { int a[5]={1,2,3,4,5}; //A int *ptr1=(int *)(&a+1); //B int *ptr2=(int *)((int)a+1); //C printf("%x,%x",ptr1[-1],*ptr2); //D return 0; } ``` ` `首先,由题目可知32位的X86系统是采用小端存储的,即高位放高地址,低位放地址。执行完A语句后,假设该数组是放在0起始地址上。 ![](https://img.kancloud.cn/28/0a/280a90ebbc1ec155a54fd6fe2d06f6e5_522x657.png) ` `&a+1是整个数组长度再加1,指向20地址,而&a\[0\]+1则是指向2地址,虽然&a与&a\[0\]地址一样,但是有着本质的不同。ptr1\[-1\]被解析成\*(ptr1-1),即ptr1往后退四字节,所以ptr1\[-1\]十六进制为5。对于C赋值语句,(int)a+1指向的地址为1,因为是低端存储,所以\*ptr2=2000000,以上,完毕。 答案:5,2000000