` `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
- 序
- 第1章 Linux下开发FPGA
- 1.1 Linux下安装diamond
- 1.2 使用轻量级linux仿真工具iverilog
- 1.3 使用linux shell来读写串口
- 1.4 嵌入式上的linux
- 设备数教程
- linux C 标准库文档
- linux 网络编程
- 开机启动流程
- 1.5 linux上实现与树莓派,FPGA等通信的串口脚本
- 第2章 Intel FPGA的使用
- 2.1 特别注意
- 2.2 高级应用开发流程
- 2.2.1 生成二进制bit流rbf
- 2.2.2 制作Preloader Image
- 2.2.2.1 生成BSP文件
- 2.2.2.2 编译preloader和uboot
- 2.2.2.3 更新SD的preloader和uboot
- 2.3 HPS使用
- 2.3.1 通过JTAG下载代码
- 2.3.2 HPS软件部分开发
- 2.3 quartus中IP核的使用
- 2.3.1 Intel中RS232串口IP的使用
- 2.4 一些问题的解决方法
- 2.4.1 关于引脚的复用的综合出错
- 第3章 关于C/C++的一些语法
- 3.1 C中数组作为形参不传长度
- 3.2 汇编中JUMP和CALL的区别
- 3.3 c++中map的使用
- 3.4 链表的一些应用
- 3.5 vector的使用
- 3.6 使用C实现一个简单的FIFO
- 3.6.1 循环队列
- 3.7 C语言不定长参数
- 3.8 AD采样计算同频信号的相位差
- 3.9 使用C实现栈
- 3.10 增量式PID
- 第4章 Xilinx的FPGA使用
- 4.1 Alinx使用中的一些问题及解决方法
- 4.1.1 在Genarate Bitstream时提示没有name.tcl
- 4.1.2 利用verilog求位宽
- 4.1.3 vivado中AXI写DDR说明
- 4.1.4 zynq中AXI GPIO中断问题
- 4.1.5 关于时序约束
- 4.1.6 zynq的PS端利用串口接收电脑的数据
- 4.1.7 SDK启动出错的解决方法
- 4.1.8 让工具综合是不优化某一模块的方法
- 4.1.9 固化程序(双核)
- 4.1.10 分配引脚时的问题
- 4.1.11 vivado仿真时相对文件路径的问题
- 4.2 GCC使用Attribute分配空间给变量
- 4.3 关于Zynq的DDR写入byte和word的方法
- 4.4 常用模块
- 4.4.1 I2S接收串转并
- 4.5 时钟约束
- 4.5.1 时钟约束
- 4.6 VIVADO使用
- 4.6.1 使用vivado进行仿真
- 4.7 关于PicoBlaze软核的使用
- 4.8 vivado一些IP的使用
- 4.8.1 float-point浮点单元的使用
- 4.10 zynq的双核中断
- 第5章 FPGA的那些好用的工具
- 5.1 iverilog
- 5.2 Arduino串口绘图器工具
- 5.3 LabVIEW
- 5.4 FPGA开发实用小工具
- 5.5 Linux下绘制时序图软件
- 5.6 verilog和VHDL相互转换工具
- 5.7 linux下搭建轻量易用的verilog仿真环境
- 5.8 VCS仿真verilog并查看波形
- 5.9 Verilog开源的综合工具-Yosys
- 5.10 sublim text3编辑器配置verilog编辑环境
- 5.11 在线工具
- 真值表 -> 逻辑表达式
- 5.12 Modelsim使用命令仿真
- 5.13 使用TCL实现的个人仿真脚本
- 5.14 在cygwin下使用命令行下载arduino代码到开发板
- 5.15 STM32开发
- 5.15.1 安装Atollic TrueSTUDIO for STM32
- 5.15.2 LED闪烁吧
- 5.15.3 模拟U盘
- 第6章 底层实现
- 6.1 硬件实现加法的流程
- 6.2 硬件实现乘法器
- 6.3 UART实现
- 6.3.1 通用串口发送模块
- 6.4 二进制数转BCD码
- 6.5 基本开源资源
- 6.5.1 深度资源
- 6.5.2 FreeCore资源集合
- 第7章 常用模块
- 7.1 温湿度传感器DHT11的verilog驱动
- 7.2 DAC7631驱动(verilog)
- 7.3 按键消抖
- 7.4 小脚丫数码管显示
- 7.5 verilog实现任意人数表决器
- 7.6 基本模块head.v
- 7.7 四相八拍步进电机驱动
- 7.8 单片机部分
- 7.8.1 I2C OLED驱动
- 第8章 verilog 扫盲区
- 8.1 时序电路中数据的读写
- 8.2 从RTL角度来看verilog中=和<=的区别
- 8.3 case和casez的区别
- 8.4 关于参数的传递与读取(paramter)
- 8.5 关于符号优先级
- 第9章 verilog中的一些语法使用
- 9.1 可综合的repeat
- 第10章 system verilog
- 10.1 简介
- 10.2 推荐demo学习网址
- 10.3 VCS在linux上环境的搭建
- 10.4 deepin15.11(linux)下搭建system verilog的vcs仿真环境
- 10.5 linux上使用vcs写的脚本仿真管理
- 10.6 system verilog基本语法
- 10.6.1 数据类型
- 10.6.2 枚举与字符串
- 第11章 tcl/tk的使用
- 11.1 使用Tcl/Tk
- 11.2 tcl基本语法教程
- 11.3 Tk的基本语法
- 11.3.1 建立按钮
- 11.3.2 复选框
- 11.3.3 单选框
- 11.3.4 标签
- 11.3.5 建立信息
- 11.3.6 建立输入框
- 11.3.7 旋转框
- 11.3.8 框架
- 11.3.9 标签框架
- 11.3.10 将窗口小部件分配到框架/标签框架
- 11.3.11 建立新的上层窗口
- 11.3.12 建立菜单
- 11.3.13 上层窗口建立菜单
- 11.3.14 建立滚动条
- 11.4 窗口管理器
- 11.5 一些学习的脚本
- 11.6 一些常用的操作语法实现
- 11.6.1 删除同一后缀的文件
- 11.7 在Lattice的Diamond中使用tcl
- 第12章 FPGA的重要知识
- 12.1 面积与速度的平衡与互换
- 12.2 硬件原则
- 12.3 系统原则
- 12.4 同步设计原则
- 12.5 乒乓操作
- 12.6 串并转换设计技巧
- 12.7 流水线操作设计思想
- 12.8 数据接口的同步方法
- 第13章 小项目
- 13.1 数字滤波器
- 13.2 FIFO
- 13.3 一个精简的CPU( mini-mcu )
- 13.3.1 基本功能实现
- 13.3.2 中断添加
- 13.3.3 使用中断实现流水灯(实际硬件验证)
- 13.3.4 综合一点的应用示例
- 13.4.5 使用flex开发汇编编译器
- 13.4.5 linux--Flex and Bison
- 13.4 有符号数转单精度浮点数
- 13.5 串口调试FPGA模板