概述
-
该文章的验证平台为xilinx的Kcu105开发板硬件平台,该平台的fpga型号为xcku040-ffva1156-2-e上面挂了4片ddr4(镁光 EDY4016AABG-DR-F)。
-
原理图如下:
(一)DDR4 IO简介
-
reset_n:
- ddr低电平复位信号
- coms信号,960mV = H, 240mV = L
-
cke:
- cke = 1时,激活ddr内部时钟信号
- cke = 0时,停用ddr内部时钟信号
- 在读写过程中必须保持高电平状态
-
act_n cs_n:
-
当act_n = 0 cs_n = 0,RAS_n/A16, CAS_n/A15, and WE_n/A14复用为ACTIVATE 命令的行地址;
-
当act_n = 1 cs_n = 0时,RAS_n/A16, CAS_n/A15, and WE_n/A14复用为RAS_n,CAS_n,WE_n 信号;
- ras_n, cas_n, we_n与command对应关系如下表
- ras_n, cas_n, we_n与command对应关系如下表
-
当cs_n = 1时,所有命令都被屏蔽
-
-
bg0 ba1 ba0:
- bax 用于在ACTIVATE,READ, WRITE, or PRECHARGE 命令时作为bank addr;
- 在配置 MODE REGISTER 时bg0,ba1,ba0一起作为模式寄存器的地址
- 000 = MR0,001 = MR1,010 = MR2,011 = MR3,
- 100 = MR4,101 = MR5,110 = MR6,111 = DNU
-
adr (A[17:0]):
- ACTIVATE 命令时,用作 row address
- READ/WRITE 命令时,column address
- 根据容量不同地址宽度略有不同4Gb时,A16,A17 not care
-
odt:
- ODT=1时,使能ddr4内部终端电阻;
- 对于x16来说,RTT应用于每个DQ、DQSU\t、DQSU uc、dqslu ut、dqslu uc、UDMün和LDM_n信号。
- The ODT pin will be ignored if the mode registers are programmed to disable R TT .
-
ck_t ck_n:
- Differential clock inputs
- All address, command, and control input signals are
sampled on the crossing of the positive edge of CK_t and the negative edge of CK_c.
-
dbi_n:
-
dbi_n引脚可以配置为两种模式DM(Data Mask)和DBI(Data bus inversion),具体由MR1的A11,和MR5的A12:A10决定
-
TDQS 功能和 DM、DBI功能互斥,所以开启DM或DBI功能需要关闭TDQS,具体有MR1的A11控制
-
DM和WRITE_DBI功能也是互斥的,两者只能选择其一,由MR5的A12:A10决定
-
x4 不支持DM和DBI功能,x8、x16支持DM和DBI功能;x8数据位宽为8恰好为1Byte,故单pin的dbi_n即可满足DM或DBI功能;x16数据位宽为16为2Byte,故双pin的dbi_n(UDBI_n,LDBI_n)才能满足需求;kcu150开发板有4片x16的DDR4共需要8pin,所以在mig中位宽是8
inout [7:0] c0_ddr4_dm_dbi_n,
-
DM和DBI低电平有效
-
DM function during Write operation: DRAM masks the write data received on the DQ inputs if DM_n was sampled Low on a given byte lane. If DM_n was sampled High on a given byte lane, DRAM does not mask the write data and writes into the DRAM core.
-
-
-
dq:
- 双向数据总线
- x4 -> DQ[3:0]; x8 -> DQ[7:0]; x16 -> DQ[15:0]
- kcu105开发板有4片EDY4016AABG-DR-F,16 x 4 = 64bit
- 如果ia mode register 使能CRC ,则CRC编码数据将跟在数据突发后
- 如果test via mode register setting MR[4]A[4] = HIGH,则DQ0,DQ1,DQ2,DQ3中的一个或全部将用于监视内部的Vfeg电平。在该模式下Rtt的值应该设置为High-Z。此测量用于验证目的,不是外部电源引脚。
-
dqs_c dqs_t:
- 若TDQS功能在mode register中使能 DRAM 将 Rtt终端电阻作用于DQS_t and DQS_c
- 上述功能只能用于x8 的DRAMs
- 若TDQS功能没有使能,则DM/TDQS_t引脚将用于DATA MASK(DM)功能,这时TDQS_c不起作用
- 它是双向信号,读内存时由内存产生,DQS的沿和数据的沿对其
- 写内存时,由外部产生(FPGA),DQS的中间对应数据的沿
- 上述功能仅仅用于x8 和 x16 DRAM
- tdqs_t复用作DM功能只是在X8系列DDR中,x16 DM功能需要dbi_n复用
(二)AXI驱动
驱动框图
-
我采用了xilinx自带ip MIG来驱动DDR4,框图如下:
-
MIG作为AXI4从设备挂在了axi interconnet上,axi interconnet引出两个主设备来读写MIG(这就是我选用xilinx 标准接口axi4接口的好处,当多个设备同时读写DDR时仲裁机制可有axi interconnet自己完成,这时app接口不具备的)。
MIG IP
驱动时钟
- 从上述两个图可以知道MIG中包含MMCM,PLL,BUFG,但是应该怎样配置相关参数呢?
- system_clk:也就是上图的CLKIN,它是MIG的参考时钟有一定的取值范围(参见PG150)不是必须为300MHz
- MMCM_CLK:必须是CK/4 = 1200M / 4 = 300MHz,也就是ui_clk为逻辑层提供时钟,比如说AXI4的时钟。
- D,D0,M这些都是根据system_clk的值以及图中的等式关系,自动计算的。
- clock1- clock4也是MMCM对system_clk分频的结果,如果逻辑层有需要可以勾选配置输出。
数据接口
- MIG采用了标准的AXI4接口作为数据传输接口
- 看到这里其实已经用标准的AXI4接口读写DDR了(前提是基础配置已经完成了),是不是感觉DDR4也没啥。但是我要说这是xilinx驱动做的太好了,以至于我们可以傻瓜式操作。有些技术还是需要深入学习才能理解的更加深刻。
(三)app驱动
-
对AXI总线不熟悉的话可以选用app接口,只需要在mig basic界面下去掉axi interface的勾选
-
axi接口其实就是在app接口的基础上封了一层axi4协议
mig_app_infc
- 从上图可以看出MIG其实分为三层,物理侧(PHY)、控制层(CTRL)、用户层接口(USER)。现在我们重点看一下用户层
User Interface
.c0_ddr4_app_addr (c0_ddr4_app_addr),
.c0_ddr4_app_cmd (c0_ddr4_app_cmd),
.c0_ddr4_app_en (c0_ddr4_app_en),
.c0_ddr4_app_hi_pri (1'b0),
.c0_ddr4_app_wdf_data (c0_ddr4_app_wdf_data),
.c0_ddr4_app_wdf_end (c0_ddr4_app_wdf_end),
.c0_ddr4_app_wdf_mask (c0_ddr4_app_wdf_mask),
.c0_ddr4_app_wdf_wren (c0_ddr4_app_wdf_wren),
.c0_ddr4_app_wdf_rdy (c0_ddr4_app_wdf_rdy),
.c0_ddr4_app_rd_data (c0_ddr4_app_rd_data),
.c0_ddr4_app_rd_data_end (c0_ddr4_app_rd_data_end),
.c0_ddr4_app_rd_data_valid (c0_ddr4_app_rd_data_valid),
.c0_ddr4_app_rdy (c0_ddr4_app_rdy),
-
app_addr:
-
对与DDR4来说app_addr的位宽等于COL+ROW+Bank+Group+BANK
-
EDY4016AABG-DR-F地址划分如下图所示
-
如上图篮框内相加结果10 + 15 + 2 + 1 = 28bit
-
28bit对应2^28个地址,由于单片EDY4016AABG-DR-F 数据宽度DQ为16bit,所以寻址空间为(2^28) * 16 = 4Gb
-
clk_phy:clk_app=4:1,且phy侧是ddr时序,所以一个用户侧1个clk_phy发送的数据在phy侧应该是4个clk_phy上下两个时钟沿共8(4*2)次才能发送完。如果用户侧是连续地址读写,那么每次地址应该+8;
-
kcu105开发板由4片EDY4016AABG-DR-F拼接而成,他们共用地址总线,DQ的数据宽度为16bit * 4=64bit,按照上述原理用户侧的数据宽度应该是64*8=512bit;
-
-
在MIG 配置界面将memory address map配置为ROW_COLUMN_BANK映射模式如下图所示
- memory address map 的配置决定 gp ba row column在地址映射中的顺序,最终影响ddr4的读写方式,例如:按照上述图片的配置方式,地址映射如下表所示,读写ddr时,先读写同行同列同bank的不同gp的数据,然后是同行同列不同bank的数据,再然后是同行不同列的数据,当写满2^13个地址后,才开始换行。在这种模式下行地址刷新的速率远远低于BANK_ROW_COLUMN模式
-
在PG150文档中上述映射如下图所示
-
所以在上述配置下EDY4016AABG-DR-F的app_addr[27:0]地址映射关系如下表
-
bit30-bit16 bit15-bit6 bit5-bit4 bit3 bit2-bit0 Row[14:0] Column[9:0] Bank[1:0] Bank Group col[2:0] - 在mig user infc中app_addr为宽为28,查看底层代码低三位是没有的,这与PG150描述有出入
- Note that the three LSBs of app_addr map to the column
address LSBs which correspond to SDRAM burst ordering.
-
-
app_cmd(1)
- 向user infc发送commands,如下表所示
Operation app_cmd[2:0] Write 000 Read 001 wr_bytes 011 - 若使能ECC,则在wr_bytes操作时需要在app_wdf_mask非0位写1
- wr_bytes会触发控制器中的read-modify-write flow,只有在ECC模式下使用屏蔽数据进行写入时才需要该流。
- 向user infc发送commands,如下表所示
-
app_en(I)
- 在app_en置位前,需将app_addr,app_cmd,app_hi_pri数据放置于总线上
- 上述步骤完成后,app_en置位以此向user intreface发送请求
- user interface 置位 app_rdy表明握手成功
-
app_rdy(O)
- 用于指示当前向user interface发送的请求user interface是否收到
- 若fpga将app_en置位后,user interface未将app_rdy置位则该请求需重新发送。
- 在如下情况下app_rdy不会置位
- PHY/Memory 初始化未完成
- All the controller Group FSMs are occupied (can be viewed as the command buffer being full).
- A read is requested and the read buffer is full.
- A write is requested and no write buffer pointers are available.
- 一个读周期被插入
-
app_wdf_wren(I)
- indicates that the data on the app_wdf_data[] bus is valid.
-
app_wdf_data(I)
- 为预写入ddr的数据
- ECC OFF,位宽 = 2 X nCK_PER_CLK X DQ_WIDTH = 2 X 4 X 64 = 512bit
- ECC ON,位宽 = 2 X nCK_PER_CLK X (DQ_WIDTH - ECC_WIDTH) = 2 X 4 X (72 -8) = 512bit
-
app_wdf_end(I)
- 用于表示app_wdf_data bus 上的数据在本次写周期内达到了最后一个数据
- 对于Back-to-Back Write写,每个时钟周期都认为是一个写周期,每个数据都认为是最后一个数据,所以app_wdf_end一直为H,如下图
-
app_wdf_rdy(O)
- This output indicates that the write data FIFO is ready to receive data.
- Write data is accepted when app_wdf_rdy = 1’b1 and app_wdf_wren = 1’b1.
-
app_wdf_mask(I)
- This provides the mask for app_wdf_data[].
- 区别于phy侧DM信号,该信号高电平有效,每bit对应1Byte app_wdf_dat,app_wdf_dat位宽512所以app_wdf_mask位宽 = 512 / 8 = 64bit
(四)Time
- 提到DDR底层就绕不开各种时间,现在挑几个重点的来说一下。
parameter tFAW = 37,//In DDR4 clock cycles
parameter tRTW = 13, // CL + (BL/2) - CWL + 4tCK In DDR4 clock cycles
parameter tWTR_L = 10, //In DDR4 clock cycles
parameter tWTR_S = 4, //In DDR4 clock cycles
parameter tRFC = 313, //In DDR4 clock cycles
parameter tREFI = 9363, //In DDR4 clock cycles
parameter ZQINTVL = 1200480193, //In DDR4 clock cycles
parameter tZQCS = 128, //In DDR4 clock cycles
parameter tRP = 16, //In DDR4 clock cycles
parameter tRRD_L = 8, //In DDR4 clock cycles
parameter tRRD_S = 7, //In DDR4 clock cycles
parameter tRAS = 39, //In DDR4 clock cycles
parameter tRCD = 16, //In DDR4 clock cycles
parameter tRTP = 10, //In DDR4 clock cycles
parameter tWR = 20, //In DDR4 clock cycles
- CAS Latency(CL)
- 从CAS(Column Active)发出,到DQS生成的间隔。
- 以t_CK个数为单位
- 在实际工作中,Bank地址与相应的行地址是同时发出的,此时这个命令称为“行激活”(Row Active),在此之后将发出列地址、bank地址与读写命令,此时称这个命令为“列激活”(Column Active)。
- 这里有个误区,开始认为bank地址只有在行激活时才有效,经过仿真发现在列激活时bank地址也是有效的
- t_RRD_S
- 决定位于不同groups 的两个Bank间的ACTIVATE命令时间间隔
- t_RRD_L
- 决定位于同groups 的两个Bank间的ACTIVATE命令时间间隔
- t_FAW
- 该参数制约不同groups 间的ACTIVATE命令个数,对于x16的DDR,每个groups有4个bank,所以tFAW时间间隔内不能发送超过4个ACTIVATE命令
- t_RCD
- 从行命令有效到读/写命令之间的时间间隔
- 以t_CK个数为单位
(五)对比
-
4片X16 DDR4
Operation AXI_4 app phy 时钟 300M 300M 1200M 数据位宽 512bit(64Byte) 512bit(64Byte) 64bit(8Byte) 数据结算方式 Byte Byte 2Byte 每个时钟地址增加 64 8(注1) 2(注2) 3332ps传输次数 1 1 8 3332ps传输总量 64Byte * 1(次) 64Byte * 1(次) 8Byte * 8(次) 注1:该地址为app_addrr地址,与phy侧地址一一对应,phy侧数据位宽即dq为宽为64(4片并联),表明phy侧每个时钟沿传输8byte。axi侧(或app侧)一个时钟发送数据总量为512bit(64Byte),会导致phy侧发送4个时钟周期共8次,也就是说phy侧地址增加8
注2:phy侧为ddr时序,每个时钟周期会触发两次传输,所以每个时钟phy侧地址增加2 -
不论DDR4内部实际存储空间怎样排布,对于 X16 的DDR4从phy侧看地址排布方式如下
+-----+
|16bit| <-phy_addr[0]
+-----+
|16bit| <-phy_addr[1]
+-----+
|16bit| <-phy_addr[2]
+-----+
|16bit|
+-----+
| . . . |
+-----+
|16bit|
+-----+
|16bit| <-phy_addr[gp + ba + row + col -1]
+-----+
- 对于4片并联 X16 的DDR4从phy侧看地址排布方式如下
|----------共64bit----------|
+-----++-----++-----++-----+
|16bit||16bit||16bit||16bit| <-phy_addr[0]
+-----++-----++-----++-----+
|16bit||16bit||16bit||16bit| <-phy_addr[1]
+-----++-----++-----++-----+
|16bit||16bit||16bit||16bit| <-phy_addr[2]
+-----++-----++-----++-----+
|16bit||16bit||16bit||16bit|
+-----++-----++-----++-----+
| . . . . . . . . |
+-----++-----++-----++-----+
|16bit||16bit||16bit||16bit|
+-----++-----++-----++-----+
|16bit||16bit||16bit||16bit| <-phy_addr[gp + ba + row + col -1]
+-----++-----++-----++-----+