这里以美光DDR4芯片 MT40A512M16HA-075E datasheet 为例,说明DDR4存储器的原理及仿真。
根据开发板手册ug1302,在vcu128(xcvu37p)开发板上,共具有5块DDR4芯片,在数据信号上4块DDR4具有16位数据线,1块DDR4具有8位数据线,共同构成72位数据线,在控制信号上共享相同信号线。
Xilinx MIG
在默认配置下,MIG配置如图所示。
通过展开IP层级,可以看到MIG的源码。
其中:
- u_mig_ddr4_phy为ddr4的物理层接口,主要负责IObuf、bitslice相关原语的配置例化、时钟生成、接口数据的输入输出。
- u_ddr_mc、u_ddr_ui、u_ddr4_cal_top负责ddr4读写指令的生成,将用户的输入的非AXI内存读写指令转换为ddr4的操作指令
- u_ddr_cal_riu为ddr4管理模块,其中包含一个microblaze软核用于控制ddr4的初始化、上板过程ddr4用户界面相关内容展示等操作。
DDR4初始化、读写操作
DDR4的基本操作过程与DDR3类似,这里根据使用verilog对DDR4的初始化、读写操作进行测试,可通过仿真模型测试,代码如下
- micron_ddr4_phy.sv 为顶层模块。
`timescale 1ns / 1ps
//
// Company:
// Engineer: wjh776a68
//
// Create Date: 01/17/2024 07:24:52 PM
// Design Name:
// Module Name: micron_ddr4
// Project Name:
// Target Devices: xcvu37p
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
// MT40A512M16LY-075E reference: https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/dram/ddr4/8gb_ddr4_sdram.pdf?rev=74679247a1e24e57b6726071152f1384
// ddr4 2666 16 18-18-18
// 2 bank group, 4 bank, 64k row, 1k column
/*********************************************************************************
* p367 timing parameters
* p41 reset time diagram
* tCK(DLL_ON) [0.75ns, 1.9ns]
* tAA 13.50ns
* tRCD 13.50ns
* tRP 13.50ns
*
*********************************************************************************/
module micron_ddr4_phy(
input clk_p // 100MHz
,input clk_n
,output [16 : 0] addr
,output [1 : 0] ba
,output [0 : 0] cke
,output [1 : 0] cs_n
,inout [8 : 0] dm_dbi_n
,inout [71 : 0] dq
,inout [8 : 0] dqs_c
,inout [8 : 0] dqs_t
,output [0 : 0] odt
,output [0 : 0] bg
,output reset_n
,output act_n
,output [0 : 0] ck_c
,output [0 : 0] ck_t
);
wire clk_I; // 100MHz
wire mmcm_clk_I, mmcm_clk_o_I, mmcm_clk6_o_I; // 100MHz
wire mmcm_clk_locked;
wire ctrl_udata_pll_clk_I; // 1333.333MHz
wire ctrl_udata_pll_clk_locked;
wire ctrl_udata_pll_clkfbout;
reg ctrl_udata_pll_phyclk_en = 1'b0;
wire mdata_pll_clk_I; // 1333.333MHz
wire mdata_pll_clk_locked;
wire mdata_pll_clkfbout;
reg mdata_pll_phyclk_en = 1'b0;
wire ldata_pll_clk_I; // 1333.333MHz
wire ldata_pll_clk_locked;
wire ldata_pll_clkfbout;
reg ldata_pll_phyclk_en = 1'b0;
wire usr_clk_p, usr_clk_n; // 333.333MHz
wire ctrl_udata_riu_clk_p, ctrl_udata_riu_clk_n; // 250MHz
wire mdata_riu_clk_p, mdata_riu_clk_n;
wire ldata_riu_clk_p, ldata_riu_clk_n;
reg clk_rst = 1;//, mmcm_clk_rst = 1, pll_clk_rst = 1;
(* srl_style = "srl_reg" *) reg [31:0] clk_rst_slr32 = {32{1'b1}};
(* srl_style = "srl_reg" *) reg [31:0] pll_clk_rst_slr32 = {32{1'b1}};
wire mmcm_clk_rst = clk_rst_slr32[31];
wire pll_clk_rst = pll_clk_rst_slr32[31];
wire ctrl_itf_rst_done, data_itf_rst_done;
wire itf_rst_done = ctrl_itf_rst_done & data_itf_rst_done; // byte initialization finish
always @(posedge clk_I) begin
clk_rst_slr32 <= {clk_rst_slr32[30:0], clk_rst};
clk_rst <= 1'b0;
end
always @(posedge clk_I) begin
if (mmcm_clk_locked) begin
pll_clk_rst_slr32 <= {pll_clk_rst_slr32[30:0], 1'b0};
end else begin
pll_clk_rst_slr32 <= {32{1'b1}};
end
end
IBUFDS IBUFDS_inst (
.O(clk_I), // 1-bit output: Buffer output
.I(clk_p), // 1-bit input: Diff_p buffer input (connect directly to top-level port)
.IB(clk_n) // 1-bit input: Diff_n buffer input (connect directly to top-level port)
);
wire mmcm_clk_CLKFBOUT;
MMCME4_BASE #(
.BANDWIDTH("OPTIMIZED"), // Jitter programming
.CLKFBOUT_MULT_F(10.0), // Multiply value for all CLKOUT
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB
.CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution (i.e., 33.333 is 30 MHz).
.CLKOUT0_DIVIDE_F(6.0), // Divide amount for CLKOUT0
.CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0
.CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0
.CLKOUT1_DIVIDE(6), // Divide amount for CLKOUT (1-128)
.CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999).
.CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000).
.CLKOUT2_DIVIDE(1), // Divide amount for CLKOUT (1-128)
.CLKOUT2_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999).
.CLKOUT2_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000).
.CLKOUT3_DIVIDE(1), // Divide amount for CLKOUT (1-128)
.CLKOUT3_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999).
.CLKOUT3_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000).
.CLKOUT4_CASCADE("FALSE"), // Divide amount for CLKOUT (1-128)
.CLKOUT4_DIVIDE(1), // Divide amount for CLKOUT (1-128)
.CLKOUT4_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999).
.CLKOUT4_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000).
.CLKOUT5_DIVIDE(1), // Divide amount for CLKOUT (1-128)
.CLKOUT5_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999).
.CLKOUT5_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000).
.CLKOUT6_DIVIDE(6), // Divide amount for CLKOUT (1-128)
.CLKOUT6_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999).
.CLKOUT6_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000).
.DIVCLK_DIVIDE(1), // Master division value
.IS_CLKFBIN_INVERTED(1'b0), // Optional inversion for CLKFBIN
.IS_CLKIN1_INVERTED(1'b0), // Optional inversion for CLKIN1
.IS_PWRDWN_INVERTED(1'b0), // Optional inversion for PWRDWN
.IS_RST_INVERTED(1'b0), // Optional inversion for RST
.REF_JITTER1(0.02), // Reference input jitter in UI (0.000-0.999).
.STARTUP_WAIT("FALSE") // Delays DONE until MMCM is locked
)
MMCME4_BASE_inst ( // 100MHz to 1000MHz(VCO) -> 166.667MHz
.CLKFBOUT(mmcm_clk_CLKFBOUT), // 1-bit output: Feedback clock pin to the MMCM
.CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT
.CLKOUT0(mmcm_clk_o_I), // 1-bit output: CLKOUT0
.CLKOUT0B(), // 1-bit output: Inverted CLKOUT0
.CLKOUT1(), // 1-bit output: CLKOUT1
.CLKOUT1B(), // 1-bit output: Inverted CLKOUT1
.CLKOUT2(), // 1-bit output: CLKOUT2
.CLKOUT2B(), // 1-bit output: Inverted CLKOUT2
.CLKOUT3(), // 1-bit output: CLKOUT3
.CLKOUT3B(), // 1-bit output: Inverted CLKOUT3
.CLKOUT4(), // 1-bit output: CLKOUT4
.CLKOUT5(), // 1-bit output: CLKOUT5
.CLKOUT6(mmcm_clk6_o_I), // 1-bit output: CLKOUT6
.LOCKED(mmcm_clk_locked), // 1-bit output: LOCK
.CLKFBIN(mmcm_clk_CLKFBOUT), // 1-bit input: Feedback clock pin to the MMCM
.CLKIN1(clk_I), // 1-bit input: Primary clock
.PWRDWN(1'b0), // 1-bit input: Power-down
.RST(mmcm_clk_rst) // 1-bit input: Reset
);
BUFGCE #(
.CE_TYPE("SYNC"), // ASYNC, HARDSYNC, SYNC
.IS_CE_INVERTED(1'b0), // Programmable inversion on CE
.IS_I_INVERTED(1'b0), // Programmable inversion on I
.SIM_DEVICE("ULTRASCALE_PLUS") // ULTRASCALE, ULTRASCALE_PLUS
)
BUFGCE_pll_inst (
.O(mmcm_clk_I), // 1-bit output: Buffer
.CE(mmcm_clk_locked), // 1-bit input: Buffer enable
.I(mmcm_clk_o_I) // 1-bit input: Buffer
);
BUFGCE #(
.CE_TYPE("SYNC"), // ASYNC, HARDSYNC, SYNC
.IS_CE_INVERTED(1'b0), // Programmable inversion on CE
.IS_I_INVERTED(1'b0), // Programmable inversion on I
.SIM_DEVICE("ULTRASCALE_PLUS") // ULTRASCALE, ULTRASCALE_PLUS
)
BUFGCE_riu_inst (
.O(), // 1-bit output: Buffer
.CE(mmcm_clk_locked), // 1-bit input: Buffer enable
.I(mmcm_clk6_o_I) // 1-bit input: Buffer
);
PLLE4_BASE #(
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB
.CLKIN_PERIOD(6.0), // Input clock period in ns to ps resolution (i.e., 33.333 is 30 MHz).
.CLKOUT0_DIVIDE(8), // Divide amount for CLKOUT0
.CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0
.CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0
.CLKOUT1_DIVIDE(4), // Divide amount for CLKOUT1
.CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT1
.CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT1
.CLKOUTPHY_MODE("VCO_2X"), // Frequency of the CLKOUTPHY
.DIVCLK_DIVIDE(1), // Master division value
.IS_CLKFBIN_INVERTED(1'b0), // Optional inversion for CLKFBIN
.IS_CLKIN_INVERTED(1'b0), // Optional inversion for CLKIN
.IS_PWRDWN_INVERTED(1'b0), // Optional inversion for PWRDWN
.IS_RST_INVERTED(1'b0), // Optional inversion for RST
.REF_JITTER(0.02), // Reference input jitter in UI
.STARTUP_WAIT("FALSE") // Delays DONE until PLL is locked
)
PLLE4_BASE_ctrl_udata_inst ( // 166.667MHz to 2666.6MHz (PHY) and 1333.3/4 MHz (usr_clk)
.CLKFBOUT(ctrl_udata_pll_clkfbout), // 1-bit output: Feedback clock
.CLKOUT0(ctrl_udata_riu_clk_p), //ctrl_udata_riu_clk_p), // 1-bit output: General Clock output
.CLKOUT0B(), //ctrl_udata_riu_clk_n), // 1-bit output: Inverted CLKOUT0
.CLKOUT1(usr_clk_p), // 1-bit output: General Clock output 1333.333/8MHz user clock for riu clk(<260MHz)
.CLKOUT1B(usr_clk_n), // 1-bit output: Inverted CLKOUT1
.CLKOUTPHY(ctrl_udata_pll_clk_I), // 1-bit output: Bitslice clock
.LOCKED(ctrl_udata_pll_clk_locked), // 1-bit output: LOCK
.CLKFBIN(ctrl_udata_pll_clkfbout), // 1-bit input: Feedback clock
.CLKIN(mmcm_clk_I), // 1-bit input: Input clock
.CLKOUTPHYEN(ctrl_udata_pll_phyclk_en), // 1-bit input: CLKOUTPHY enable
.PWRDWN(1'b0), // 1-bit input: Power-down
.RST(pll_clk_rst) // 1-bit input: Reset
);
PLLE4_BASE #(
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB
.CLKIN_PERIOD(6.0), // Input clock period in ns to ps resolution (i.e., 33.333 is 30 MHz).
.CLKOUT0_DIVIDE(8), // Divide amount for CLKOUT0
.CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0
.CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0
.CLKOUT1_DIVIDE(4), // Divide amount for CLKOUT1
.CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT1
.CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT1
.CLKOUTPHY_MODE("VCO_2X"), // Frequency of the CLKOUTPHY
.DIVCLK_DIVIDE(1), // Master division value
.IS_CLKFBIN_INVERTED(1'b0), // Optional inversion for CLKFBIN
.IS_CLKIN_INVERTED(1'b0), // Optional inversion for CLKIN
.IS_PWRDWN_INVERTED(1'b0), // Optional inversion for PWRDWN
.IS_RST_INVERTED(1'b0), // Optional inversion for RST
.REF_JITTER(0.0), // Reference input jitter in UI
.STARTUP_WAIT("FALSE") // Delays DONE until PLL is locked
)
PLLE4_BASE_mdata_inst ( // 500MHz to 2666.6MHz (PHY) and 1333.3/4 MHz (usr_clk)
.CLKFBOUT(mdata_pll_clkfbout), // 1-bit output: Feedback clock
.CLKOUT0(mdata_riu_clk_p), // 1-bit output: General Clock output
.CLKOUT0B(mdata_riu_clk_n), // 1-bit output: Inverted CLKOUT0
.CLKOUT1(), // 1-bit output: General Clock output 1333.333/8MHz user clock for riu clk(<260MHz)
.CLKOUT1B(), // 1-bit output: Inverted CLKOUT1
.CLKOUTPHY(mdata_pll_clk_I), // 1-bit output: Bitslice clock
.LOCKED(mdata_pll_clk_locked), // 1-bit output: LOCK
.CLKFBIN(mdata_pll_clkfbout), // 1-bit input: Feedback clock
.CLKIN(mmcm_clk_I), // 1-bit input: Input clock
.CLKOUTPHYEN(mdata_pll_phyclk_en), // 1-bit input: CLKOUTPHY enable
.PWRDWN(1'b0), // 1-bit input: Power-down
.RST(pll_clk_rst) // 1-bit input: Reset
);
PLLE4_BASE #(
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB
.CLKIN_PERIOD(6.0), // Input clock period in ns to ps resolution (i.e., 33.333 is 30 MHz).
.CLKOUT0_DIVIDE(8), // Divide amount for CLKOUT0
.CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0
.CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0
.CLKOUT1_DIVIDE(4), // Divide amount for CLKOUT1
.CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT1
.CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT1
.CLKOUTPHY_MODE("VCO_2X"), // Frequency of the CLKOUTPHY
.DIVCLK_DIVIDE(1), // Master division value
.IS_CLKFBIN_INVERTED(1'b0), // Optional inversion for CLKFBIN
.IS_CLKIN_INVERTED(1'b0), // Optional inversion for CLKIN
.IS_PWRDWN_INVERTED(1'b0), // Optional inversion for PWRDWN
.IS_RST_INVERTED(1'b0), // Optional inversion for RST
.REF_JITTER(0.02), // Reference input jitter in UI
.STARTUP_WAIT("FALSE") // Delays DONE until PLL is locked
)
PLLE4_BASE_ldata_inst ( // 500MHz to 2666.6MHz (PHY) and 1333.3/4 MHz (usr_clk)
.CLKFBOUT(ldata_pll_clkfbout), // 1-bit output: Feedback clock
.CLKOUT0(ldata_riu_clk_p), // 1-bit output: General Clock output
.CLKOUT0B(ldata_riu_clk_n), // 1-bit output: Inverted CLKOUT0
.CLKOUT1(), // 1-bit output: General Clock output 1333.333/8MHz user clock for riu clk(<260MHz)
.CLKOUT1B(), // 1-bit output: Inverted CLKOUT1
.CLKOUTPHY(ldata_pll_clk_I), // 1-bit output: Bitslice clock
.LOCKED(ldata_pll_clk_locked), // 1-bit output: LOCK
.CLKFBIN(ldata_pll_clkfbout), // 1-bit input: Feedback clock
.CLKIN(mmcm_clk_I), // 1-bit input: Input clock
.CLKOUTPHYEN(ldata_pll_phyclk_en), // 1-bit input: CLKOUTPHY enable
.PWRDWN(1'b0), // 1-bit input: Power-down
.RST(pll_clk_rst) // 1-bit input: Reset
);
(* srl_style = "srl_reg" *) reg [63:0] pll_clk_rst_fin_slr64 = {64{1'b0}};
wire pll_clk_rst_fin = pll_clk_rst_fin_slr64[63];
always @(posedge mmcm_clk_I) begin
if (ctrl_udata_pll_clk_locked & mdata_pll_clk_locked & ldata_pll_clk_locked) begin
pll_clk_rst_fin_slr64[31:0] <= {pll_clk_rst_fin_slr64[31 - 1 : 0], 1'b1};
pll_clk_rst_fin_slr64[63:32] <= {pll_clk_rst_fin_slr64[63 - 1 : 32], pll_clk_rst_fin_slr64[31]};
end else begin
pll_clk_rst_fin_slr64[31:0] <= {32{1'b0}};
pll_clk_rst_fin_slr64[63:32] <= {32{1'b0}};
end
end
logic delay_rst = 0;
logic ctrl_rst = 0;
always @(posedge mmcm_clk_I) begin
if (pll_clk_rst_fin) begin
ctrl_udata_pll_phyclk_en <= 1'b1;
mdata_pll_phyclk_en <= 1'b1;
ldata_pll_phyclk_en <= 1'b1;
end else begin
ctrl_udata_pll_phyclk_en <= 1'b0;
mdata_pll_phyclk_en <= 1'b0;
ldata_pll_phyclk_en <= 1'b0;
end
end
always @(posedge mmcm_clk_I) begin
if (ctrl_udata_pll_clk_locked & mdata_pll_clk_locked & ldata_pll_clk_locked) begin
delay_rst <= 1'b0;
ctrl_rst <= 1'b0;
end else begin
delay_rst <= 1'b1;
ctrl_rst <= 1'b1;
end
end
logic [7:0] addr_o_I[16:0];
logic [7:0] ba_o_I[1:0];
logic [7:0] bg_o_I;
logic [7:0] cs_n_o_I[1:0];
logic [7:0] cke_o_I;
logic [7:0] act_n_o_I;
logic [7:0] odt_o_I;
logic [7:0] ck_o_I;
logic [7:0] reset_n_o_I;
micron_ddr4_ctrl #(
.CLK_FREQ(2666.666) // 4 * 333.333
) micron_ddr4_ctrl_inst(
.pll_clk(ctrl_udata_pll_clk_I),
.riu_clk(ctrl_udata_riu_clk_p),
.delay_rst(delay_rst), // async
.ctrl_rst(ctrl_rst), // async
.itf_rst_done(ctrl_itf_rst_done), //
.addr(addr),
.ba(ba),
.bg(bg),
.cke(cke),
.cs_n(cs_n[1]),
.act_n(act_n),
.odt(odt),
.ck_t(ck_t),
.ck_c(ck_c),
.reset_n(reset_n),
.addr_o_I(addr_o_I),
.ba_o_I(ba_o_I),
.bg_o_I(bg_o_I),
.cs_n_o_I(cs_n_o_I[1:1]),
.cke_o_I(cke_o_I),
.act_n_o_I(act_n_o_I),
.odt_o_I(odt_o_I),
.ck_o_I(ck_o_I),
.reset_n_o_I(reset_n_o_I)
);
logic [3:0] TRI_TBYTE_IN[8:0];
logic [3:0] PHY_RDEN[8:0];
logic [3:0] lo_TRI_TBYTE_IN[8:0];
logic [3:0] hi_TRI_TBYTE_IN[8:0];
reg [3:0] lo_PHY_RDEN[8:0],
hi_PHY_RDEN[8:0];
reg cs_n_T_IN = 0;
logic [7:0] dm_dbi_n_o_I[8:0];
logic dm_dbi_n_FIFO_EMPTY[8:0];
logic dm_dbi_n_FIFO_RD_CLK[8:0];
logic dm_dbi_n_FIFO_RD_EN[8:0];
logic [7:0] dq_o_I[71:0];
logic dq_FIFO_EMPTY[71:0];
logic dq_FIFO_RD_CLK[71:0];
logic dq_FIFO_RD_EN[71:0];
logic [7:0] dqs_o_I[8:0];
logic dqs_FIFO_EMPTY[8:0];
logic dqs_FIFO_RD_CLK[8:0];
logic dqs_FIFO_RD_EN[8:0];
// logic [7:0] cs_n_o_I[0:0] = {0};
logic [7:0] dm_dbi_n_i_I[8:0];
logic [7:0] dq_i_I[71:0];
logic [7:0] dqs_i_I[8:0];
micron_ddr4_data #(
.CLK_FREQ(2666.666) // 4 * 333.333 * 2
) micron_ddr4_data_inst (
.pll_clk_bank0(ldata_pll_clk_I),
.pll_clk_bank1(mdata_pll_clk_I),
.pll_clk_bank2(ctrl_udata_pll_clk_I),
.riu_clk_bank0(ldata_riu_clk_p), //ldata_riu_clk_p),
.riu_clk_bank1(mdata_riu_clk_p), //mdata_riu_clk_p),
.riu_clk_bank2(ctrl_udata_riu_clk_p),
.delay_rst(delay_rst),
.ctrl_rst(ctrl_rst),
.itf_rst_done(data_itf_rst_done),
.dm_dbi_n(dm_dbi_n),
.dq(dq),
.dqs_t(dqs_t),
.dqs_c(dqs_c),
.cs_n(cs_n[0]),
.lo_TRI_TBYTE_IN(lo_TRI_TBYTE_IN),
.hi_TRI_TBYTE_IN(hi_TRI_TBYTE_IN),
.lo_PHY_RDEN(lo_PHY_RDEN),
.hi_PHY_RDEN(hi_PHY_RDEN),
.cs_n_T_IN(1'b1),
.dm_dbi_n_o_I(dm_dbi_n_o_I),
.dq_o_I(dq_o_I),
.dqs_o_I(dqs_o_I),
.cs_n_o_I(cs_n_o_I[0:0]),
.dm_dbi_n_i_I(dm_dbi_n_i_I),
.dm_dbi_n_FIFO_EMPTY(dm_dbi_n_FIFO_EMPTY),
.dm_dbi_n_FIFO_RD_CLK(dm_dbi_n_FIFO_RD_CLK),
.dm_dbi_n_FIFO_RD_EN(dm_dbi_n_FIFO_RD_EN),
.dq_i_I(dq_i_I),
.dq_FIFO_EMPTY(dq_FIFO_EMPTY),
.dq_FIFO_RD_CLK(dq_FIFO_RD_CLK),
.dq_FIFO_RD_EN(dq_FIFO_RD_EN),
.dqs_i_I(dqs_i_I),
.dqs_FIFO_EMPTY(dqs_FIFO_EMPTY),
.dqs_FIFO_RD_CLK(dqs_FIFO_RD_CLK),
.dqs_FIFO_RD_EN(dqs_FIFO_RD_EN)
);
always @(*) begin
for (int j = 0; j < 9; j++) begin
dm_dbi_n_FIFO_RD_CLK[j] = usr_clk_p;
dqs_FIFO_RD_CLK[j] = usr_clk_p;
for (int i = 0; i < 8; i++) begin
dq_FIFO_RD_CLK[8 * j + i] = usr_clk_p;
end
end
end
always @(*) begin // test1
for (int j = 0; j < 9; j++) begin
for (int i = 0; i < 8; i++) begin
dq_FIFO_RD_EN[8 * j + i] = ~dq_FIFO_EMPTY[8 * j];
end
dqs_FIFO_RD_EN[j] = ~dq_FIFO_EMPTY[8 * j];
dm_dbi_n_FIFO_RD_EN[j] = ~dq_FIFO_EMPTY[8 * j];
end
end
// always @(posedge usr_clk_p) begin // follow ug571
// for (int j = 0; j < 9; j++) begin
// for (int i = 0; i < 8; i++) begin
// dq_FIFO_RD_EN[8 * j + i] <= ~dq_FIFO_EMPTY[8 * j];
// end
// dqs_FIFO_RD_EN[j] <= ~dq_FIFO_EMPTY[8 * j];
// dm_dbi_n_FIFO_RD_EN[j] <= ~dq_FIFO_EMPTY[8 * j];
// end
// end
always @(*) begin
for (int i = 0; i < 9; i++) begin
lo_TRI_TBYTE_IN[i] = TRI_TBYTE_IN[i];
hi_TRI_TBYTE_IN[i] = TRI_TBYTE_IN[i];
lo_PHY_RDEN[i] = PHY_RDEN[i];
hi_PHY_RDEN[i] = PHY_RDEN[i];
end
end
logic dm_dbi_n_i_valid[8:0], dq_i_valid[71:0], dqs_i_valid[8:0];
always @(posedge usr_clk_p) begin
for (int i = 0; i < 9; i++) begin
dm_dbi_n_i_valid[i] <= dm_dbi_n_FIFO_RD_EN[i];
for (int j = 0; j < 8; j++) begin
dq_i_valid[j + 8 * i] <= dq_FIFO_RD_EN[j + 8 * i];
end
dqs_i_valid[i] <= dqs_FIFO_RD_EN[i];
end
end
logic ram_clk;
logic [29:0] ram_addr;
logic [575:0] ram_rd_data;
logic ram_en;
logic [575:0] ram_wr_data;
logic ram_wr;
logic ram_rdy;
micron_ddr4_fabric micron_ddr4_fabric_inst(
.usr_clk(usr_clk_p),
.itf_rst_done(itf_rst_done),
.TRI_TBYTE_IN(TRI_TBYTE_IN),
.PHY_RDEN(PHY_RDEN),
.addr_o_data(addr_o_I),
.ba_o_data(ba_o_I),
.bg_o_data(bg_o_I),
.cs_n_o_data(cs_n_o_I),
.cke_o_data(cke_o_I),
.act_n_o_data(act_n_o_I),
.odt_o_data(odt_o_I),
.ck_o_data(ck_o_I),
.reset_n_o_data(reset_n_o_I),
.dm_dbi_n_o_data(dm_dbi_n_o_I),
.dq_o_data(dq_o_I),
.dqs_o_data(dqs_o_I),
.dm_dbi_n_i_data(dm_dbi_n_i_I),
.dm_dbi_n_i_valid(dm_dbi_n_i_valid),
.dq_i_data(dq_i_I),
.dq_i_valid(dq_i_valid),
.dqs_i_data(dqs_i_I),
.dqs_i_valid(dqs_i_valid),
.ram_clk(ram_clk),
.ram_addr(ram_addr),
.ram_rd_data(ram_rd_data),
.ram_en(ram_en),
.ram_wr_data(ram_wr_data),
.ram_wr(ram_wr),
.ram_rdy(ram_rdy)
);
micron_ddr4_usr micron_ddr4_usr_inst(
.ram_clk(ram_clk),
.ram_addr(ram_addr),
.ram_rd_data(ram_rd_data),
.ram_en(ram_en),
.ram_wr_data(ram_wr_data),
.ram_wr(ram_wr),
.ram_rdy(ram_rdy)
);
endmodule
- micron_ddr4_fabric.sv 为控制模块,包含初始化操作,同时根据输入读写指令进行读写操作
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 02/01/2024 05:07:15 PM
// Design Name:
// Module Name: micron_ddr4_fabric
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
// MT40A512M16LY-075E reference: https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/dram/ddr4/8gb_ddr4_sdram.pdf?rev=74679247a1e24e57b6726071152f1384
// ddr4 2666 16 18-18-18
// 2 bank group, 4 bank, 64k row, 1k column
/*********************************************************************************
* p367 timing parameters
* p41 reset time diagram
* p69 truth table
* tCK(DLL_ON) [0.75ns, 1.9ns]
* tAA 13.50ns
* tRCD 13.50ns
* tRP 13.50ns
*
*********************************************************************************/
/************************** MACRO *********************************************/
//`define TIMEUS_INT(a) int(a * 1000 / CYCLE)
//`define TIMEMS_INT(a) int(a * 1000000 / CYCLE)
// vcu128 using five(precisely 4.5) ddr4 chips with x16 datawidth (REF UG1302)
module micron_ddr4_fabric #(
parameter CYCLE = 3, // 0.75ns * 4
parameter CYCLE_1US = 1000 / CYCLE,
parameter CYCLE_1MS = 1000000 / CYCLE,
parameter tXPR = 360,
parameter tMRD = 6,
parameter tMOD = 18,
parameter tDLLK = 640.5,
parameter tZQinit = 768
) (
input usr_clk,
input itf_rst_done,
output reg [3:0] TRI_TBYTE_IN[8:0],
output reg [3:0] PHY_RDEN[8:0],
output reg [7:0] addr_o_data[16:0],
output reg [7:0] ba_o_data[1:0],
output reg [7:0] bg_o_data,
output reg [7:0] cs_n_o_data[1:0],
output reg [7:0] cke_o_data,
output reg [7:0] act_n_o_data,
output reg [7:0] odt_o_data,
output reg [7:0] ck_o_data,
output reg [7:0] reset_n_o_data,
output reg [7:0] dm_dbi_n_o_data[8:0],
output reg [7:0] dq_o_data[71:0],
output reg [7:0] dqs_o_data[8:0],
input [7:0] dm_dbi_n_i_data[8:0],
input dm_dbi_n_i_valid[8:0],
input [7:0] dq_i_data[71:0],
input dq_i_valid[71:0],
input [7:0] dqs_i_data[8:0],
input dqs_i_valid[8:0],
output ram_clk,
input [29:0] ram_addr,
output reg [575:0] ram_rd_data,
input ram_en,
input [575:0] ram_wr_data,
input ram_wr,
output reg ram_rdy
);
assign ram_clk = usr_clk;
function [31:0] TIMENS_INT(input [31:0] a);
return (a - CYCLE)/ CYCLE + 1; // ceil
endfunction
function [31:0] TIMEUS_INT(input [31:0] a);
return (1000 * a - CYCLE) / CYCLE + 1; // ceil
endfunction
(* MARK_DEBUG="true" *) reg [5:0] cs = 0, ns;
(* ASYNC_REG="true" *) reg itf_rst_done_ff = 1'b0, itf_rst_done_ff2 = 1'b0; // riu_clk domain to usr_clk domain
reg ddr_reset_fin_r = 1'b0,
ddr_init_fin_r = 1'b0,
ddr_activate_delay_fin_r = 1'b0,
ddr_rd_delay_fin_r = 1'b0,
ddr_rddata_delay_fin_r_all_r = 1'b0,
ddr_wr_delay_fin_r = 1'b0,
ddr_wrdata_delay_fin_r = 1'b0,
ddr_precharge_delay_fin_r = 1'b0;
always @(posedge usr_clk) begin
itf_rst_done_ff <= itf_rst_done;
itf_rst_done_ff2 <= itf_rst_done_ff;
end
always @(posedge usr_clk, negedge itf_rst_done_ff2) begin
if (~itf_rst_done_ff2) begin
cs <= 0;
end else begin
cs <= ns;
end
end
always @(*) begin
case (cs)
0: begin // hardware io banks reset
ns = 1;
end
1: begin
ns = 2;
end
2: begin // ddr reset
if (ddr_reset_fin_r) begin
ns = 3;
end else begin
ns = 2;
end
end
3: begin // ddr initialization seq
if (ddr_init_fin_r) begin
ns = 4;
end else begin
ns = 3;
end
end
4: begin // ddr idle state
case ({ram_en, ram_wr})
2'b10: ns = 6;
2'b11: ns = 10;
default: begin
// if (ddr_idle_fin_r) begin // goto refresh
// ns = 5;
// end else begin
ns = 4;
// end
end
endcase
end
5: begin // ddr refresh
ns = 4;
end
6: begin // ddr activate
if (ddr_activate_delay_fin_r) begin
ns = 7;
end else begin
ns = 6;
end
end
7: begin // ddr send rd command
if (ddr_rd_delay_fin_r) begin
ns = 8;
end else begin
ns = 7;
end
end
8: begin // ddr get data
if (ddr_rddata_delay_fin_r_all_r) begin
ns = 9;
end else begin
ns = 8;
end
end
9: begin // ddr precharge
if (ddr_precharge_delay_fin_r) begin
ns = 4;
end else begin
ns = 9;
end
end
10: begin // ddr activate
if (ddr_activate_delay_fin_r) begin
ns = 11;
end else begin
ns = 10;
end
end
11: begin // ddr send wr command
if (ddr_wr_delay_fin_r) begin
ns = 12;
end else begin
ns = 11;
end
end
12: begin // ddr put data
ns = 13;
end
13: begin // ddr put rest data
ns = 14;
end
14: begin // ddr precharge
if (ddr_precharge_delay_fin_r) begin
ns = 4;
end else begin
ns = 14;
end
end
default: begin
ns = 0;
end
endcase
end
/******************** function definitions begin *****************************/
task io_bank_reset();
PHY_RDEN <= {4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000};
TRI_TBYTE_IN <= {4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000};
for (int i = 0; i < 17; i++) begin
addr_o_data[i] <= 8'b00000000;
end
for (int i = 0; i < 2; i++) begin
ba_o_data[i] <= 8'b00000000;
end
bg_o_data <= 8'b00000000;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b11111111;
end
cke_o_data <= 8'b00000000;
act_n_o_data <= 8'b00000000;
odt_o_data <= 8'b00000000;
ck_o_data <= 8'b00000000;
reset_n_o_data <= 8'b00000000;
for (int i = 0; i < 9; i++) begin
dqs_o_data[i] <= 8'b00000000;
dm_dbi_n_o_data[i] <= 8'b00000000;
end
for (int i = 0; i < 72; i++) begin
dq_o_data[i] <= 8'b00000000;
end
endtask
task CMD_MRS(input [1:0] _cs_n, input _bg, input [1:0] _ba, input [13:0] _opcode);
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= {_cs_n[i], _cs_n[i], 6'b111111};
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b00111111;
addr_o_data[15] <= 8'b00111111;
addr_o_data[14] <= 8'b00111111;
bg_o_data <= {_bg, _bg, 6'b0};
for (int i = 0; i < 2; i++) begin
ba_o_data[i] <= {_ba[i], _ba[i], 6'b0};
end
for (int i = 0; i < 14; i++) begin
addr_o_data[i] <= {_opcode[i], _opcode[i], 6'b0};
end
endtask
task CMD_DES();
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b11111111;
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b00111111;
addr_o_data[15] <= 8'b00111111;
addr_o_data[14] <= 8'b00111111;
endtask
task CMD_ZQCL(input [1:0] _cs_n);
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= {_cs_n[i], _cs_n[i], 6'b111111};
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b11111111;
addr_o_data[15] <= 8'b11111111;
addr_o_data[14] <= 8'b00111111;
addr_o_data[10] <= 8'b11000000;
endtask
task CMD_NOP();
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b00111111;
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b11111111;
addr_o_data[15] <= 8'b11111111;
addr_o_data[14] <= 8'b11111111;
endtask
task CMD_NUL();
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b11111111;
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b11111111;
addr_o_data[15] <= 8'b11111111;
addr_o_data[14] <= 8'b11111111;
endtask
task CMD_ACT(input _bg, input [1:0] _ba, input [16:0] _ra);
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b00111111;
end
act_n_o_data <= 8'b00111111;
addr_o_data[16] <= {_ra[16], _ra[16], 6'b111111};
addr_o_data[15] <= {_ra[15], _ra[15], 6'b111111};
addr_o_data[14] <= {_ra[14], _ra[14], 6'b111111};
addr_o_data[12] <= {_ra[13], _ra[13], 6'b111111};
addr_o_data[13] <= {_ra[12], _ra[12], 6'b111111};
addr_o_data[11] <= {_ra[11], _ra[11], 6'b111111};
for (int i = 0; i < 11; i++) begin
addr_o_data[i] <= {_ra[i], _ra[i], 6'b111111};
end
bg_o_data <= {_bg, _bg, 6'b0};
for (int i = 0; i < 2; i++) begin
ba_o_data[i] <= {_ba[i], _ba[i], 6'b0};
end
endtask
task CMD_WR(input _bg, input [1:0] _ba, input [9:0] _ca);
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b00111111;
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b11111111;
addr_o_data[15] <= {2'b00, 6'b111111};
addr_o_data[14] <= {2'b00, 6'b111111};
addr_o_data[12] <= {2'bxx, 6'b111111};
addr_o_data[13] <= {2'bxx, 6'b111111};
addr_o_data[11] <= {2'bxx, 6'b111111};
addr_o_data[10] <= {2'b00, 6'b111111};
for (int i = 0; i < 10; i++) begin
addr_o_data[i] <= {_ca[i], _ca[i], 6'b111111};
end
bg_o_data <= {_bg, _bg, 6'b0};
for (int i = 0; i < 2; i++) begin
ba_o_data[i] <= {_ba[i], _ba[i], 6'b0};
end
endtask
task CMD_RD(input _bg, input [1:0] _ba, input [9:0] _ca);
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b00111111;
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b11111111;
addr_o_data[15] <= {2'b00, 6'b111111};
addr_o_data[14] <= {2'b11, 6'b111111};
addr_o_data[12] <= {2'bxx, 6'b111111};
addr_o_data[13] <= {2'bxx, 6'b111111};
addr_o_data[11] <= {2'bxx, 6'b111111};
addr_o_data[10] <= {2'b00, 6'b111111};
for (int i = 0; i < 10; i++) begin
addr_o_data[i] <= {_ca[i], _ca[i], 6'b111111};
end
bg_o_data <= {_bg, _bg, 6'b0};
for (int i = 0; i < 2; i++) begin
ba_o_data[i] <= {_ba[i], _ba[i], 6'b0};
end
endtask
task CMD_PRE(input _bg, input [1:0] _ba);
ck_o_data <= 8'b10101010;
cke_o_data <= 8'b11111111;
for (int i = 0; i < 2; i++) begin
cs_n_o_data[i] <= 8'b00111111;
end
act_n_o_data <= 8'b11111111;
addr_o_data[16] <= 8'b00111111;
addr_o_data[15] <= {2'b11, 6'b111111};
addr_o_data[14] <= {2'b00, 6'b111111};
addr_o_data[12] <= {2'bxx, 6'b111111};
addr_o_data[13] <= {2'bxx, 6'b111111};
addr_o_data[11] <= {2'bxx, 6'b111111};
addr_o_data[10] <= {2'b00, 6'b111111};
for (int i = 0; i < 10; i++) begin
addr_o_data[i] <= {2'bxx, 6'b111111};
end
bg_o_data <= {_bg, _bg, 6'b0};
for (int i = 0; i < 2; i++) begin
ba_o_data[i] <= {_ba[i], _ba[i], 6'b0};
end
endtask
/***************** function definitions end ***********************/
/****************** reset related logic start **********************/
reg [31:0] ddr_reset_fin_cnt_r = 32'b0;
reg [1:0] ddr_reset_stage_r = 2'b0;
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_reset_fin_cnt_r <= TIMEUS_INT(698); //32'b0; //XILINX_SIMULATOR
end
2: begin
ddr_reset_fin_cnt_r <= ddr_reset_fin_cnt_r + 1;
end
endcase
end
always @(posedge usr_clk) begin // usr_clk 0.75ns * 4 ->
case (ddr_reset_fin_cnt_r)
TIMEUS_INT(0): begin // Ta: 0
ddr_reset_stage_r <= 2'b00;
end
TIMEUS_INT(200): begin // Tb: tPW_RESET_L : 200 us
ddr_reset_stage_r <= 2'b01;
end
TIMEUS_INT(698): begin // Tc: tPW_RESET_L + 500us - tCKSRX : 700us - min(5CK, 10ns) -> max(699us)
ddr_reset_stage_r <= 2'b10;
end
TIMEUS_INT(699): begin // Td-: tPW_RESET_L + 500us - tIS : 700us - 55ps -> 699us
ddr_reset_stage_r <= 2'b11;
end
default: begin
ddr_reset_stage_r <= ddr_reset_stage_r;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_reset_fin_cnt_r)
TIMEUS_INT(700 + 3): begin // Td: 700us
ddr_reset_fin_r <= 1'b1;
end
default: begin
ddr_reset_fin_r <= 1'b0;
end
endcase
end
/************************** reset related logic end ******************/
/********************** initialization related logic ******************/
reg [31:0] ddr_init_fin_cnt_r = 32'b0;
reg [4:0] ddr_init_stage_r = 5'b00000;
reg ddr_init_stage_fresh_r = 1'b0;
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_init_fin_cnt_r <= 32'b0;
end
3: begin
ddr_init_fin_cnt_r <= ddr_init_fin_cnt_r + 1;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_init_fin_cnt_r)
TIMENS_INT(tXPR): begin // Te : tXPR : min(tRFC1 + 10ns) -> min 360ns
ddr_init_stage_r <= 5'b00000;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + tMRD): begin // Tf : tXPR + tMRD : 360ns + 8CK -> 366ns
ddr_init_stage_r <= 5'b00001;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 2 * tMRD): begin // Tg : tXPR + 2 * tMRD -> 372ns
ddr_init_stage_r <= 5'b00010;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 3 * tMRD): begin // Th : tXPR + 3 * tMRD -> 378ns
ddr_init_stage_r <= 5'b00011;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 4 * tMRD): begin // Th : tXPR + 4 * tMRD -> 384ns
ddr_init_stage_r <= 5'b00100;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 5 * tMRD): begin // Th : tXPR + 5 * tMRD -> 390ns
ddr_init_stage_r <= 5'b00101;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD): begin // Th : tXPR + 6 * tMRD -> 396ns
ddr_init_stage_r <= 5'b00110;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD): begin // Ti : tXPR + 6 * tMRD + tMOD : min(306ns + max(24nCK, 15ns)) -> 414ns
ddr_init_stage_r <= 5'b00111;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tDLLK): begin // Tj : tXPR + 6 * tMRD + tDLLK -> 324ns + 854CK -> 1036.5ns
ddr_init_stage_r <= 5'b01000;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit): begin // Tk : tXPR + 6 * tMRD + tMOD + tZQinit : 324ns + 1024CK -> 1182ns
ddr_init_stage_r <= 5'b10000;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + tMRD): begin // T0 : Tk + tMRD : 1092ns + 8CK -> 1188ns
ddr_init_stage_r <= 5'b10001;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 2 * tMRD): begin // T1 : Tk + 2 * tMRD -> 1194ns
ddr_init_stage_r <= 5'b10010;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 3 * tMRD): begin // T2 : Tk + 3 * tMRD -> 1200ns
ddr_init_stage_r <= 5'b10011;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 4 * tMRD): begin // T3 : Tk + 4 * tMRD -> 1206ns
ddr_init_stage_r <= 5'b10100;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 5 * tMRD): begin // T4 : Tk + 5 * tMRD -> 1212ns
ddr_init_stage_r <= 5'b10101;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 6 * tMRD): begin // T5 : Tk + 6 * tMRD -> 1218ns
ddr_init_stage_r <= 5'b10110;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 6 * tMRD + tMOD): begin // T6 : Tk + 6 * tMRD + tMOD : min(1128ns + max(24nCK, 15ns)) -> 1236ns
ddr_init_stage_r <= 5'b10111;
ddr_init_stage_fresh_r <= 1'b1;
end
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 6 * tMRD + tDLLK): begin // T7 : Tk + 6 * tMRD + tDLLK -> 1128ns + 854CK -> 1840.5ns
ddr_init_stage_r <= 5'b11000;
ddr_init_stage_fresh_r <= 1'b1;
end
default: begin
ddr_init_stage_r <= ddr_init_stage_r;
ddr_init_stage_fresh_r <= 1'b0;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_init_fin_cnt_r)
TIMENS_INT(tXPR + 6 * tMRD + tMOD + tZQinit + 6 * tMRD + tMOD + tZQinit): begin // T9 : T0 + 6 * tMRD + tMOD + tZQinit : 1146ns + 1024CK -> 2004ns
ddr_init_fin_r <= 1'b1;
end
default: begin
ddr_init_fin_r <= 1'b0;
end
endcase
end
/************ initialization related logic end *********************/
/************ activate related logic start *********************/
reg [31:0] ddr_activate_delay_fin_cnt_r = 32'b0;
reg ddr_activate_delay_fresh_r = 1'b0;
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_activate_delay_fin_cnt_r <= 32'b0;
end
6, 10: begin
ddr_activate_delay_fin_cnt_r <= ddr_activate_delay_fin_cnt_r + 1;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_activate_delay_fin_cnt_r)
1: begin
ddr_activate_delay_fresh_r <= 1'b1;
ddr_activate_delay_fin_r <= 1'b0;
end
10: begin // tRCD-AL
ddr_activate_delay_fresh_r <= 1'b0;
ddr_activate_delay_fin_r <= 1'b1;
end
default: begin
ddr_activate_delay_fresh_r <= 1'b0;
ddr_activate_delay_fin_r <= 1'b0;
end
endcase
end
/************ activate related logic end *********************/
/************ rd related logic start *********************/
reg [31:0] ddr_rd_delay_fin_cnt_r = 32'b0;
reg ddr_rd_delay_fresh_r = 1'b0;
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_rd_delay_fin_cnt_r <= 32'b0;
end
7: begin
ddr_rd_delay_fin_cnt_r <= ddr_rd_delay_fin_cnt_r + 1;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_rd_delay_fin_cnt_r)
1: begin
ddr_rd_delay_fresh_r <= 1'b1;
ddr_rd_delay_fin_r <= 1'b0;
end
4: begin
ddr_rd_delay_fresh_r <= 1'b0;
ddr_rd_delay_fin_r <= 1'b1;
end
default: begin
ddr_rd_delay_fresh_r <= 1'b0;
ddr_rd_delay_fin_r <= 1'b0;
end
endcase
end
/************ rd related logic end *********************/
/************ rddata related logic start *********************/
reg [31:0] ddr_rddata_delay_fin_cnt_r[71:0];
reg [71:0] ddr_rddata_delay_fresh_r;
reg [71:0] ddr_rddata_delay_fin_r;
generate for (genvar i = 0; i < 72; i++) begin
initial begin
ddr_rddata_delay_fin_cnt_r[i] = 1'b0;
ddr_rddata_delay_fresh_r[i] = 1'b0;
ddr_rddata_delay_fin_r[i] = 1'b0;
end
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_rddata_delay_fin_cnt_r[i] <= 32'b0;
end
8: begin
if (dq_i_valid[i]) begin
ddr_rddata_delay_fin_cnt_r[i] <= ddr_rddata_delay_fin_cnt_r[i] + 1;
end
end
endcase
end
always @(posedge usr_clk) begin
if (ddr_rddata_delay_fin_cnt_r[i] == 3'd0 && dq_i_valid[i] == 1'b1) begin
ddr_rddata_delay_fin_r[i] <= 1'b1;
end else begin
ddr_rddata_delay_fin_r[i] <= 1'b0;
end
for (int j = 0; j < 8; j++) begin
if (dq_i_valid[i]) begin
ram_rd_data[8 * i + j] <= dq_i_data[i][j];
end
end
end
end
endgenerate
always @(posedge usr_clk) begin
if (ddr_rddata_delay_fin_r == 72'b111111111111111111111111111111111111111111111111111111111111111111111111) begin
ddr_rddata_delay_fin_r_all_r <= 1'b1;
end else begin
ddr_rddata_delay_fin_r_all_r <= 1'b0;
end
end
/************ rddata related logic end *********************/
/************ precharge related logic start *********************/
reg [31:0] ddr_precharge_delay_fin_cnt_r = 32'b0;
reg ddr_precharge_delay_fresh_r = 1'b0;
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_precharge_delay_fin_cnt_r <= 32'b0;
end
9, 14: begin
ddr_precharge_delay_fin_cnt_r <= ddr_precharge_delay_fin_cnt_r + 1;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_precharge_delay_fin_cnt_r)
1: begin
ddr_precharge_delay_fresh_r <= 1'b0;
ddr_precharge_delay_fin_r <= 1'b0;
end
31: begin
ddr_precharge_delay_fresh_r <= 1'b1;
ddr_precharge_delay_fin_r <= 1'b0;
end
61: begin
ddr_precharge_delay_fresh_r <= 1'b0;
ddr_precharge_delay_fin_r <= 1'b1;
end
default: begin
ddr_precharge_delay_fresh_r <= 1'b0;
ddr_precharge_delay_fin_r <= 1'b0;
end
endcase
end
/************ precharge related logic end *********************/
/************ wr related logic start *********************/
reg [31:0] ddr_wr_delay_fin_cnt_r = 32'b0;
reg ddr_wr_delay_fresh_r = 1'b0;
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_wr_delay_fin_cnt_r <= 32'b0;
end
11: begin
ddr_wr_delay_fin_cnt_r <= ddr_wr_delay_fin_cnt_r + 1;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_wr_delay_fin_cnt_r)
1: begin
ddr_wr_delay_fresh_r <= 1'b1;
ddr_wr_delay_fin_r <= 1'b0;
end
4: begin // tCCD_L(WR)
ddr_wr_delay_fresh_r <= 1'b0;
ddr_wr_delay_fin_r <= 1'b1;
end
default: begin
ddr_wr_delay_fresh_r <= 1'b0;
ddr_wr_delay_fin_r <= 1'b0;
end
endcase
end
/************ wr related logic end *********************/
/************ wrdata related logic start *********************/
reg [31:0] ddr_wrdata_delay_fin_cnt_r = 32'b0;
reg ddr_wrdata_delay_fresh_r = 1'b0;
always @(posedge usr_clk) begin
case (ns)
default: begin
ddr_wrdata_delay_fin_cnt_r <= 32'b0;
end
12: begin
ddr_wrdata_delay_fin_cnt_r <= ddr_wrdata_delay_fin_cnt_r + 1;
end
endcase
end
always @(posedge usr_clk) begin
case (ddr_wrdata_delay_fin_cnt_r)
1: begin
ddr_wrdata_delay_fresh_r <= 1'b1;
ddr_wrdata_delay_fin_r <= 1'b0;
end
20: begin // tRAS
ddr_wrdata_delay_fresh_r <= 1'b0;
ddr_wrdata_delay_fin_r <= 1'b1;
end
default: begin
ddr_wrdata_delay_fresh_r <= 1'b0;
ddr_wrdata_delay_fin_r <= 1'b0;
end
endcase
end
/************ wrdata related logic end *********************/
/************ ram ready indicator logic start ****************/
always @(posedge usr_clk) begin
case (ns)
default: ram_rdy <= 1'b0;
4: ram_rdy <= 1'b1;
endcase
end
/************ ram ready indicator logic end ****************/
/************ wrdata logic start ****************/
always @(posedge usr_clk) begin
case (ns)
12: begin
for (int i = 0; i < 9; i++) begin
dqs_o_data[i] <= 8'b10101010;
dm_dbi_n_o_data[i] <= 8'b11111111;
PHY_RDEN[i] <= 4'b0001;
TRI_TBYTE_IN[i] <= 4'b1110;
end
for (int i = 0; i < 72; i++) begin
dq_o_data[i] <= {ram_wr_data[8 * i + 5], ram_wr_data[8 * i + 4], ram_wr_data[8 * i + 3], ram_wr_data[8 * i + 2], ram_wr_data[8 * i + 1], ram_wr_data[8 * i + 0], ram_wr_data[8 * i + 7], ram_wr_data[8 * i + 6]}; // 8'b11100101};
end
end
13: begin
for (int i = 0; i < 9; i++) begin
PHY_RDEN[i] <= 4'b1100;
TRI_TBYTE_IN[i] <= 4'b0011;
end
end
default: begin
for (int i = 0; i < 9; i++) begin
PHY_RDEN[i] <= 4'b1111;
TRI_TBYTE_IN[i] <= 4'b0000;
end
end
endcase
end
/************ wrdata logic end ****************/
always @(posedge usr_clk, negedge itf_rst_done_ff2) begin // cdc
if (~itf_rst_done_ff2) begin
io_bank_reset();
end else begin
case (ns)
0, 1: begin
io_bank_reset();
end
2: begin
PHY_RDEN <= {4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000};
TRI_TBYTE_IN <= {4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000};
case (ddr_reset_stage_r)
2'b00: begin
ck_o_data <= 8'b00000000;
reset_n_o_data <= 8'b00000000;
cke_o_data <= 8'b00000000;
end
2'b01: begin
ck_o_data <= 8'b00000000;
reset_n_o_data <= 8'b11111111;
cke_o_data <= 8'b00000000;
end
2'b10: begin
ck_o_data <= 8'b10101010;
reset_n_o_data <= 8'b11111111;
cke_o_data <= 8'b00000000;
end
2'b11: begin
CMD_DES();
end
endcase
end
3: begin
PHY_RDEN <= {4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000};
TRI_TBYTE_IN <= {4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000, 4'b0000};
if (ddr_init_stage_fresh_r) begin
case (ddr_init_stage_r)
5'b00000: begin
CMD_MRS(2'b10, 1'b0, 2'b11, 14'h0400);
end
5'b00001: begin
CMD_MRS(2'b10, 1'b1, 2'b10, 14'h0c14);
end
5'b00010: begin
CMD_MRS(2'b10, 1'b1, 2'b01, 14'h0000);
end
5'b00011: begin
CMD_MRS(2'b10, 1'b1, 2'b00, 14'h0000);
end
5'b00100: begin
CMD_MRS(2'b10, 1'b0, 2'b10, 14'h0020);
end
5'b00101: begin
CMD_MRS(2'b10, 1'b0, 2'b01, 14'h0301);
end
5'b00110: begin
CMD_MRS(2'b10, 1'b0, 2'b00, 14'h0b40);
end
5'b00111: begin
CMD_ZQCL(2'b10);
end
5'b01000: begin
CMD_DES();
end
5'b10000: begin
CMD_MRS(2'b01, 1'b0, 2'b11, 14'h0400);
end
5'b10001: begin
CMD_MRS(2'b01, 1'b1, 2'b01, 14'h240c);
end
5'b10010: begin
CMD_MRS(2'b01, 1'b1, 2'b10, 14'h0000);
end
5'b10011: begin
CMD_MRS(2'b01, 1'b1, 2'b00, 14'h0000);
end
5'b10100: begin
CMD_MRS(2'b01, 1'b0, 2'b01, 14'h0040);
end
5'b10101: begin
CMD_MRS(2'b01, 1'b0, 2'b10, 14'h0281);
end
5'b10110: begin
CMD_MRS(2'b01, 1'b0, 2'b00, 14'h22a0);
end
5'b10111: begin
CMD_ZQCL(2'b01);
end
5'b11000: begin
CMD_DES();
end
endcase
end else begin // NOP command
CMD_NUL();
end
end
4: begin
CMD_NUL();
end
6: begin
if (ddr_activate_delay_fresh_r) begin
CMD_ACT(ram_addr[19], ram_addr[18:17], ram_addr[16:0]);
end else begin
CMD_NUL();
end
end
7: begin
if (ddr_rd_delay_fresh_r) begin
CMD_RD(ram_addr[19], ram_addr[18:17], ram_addr[29:20]);
end else begin
CMD_NUL();
end
end
8: begin
CMD_NUL();
end
9: begin
if (ddr_precharge_delay_fresh_r) begin
CMD_PRE(ram_addr[19], ram_addr[18:17]);
end else begin
CMD_NUL();
end
end
10: begin
if (ddr_activate_delay_fresh_r) begin
CMD_ACT(ram_addr[19], ram_addr[18:17], ram_addr[16:0]);
end else begin
CMD_NUL();
end
end
11: begin
if (ddr_wr_delay_fresh_r) begin
CMD_WR(ram_addr[19], ram_addr[18:17], ram_addr[29:20]);
end else begin
CMD_NUL();
end
end
12, 13: begin
CMD_NUL();
end
14: begin
if (ddr_precharge_delay_fresh_r) begin
CMD_PRE(ram_addr[19], ram_addr[18:17]);
end else begin
CMD_NUL();
end
end
endcase
end
end
endmodule
- micron_ddr4_usr.sv 为输入读写指令生成模块,这里在确认ddr初始化完成后进行了一次写操作和一次读操作。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 03/05/2024 11:23:10 PM
// Design Name:
// Module Name: micron_ddr4_usr
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module micron_ddr4_usr(
input ram_clk,
output reg [29:0] ram_addr,
input [575:0] ram_rd_data,
output reg ram_en,
output reg [575:0] ram_wr_data,
output reg ram_wr,
input ram_rdy
);
initial begin
ram_addr = 32'b0;
ram_en = 1'b0;
ram_wr_data = 'd0;
ram_wr = 1'b0;
end
(* MARK_DEBUG="true" *) reg [5:0] state_r = 'd0, state_s;
always @(posedge ram_clk) begin
state_r <= state_s;
end
always @(*) begin
case (state_r)
0: begin
if (ram_rdy) begin
state_s = 1;
end else begin
state_s = 0;
end
end
1: begin
state_s = 2;
end
2: begin
if (ram_rdy) state_s = 3;
else state_s = 2;
end
3: begin
state_s = 4;
end
4: state_s = 4;
default: state_s = 0;
endcase
end
always @(posedge ram_clk) begin
case (state_s)
0: begin
ram_addr <= 30'h0;
ram_en <= 1'b0;
ram_wr <= 1'b0;
ram_wr_data <= 'd0;
end
1: begin
ram_en <= 1'b1;
ram_wr <= 1'b1;
ram_wr_data <= 576'h574a48776a68;
end
2: begin
ram_en <= 1'b0;
end
3: begin
ram_en <= 1'b1;
ram_wr <= 1'b0;
end
4: begin
ram_en <= 1'b0;
end
endcase
end
endmodule
- const.xdc 约束文件,包含DDR4引脚约束及用于时序收敛添加的约束
set_property PACKAGE_PIN BH51 [get_ports clk_p]
set_property IOSTANDARD LVDS [get_ports clk_p]
set_property IOSTANDARD LVDS [get_ports clk_n]
set_property IOSTANDARD POD12_DCI [get_ports {dq[7]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[6]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[5]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[4]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[3]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[2]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[1]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[0]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[8]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[7]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[6]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[5]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[4]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[3]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[2]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[1]}]
set_property IOSTANDARD POD12_DCI [get_ports {dm_dbi_n[0]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[8]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[7]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[6]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[5]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[4]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[3]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[2]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[1]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_c[0]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[8]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[7]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[6]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[5]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[4]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[3]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[2]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[1]}]
set_property IOSTANDARD DIFF_POD12_DCI [get_ports {dqs_t[0]}]
#set_property PACKAGE_PIN BM28 [get_ports dm_dbi_n]
#set_property PACKAGE_PIN BN29 [get_ports dqs_t]
create_clock -period 10.000 -name ddr4_clk -waveform {0.000 5.000} [get_ports clk_p]
# set_false_path -from [get_pins micron_ddr4_data_inst/BITSLICE_CONTROL_hi_halfbyte_inst/RIU_CLK] -to [get_pins micron_ddr4_data_inst/hi_DLY_RDY_ff_reg/D]
# set_false_path -from [get_pins micron_ddr4_data_inst/BITSLICE_CONTROL_lo_halfbyte_inst/RIU_CLK] -to [get_pins micron_ddr4_data_inst/lo_DLY_RDY_ff_reg/D]
# set_false_path -from [get_cells *BITSLICE_CONTROL_.*_inst] -to [get_cells *DLY_RDY_ff_reg]
set_property PACKAGE_PIN BK48 [get_ports {cs_n[1]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {cs_n[1]}]
set_property PACKAGE_PIN BH49 [get_ports {odt[0]}]
set_property PACKAGE_PIN BH50 [get_ports reset_n]
set_property IOSTANDARD LVCMOS12 [get_ports reset_n]
set_property IOSTANDARD SSTL12_DCI [get_ports {odt[0]}]
set_property PACKAGE_PIN BG52 [get_ports act_n]
set_property PACKAGE_PIN BH52 [get_ports {cke[0]}]
set_property PACKAGE_PIN BK53 [get_ports {ck_t[0]}]
set_property PACKAGE_PIN BH54 [get_ports {addr[15]}]
set_property PACKAGE_PIN BJ54 [get_ports {addr[16]}]
set_property PACKAGE_PIN BG53 [get_ports {addr[14]}]
set_property PACKAGE_PIN BG54 [get_ports {bg[0]}]
set_property PACKAGE_PIN BE53 [get_ports {ba[1]}]
set_property PACKAGE_PIN BE54 [get_ports {ba[0]}]
set_property PACKAGE_PIN BF53 [get_ports {addr[6]}]
set_property IOSTANDARD SSTL12_DCI [get_ports act_n]
set_property IOSTANDARD SSTL12_DCI [get_ports {cke[0]}]
set_property IOSTANDARD DIFF_SSTL12_DCI [get_ports {ck_t[0]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[15]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[16]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[14]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {bg[0]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {ba[1]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {ba[0]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[6]}]
set_property PACKAGE_PIN BG48 [get_ports {addr[2]}]
set_property PACKAGE_PIN BG49 [get_ports {addr[11]}]
set_property PACKAGE_PIN BF50 [get_ports {addr[0]}]
set_property PACKAGE_PIN BG50 [get_ports {addr[7]}]
set_property PACKAGE_PIN BF51 [get_ports {addr[8]}]
set_property PACKAGE_PIN BF52 [get_ports {addr[13]}]
set_property PACKAGE_PIN BF47 [get_ports {addr[10]}]
set_property PACKAGE_PIN BF48 [get_ports {addr[12]}]
set_property PACKAGE_PIN BE49 [get_ports {addr[4]}]
set_property PACKAGE_PIN BE50 [get_ports {addr[3]}]
set_property PACKAGE_PIN BD51 [get_ports {addr[1]}]
set_property PACKAGE_PIN BE51 [get_ports {addr[5]}]
set_property PACKAGE_PIN BG47 [get_ports {addr[9]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[2]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[11]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[0]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[7]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[8]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[13]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[10]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[12]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[4]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[3]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[1]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[5]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {addr[9]}]
set_property PACKAGE_PIN BP49 [get_ports {cs_n[0]}]
set_property IOSTANDARD SSTL12_DCI [get_ports {cs_n[0]}]
set_property DRIVE 8 [get_ports reset_n]
set_property PACKAGE_PIN BM28 [get_ports {dm_dbi_n[4]}]
set_property PACKAGE_PIN BP28 [get_ports {dq[35]}]
set_property PACKAGE_PIN BP29 [get_ports {dq[33]}]
set_property PACKAGE_PIN BN31 [get_ports {dq[38]}]
set_property PACKAGE_PIN BP31 [get_ports {dq[34]}]
set_property PACKAGE_PIN BN29 [get_ports {dqs_t[4]}]
set_property PACKAGE_PIN BL30 [get_ports {dq[39]}]
set_property PACKAGE_PIN BM30 [get_ports {dq[37]}]
set_property PACKAGE_PIN BN32 [get_ports {dq[36]}]
set_property PACKAGE_PIN BP32 [get_ports {dq[32]}]
set_property PACKAGE_PIN BM34 [get_ports {dm_dbi_n[5]}]
set_property PACKAGE_PIN BN34 [get_ports {dq[42]}]
set_property PACKAGE_PIN BP34 [get_ports {dq[41]}]
set_property PACKAGE_PIN BL32 [get_ports {dq[40]}]
set_property PACKAGE_PIN BM33 [get_ports {dq[46]}]
set_property PACKAGE_PIN BL35 [get_ports {dqs_t[5]}]
set_property PACKAGE_PIN BK31 [get_ports {dq[47]}]
set_property PACKAGE_PIN BL31 [get_ports {dq[44]}]
set_property PACKAGE_PIN BK33 [get_ports {dq[43]}]
set_property PACKAGE_PIN BL33 [get_ports {dq[45]}]
set_property PACKAGE_PIN BH32 [get_ports {dm_dbi_n[6]}]
set_property PACKAGE_PIN BJ33 [get_ports {dq[52]}]
set_property PACKAGE_PIN BJ34 [get_ports {dq[48]}]
set_property PACKAGE_PIN BG34 [get_ports {dq[54]}]
set_property PACKAGE_PIN BG35 [get_ports {dq[49]}]
set_property PACKAGE_PIN BK34 [get_ports {dqs_t[6]}]
set_property PACKAGE_PIN BF35 [get_ports {dq[53]}]
set_property PACKAGE_PIN BF36 [get_ports {dq[55]}]
set_property PACKAGE_PIN BH34 [get_ports {dq[50]}]
set_property PACKAGE_PIN BH35 [get_ports {dq[51]}]
set_property PACKAGE_PIN BG29 [get_ports {dm_dbi_n[7]}]
set_property PACKAGE_PIN BH29 [get_ports {dq[62]}]
set_property PACKAGE_PIN BH30 [get_ports {dq[57]}]
set_property PACKAGE_PIN BF31 [get_ports {dq[56]}]
set_property PACKAGE_PIN BG32 [get_ports {dq[59]}]
set_property PACKAGE_PIN BJ29 [get_ports {dqs_t[7]}]
set_property PACKAGE_PIN BF32 [get_ports {dq[61]}]
set_property PACKAGE_PIN BF33 [get_ports {dq[63]}]
set_property PACKAGE_PIN BH31 [get_ports {dq[60]}]
set_property PACKAGE_PIN BJ31 [get_ports {dq[58]}]
set_property PACKAGE_PIN BN42 [get_ports {dm_dbi_n[0]}]
set_property PACKAGE_PIN BN47 [get_ports {dq[6]}]
set_property PACKAGE_PIN BP47 [get_ports {dq[2]}]
set_property PACKAGE_PIN BP43 [get_ports {dq[7]}]
set_property PACKAGE_PIN BP44 [get_ports {dq[1]}]
set_property PACKAGE_PIN BN46 [get_ports {dqs_t[0]}]
set_property PACKAGE_PIN BM44 [get_ports {dq[4]}]
set_property PACKAGE_PIN BN44 [get_ports {dq[5]}]
set_property PACKAGE_PIN BM45 [get_ports {dq[0]}]
set_property PACKAGE_PIN BN45 [get_ports {dq[3]}]
set_property PACKAGE_PIN BL47 [get_ports {dm_dbi_n[1]}]
set_property PACKAGE_PIN BL45 [get_ports {dq[8]}]
set_property PACKAGE_PIN BL46 [get_ports {dq[10]}]
set_property PACKAGE_PIN BL42 [get_ports {dq[14]}]
set_property PACKAGE_PIN BL43 [get_ports {dq[12]}]
set_property PACKAGE_PIN BK45 [get_ports {dqs_t[1]}]
set_property PACKAGE_PIN BK43 [get_ports {dq[11]}]
set_property PACKAGE_PIN BK44 [get_ports {dq[9]}]
set_property PACKAGE_PIN BJ43 [get_ports {dq[15]}]
set_property PACKAGE_PIN BJ44 [get_ports {dq[13]}]
set_property PACKAGE_PIN BH42 [get_ports {dm_dbi_n[2]}]
set_property PACKAGE_PIN BH44 [get_ports {dq[19]}]
set_property PACKAGE_PIN BH45 [get_ports {dq[20]}]
set_property PACKAGE_PIN BJ41 [get_ports {dq[23]}]
set_property PACKAGE_PIN BK41 [get_ports {dq[16]}]
set_property PACKAGE_PIN BH46 [get_ports {dqs_t[2]}]
set_property PACKAGE_PIN BG42 [get_ports {dq[18]}]
set_property PACKAGE_PIN BG43 [get_ports {dq[22]}]
set_property PACKAGE_PIN BG44 [get_ports {dq[17]}]
set_property PACKAGE_PIN BG45 [get_ports {dq[21]}]
set_property PACKAGE_PIN BD41 [get_ports {dm_dbi_n[3]}]
set_property PACKAGE_PIN BF45 [get_ports {dq[29]}]
set_property PACKAGE_PIN BF46 [get_ports {dq[31]}]
set_property PACKAGE_PIN BF42 [get_ports {dq[25]}]
set_property PACKAGE_PIN BF43 [get_ports {dq[27]}]
set_property PACKAGE_PIN BE45 [get_ports {dqs_t[3]}]
set_property PACKAGE_PIN BC42 [get_ports {dq[26]}]
set_property PACKAGE_PIN BD42 [get_ports {dq[28]}]
set_property PACKAGE_PIN BE43 [get_ports {dq[24]}]
set_property PACKAGE_PIN BE44 [get_ports {dq[30]}]
set_property PACKAGE_PIN BP48 [get_ports {dm_dbi_n[8]}]
set_property PACKAGE_PIN BN50 [get_ports {dq[66]}]
set_property PACKAGE_PIN BN51 [get_ports {dq[64]}]
set_property PACKAGE_PIN BM48 [get_ports {dq[68]}]
set_property PACKAGE_PIN BN49 [get_ports {dq[70]}]
set_property PACKAGE_PIN BM49 [get_ports {dqs_t[8]}]
set_property PACKAGE_PIN BL51 [get_ports {dq[71]}]
set_property PACKAGE_PIN BM52 [get_ports {dq[65]}]
set_property PACKAGE_PIN BL52 [get_ports {dq[67]}]
set_property PACKAGE_PIN BL53 [get_ports {dq[69]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[71]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[70]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[69]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[68]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[67]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[66]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[65]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[64]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[63]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[62]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[61]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[60]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[59]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[58]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[57]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[56]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[55]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[54]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[53]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[52]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[51]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[50]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[49]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[48]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[47]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[46]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[45]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[44]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[43]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[42]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[41]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[40]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[39]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[38]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[37]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[36]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[35]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[34]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[33]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[32]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[31]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[30]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[29]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[28]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[27]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[26]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[25]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[24]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[23]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[22]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[21]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[20]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[19]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[18]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[17]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[16]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[15]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[14]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[13]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[12]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[11]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[10]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[9]}]
set_property IOSTANDARD POD12_DCI [get_ports {dq[8]}]
# set_false_path -through [get_pins -hierarchical -regexp .*byte_inst/DLY_RDY.*]
# set_false_path -through [get_pins -hierarchical -regexp .*byte_inst/VTC_RDY.*]
# set_property LOC MMCM_X0Y1 [get_cells MMCME4_BASE_inst]
set_property LOC PLL_X0Y4 [get_cells PLLE4_BASE_ctrl_udata_inst]
set_property LOC PLL_X0Y2 [get_cells PLLE4_BASE_mdata_inst]
set_property LOC PLL_X0Y0 [get_cells PLLE4_BASE_ldata_inst]
# wpws closure
set_property LOC BUFGCE_X0Y4 [get_cells ldata_riu_clk_p_BUFG_inst]
set_clock_groups -name mdata_clock_group -asynchronous -group [get_clocks -of_objects [get_pins PLLE4_BASE_mdata_inst/CLKOUT0]] -group [get_clocks -of_objects [get_pins PLLE4_BASE_mdata_inst/CLKOUTPHY]]
set_clock_groups -name ldata_clock_group -asynchronous -group [get_clocks -of_objects [get_pins PLLE4_BASE_ldata_inst/CLKOUT0]] -group [get_clocks -of_objects [get_pins PLLE4_BASE_ldata_inst/CLKOUTPHY]]
set_clock_groups -name ctrl_udata_clock_group -asynchronous -group [get_clocks -of_objects [get_pins PLLE4_BASE_ctrl_udata_inst/CLKOUT0]] -group [get_clocks -of_objects [get_pins PLLE4_BASE_ctrl_udata_inst/CLKOUTPHY]]