【DDR】基于Verilog的DDR控制器的简单实现(三)——读操作

上一节 【DDR】基于Verilog的DDR控制器的简单实现(二)——写操作

本文继续以美光(Micron)公司生产的DDR3芯片MT41J512M8RH-093(芯片手册)为例,说明DDR芯片的读操作过程。下图为读操作指令格式(来自P122 Table 72: READ Command Summary),与写操作指令格式区别在于WE#位。
在这里插入图片描述

DDR的读操作过程类似于写操作过程,在读特定row前需要使用ACTIVATE指令激活,在读完毕后需要显式或隐式使用PRECHARGE预充电。主要区别在于读操作的DQS与DQ由DDR芯片产生,DDR控制器需要根据DQS时钟对DQ采样。一次读操作的波形图如下(来自P163 Figure 69: READ Latency),在READ指令发出后经过CL+AL个周期,DQ数据线上将有连续数据输出。其中CL(CAS latency)、AL的值为初始化阶段写入MR0,MR1寄存器的值。
在这里插入图片描述
读过程DQS和DQ总线上的时序约束如图(来自P170 Figure 79: Data Output Timing – tDQSQ and Data Valid Window),DQS作为DQ的时钟信号,在DQ数据开始输出前tRPRE时钟周期开始输出低电平。DQ数据线上的多个bit只有在Data valid的一段时间内同时有效。
在这里插入图片描述

读过程主要涉及的时序约束如下(来自P94)

* tDQSQ     <75ps 				;DQ信号同时有效开始相对DQS边沿的延后时间
* tQH       >0.38 tCK			;DQ信号同时有效结束相对DQS边沿的延后时间
* tRTP      >max(7.5ns,4CK) 	;READ指令后相邻PRECHARGE指令最小时间间隔

仿真时将时钟周期取为最小时钟周期0.938ns,对应时钟频率1066.099MHz。tDQSS取为0,此时DQS时钟与clk时钟相同,每次连续写操作只对8个地址中的首个数据,最终得到的DDR3写数据代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer:    wjh776a68 
// 
// Create Date: 01/15/2024 15:25:15 PM
// Design Name: 
// Module Name: micron_ddr_rdbyte
// Project Name: 
// Target Devices:  VU9P 
// Tool Versions:   2017.4 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//// ddr3 x8 4Gb MT41J512M8RH-093
/****************************
*  DDR3L-2133 https://www.micron.com/-/media/client/global/documents/products/data-sheet/dram/ddr3/4gb_ddr3l.pdf?rev=305217e2f9bd4ef48d7c6f353dfc064c
* CK(MIN) 0.938 ns
* CL        14 CK
* RCD(MIN)  14 CK
* RC(MIN)   50 CK
* RAS(MIN)  36 CK
* RP(MIN)   14 CK
* FAW       27 CK
* RRD       6  CK
* RFC       279CK
* XPR       >max(5CK, RFC+10ns)
* MRD       >4CK
* MOD       >max(12CK, 15ns)
* ZQinit    <max(512nCK, 640ns)
* DLLK      >512CK
*
* tDQSS     =(-0.27, 0.27)CK    P94
* tDSS      >0.18CK
* tWPRE     >0.9CK
* tWPST     >0.3CK
* tDS       >55ps 
* tDH       >60ps 
* tRAS      >33ns
* tWR       >15ns
*
* tDQSQ     <75ps P94
* tQH       >0.38 tCK
* tRTP      >max(7.5ns,4CK)
* command all p118
* initial waveform p137
*
* COMMAND     | NOP | MRS_1 | MRS_2 | MRS_3 | MRS_4 | ZQCL             
* ddr_cke     | 1 1 |  1 1  |  1 1  |  1 1  |  1 1  |  1 1   
* ddr_dqs_en  |  0  |       |       |       |       |        
* ddr_dq_en   |  0  |       |       |       |       |         
* ddr_cs_n    |  0  |   0   |   0   |   0   |   0   |   0     
* ddr_ras_n   |  1  |   0   |   0   |   0   |   0   |   1    
* ddr_cas_n   |  1  |   0   |   0   |   0   |   0   |   1    
* ddr_we_n    |  1  |   0   |   0   |   0   |   0   |   0    
* ddr_ba      | vvv |  010  |  011  |  001  |  000  |         
* ddr_addr    | vvv |   28  |   00  |   44  |  124  |  a[10]      
* ddr_odt     |  0  |       |       |       |       |        
*
* ACT : open a row in a bank, do PRECHANGE after open other row in the same bank P161
* PRECHARGE : access for the same bank is avaliable for 'RP after PRECHARGE *
* WRITE COMMAND (P122 Table 73)
* COMMAND     | WR  | WRS4  | WRS8  | WRAP  | WRAPS4| WRAPS8 
* ddr_cke     | 1 1 |  1 1  |  1 1  |  1 1  |  1 1  |  1 1   
* ddr_dqs_en  |  -  |       |       |       |       |        
* ddr_dq_en   |  -  |       |       |       |       |         
* ddr_cs_n    |  0  |   0   |   0   |   0   |   0   |   0     
* ddr_ras_n   |  1  |   1   |   1   |   1   |   1   |   1    
* ddr_cas_n   |  0  |   0   |   0   |   0   |   0   |   0    
* ddr_we_n    |  0  |   0   |   0   |   0   |   0   |   0    
* ddr_ba      | BA  |  BA   |  BA   |  BA   |  BA   |   BA    
* ddr_addr12  |  v  |   0   |   1   |   v   |   0   |   1    
* ddr_addr10  |  0  |   0   |   0   |   1   |   1   |   1   
* ddr_addr    | CA  |       |       |       |       | 
* ddr_odt     |  -  |       |       |       |       |        
* ddr_dq      | data write to mem
* ddr_dm      | 0 : dq valid ; 1 : dq invalid, write skip that byte/column
*
* READ COMMAND (P122 Table 72)
* COMMAND     | RD  | RDS4  | RDS8  | RDAP  | RDAPS4| RDAPS8 
* ddr_cke     | 1 1 |  1 1  |  1 1  |  1 1  |  1 1  |  1 1   
* ddr_dqs_en  |  -  |       |       |       |       |        
* ddr_dq_en   |  -  |       |       |       |       |         
* ddr_cs_n    |  0  |   0   |   0   |   0   |   0   |   0     
* ddr_ras_n   |  1  |   1   |   1   |   1   |   1   |   1    
* ddr_cas_n   |  0  |   0   |   0   |   0   |   0   |   0    
* ddr_we_n    |  1  |   1   |   1   |   1   |   1   |   1    
* ddr_ba      | BA  |  BA   |  BA   |  BA   |  BA   |   BA    
* ddr_addr12  |  v  |   0   |   1   |   v   |   0   |   1    
* ddr_addr10  |  0  |   0   |   0   |   1   |   1   |   1   
* ddr_addr    | CA  |       |       |       |       | 
* ddr_odt     |  -  |       |       |       |       |        
* ddr_dq      | data read from mem
* ddr_dm      | -
*
***************************************************************/
module micron_ddr_rdbyte #(parameter CLK_FREQ = 1066.099, // MHzparameter _1MS_CYCLE = 10.0**-3 / (1.0 / (CLK_FREQ * 10**6)),parameter _1US_CYCLE = 10.0**-6 / (1.0 / (CLK_FREQ * 10**6)),parameter integer INITIAL_CYCLE = 200 * _1US_CYCLE,parameter integer INITIAL_STABLE_CYCLE = 500 * _1US_CYCLE,parameter integer FREE_CYCLE = _1US_CYCLE
) (output  reg [15:0]  ddr_addr,output  reg [2:0]   ddr_ba,output  reg         ddr_cas_n,output  reg [0:0]   ddr_ck_n,output  reg [0:0]   ddr_ck_p,output  reg [0:0]   ddr_cke,output  reg [0:0]   ddr_cs_n,output  reg [0:0]   ddr_dm,inout       [7:0]   ddr_dq,inout       [0:0]   ddr_dqs_n,inout       [0:0]   ddr_dqs_p,output  reg [0:0]   ddr_odt,output  reg         ddr_ras_n,output  reg         ddr_reset_n,output  reg         ddr_we_n,input       [28:0]  s_wraddr, // 4Gb -> 512MB -> 512M -> 2^29// 3BA 16RA 10CAinput       [7:0]   s_wrdata,input               s_wrstrb,input               s_wren,input       [28:0]  s_rdaddr,output      [7:0]   s_rddata,input               s_rden,input clk);localparam [27:0] NOP_CMD =  {11'b11110111000, 16'h0000, 1'b0};
localparam [27:0] MRS1_CMD = {11'b11110000010, 16'h0028, 1'b0}; //MR2 tCWL=10 A5-A3
localparam [27:0] MRS2_CMD = {11'b11110000011, 16'h0000, 1'b0}; //MR3
localparam [27:0] MRS3_CMD = {11'b11110000001, 16'h0044, 1'b0}; //MR1 tAL=0 A4-A3 
localparam [27:0] MRS4_CMD = {11'b11110000000, 16'h0124, 1'b0}; //MR0 tCAS=14CK A6-A4,A2
localparam [27:0] ZQCL_CMD = {11'b11110110000, 16'h0400, 1'b0};localparam [27:0] ACT_CMD  = {11'b11110011000, 16'h0000, 1'b0}; // ba ralocalparam [27:0] PRE_CMD  = {11'b11110010000, 16'h0000, 1'b0}; // balocalparam [27:0] WR_CMD   = {11'b11110100000, 16'h0000, 1'b0}; // dqs_o dq_o ba ca
localparam [27:0] RD_CMD   = {11'b11110101000, 16'h0000, 1'b0}; // dqs_i dq_i ba careg ddr_cke_p1, ddr_cke_p2;
reg ddr_dqs_o, ddr_dqs_en;
wire ddr_dqs_i;
reg [7:0] ddr_dq_o_r_p1, ddr_dq_o_r_p2;
wire [7:0] ddr_dq_o_r;
wire [7:0] ddr_dq_o, ddr_dq_i;
wire [7:0] dq_i_r_p1, dq_i_r_p2; 
wire [7:0] dq_i_r;
reg ddr_dq_en;
reg ddr_dm_o_r_p1, ddr_dm_o_r_p2;
wire ddr_dm_o_r;
wire ddr_dm_o; wire [2:0]  wraddr_ba_s;
wire [15:0] wraddr_ra_s;
wire [9:0]  wraddr_ca_s;
wire [7:0]  wrdata_s;
wire        wrstrb_s;
wire        wren_s;wire [2:0]  rdaddr_ba_s;
wire [15:0] rdaddr_ra_s;
wire [9:0]  rdaddr_ca_s;
wire [7:0]  rddata_s;
// wire        rdstrb_s;
wire        rden_s;reg  [2:0]  wraddr_ba_r;
reg  [15:0] wraddr_ra_r;
reg  [9:0]  wraddr_ca_r;
reg  [7:0]  wrdata_r;
reg         wrstrb_r;
reg         wren_r;reg  [2:0]  rdaddr_ba_r;
reg  [15:0] rdaddr_ra_r;
reg  [9:0]  rdaddr_ca_r;
reg  [7:0]  rddata_r;
// reg         rdstrb_r;
reg         rden_r;OBUFDS OBUFDS_ck (.O(ddr_ck_p),   // 1-bit output: Diff_p output (connect directly to top-level port).OB(ddr_ck_n), // 1-bit output: Diff_n output (connect directly to top-level port).I(clk)    // 1-bit input: Buffer input);IOBUFDS #(.DQS_BIAS("FALSE")  // (FALSE, TRUE))IOBUFDS_dqs_inst (.O(ddr_dqs_i),     // 1-bit output: Buffer output.I(ddr_dqs_o),     // 1-bit input: Buffer input.IO(ddr_dqs_p),   // 1-bit inout: Diff_p inout (connect directly to top-level port).IOB(ddr_dqs_n), // 1-bit inout: Diff_n inout (connect directly to top-level port).T(ddr_dqs_en)      // 1-bit input: 3-state enable input);generateOBUF OBUF_dm_inst (.O(ddr_dm), // 1-bit output: Buffer output (connect directly to top-level port).I(ddr_dm_o)  // 1-bit input: Buffer input);IDELAYCTRL #(.SIM_DEVICE("ULTRASCALE")  // Must be set to "ULTRASCALE" )IDELAYCTRL_dm_o_inst (.RDY(),       // 1-bit output: Ready output.REFCLK(clk), // 1-bit input: Reference clock input.RST(1'b0)        // 1-bit input: Active high reset input. Asynchronous assert, synchronous deassert to// REFCLK.);ODELAYE3 #(.CASCADE("NONE"),          // Cascade setting (MASTER, NONE, SLAVE_END, SLAVE_MIDDLE).DELAY_FORMAT("TIME"),     // (COUNT, TIME).DELAY_TYPE("FIXED"),      // Set the type of tap delay line (FIXED, VARIABLE, VAR_LOAD).DELAY_VALUE(55),           // Output delay tap setting (ps).IS_CLK_INVERTED(1'b0),    // Optional inversion for CLK.IS_RST_INVERTED(1'b0),    // Optional inversion for RST.REFCLK_FREQUENCY(1066.098),  // IDELAYCTRL clock input frequency in MHz (200.0-2667.0)..SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,// ULTRASCALE_PLUS_ES2).UPDATE_MODE("ASYNC")      // Determines when updates to the delay will take effect (ASYNC, MANUAL, SYNC))ODELAYE3_dm_o_inst (.CASC_OUT(),       // 1-bit output: Cascade delay output to IDELAY input cascade.CNTVALUEOUT(), // 9-bit output: Counter value output.DATAOUT(ddr_dm_o),         // 1-bit output: Delayed data from ODATAIN input port.CASC_IN(1'b0),         // 1-bit input: Cascade delay input from slave IDELAY CASCADE_OUT.CASC_RETURN(1'b0), // 1-bit input: Cascade delay returning from slave IDELAY DATAOUT.CE(1'b1),                   // 1-bit input: Active high enable increment/decrement input.CLK(clk),                 // 1-bit input: Clock input.CNTVALUEIN(9'b0),   // 9-bit input: Counter value input.EN_VTC(1'b1),           // 1-bit input: Keep delay constant over VT.INC(1'b0),                 // 1-bit input: Increment/Decrement tap delay input.LOAD(1'b0),               // 1-bit input: Load DELAY_VALUE input.ODATAIN(ddr_dm_o_r),         // 1-bit input: Data input.RST(1'b0)                  // 1-bit input: Asynchronous Reset to the DELAY_VALUE);ODDRE1 #(.IS_C_INVERTED(1'b1),  // Optional inversion for C.IS_D1_INVERTED(1'b0), // Unsupported, do not use.IS_D2_INVERTED(1'b0), // Unsupported, do not use.SRVAL(1'b0)           // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1))ODDRE1_dm_o_inst (.Q(ddr_dm_o_r),   // 1-bit output: Data output to IOB.C(clk),   // 1-bit input: High-speed clock input.D1(ddr_dm_o_r_p1), // 1-bit input: Parallel data input 1.D2(ddr_dm_o_r_p2), // 1-bit input: Parallel data input 2.SR(1'b0)  // 1-bit input: Active High Async Reset);for (genvar i = 0; i < 8; i++) beginIOBUF IOBUF_dq_inst (.O(ddr_dq_i[i]),   // 1-bit output: Buffer output.I(ddr_dq_o[i]),   // 1-bit input: Buffer input.IO(ddr_dq[i]), // 1-bit inout: Buffer inout (connect directly to top-level port).T(ddr_dq_en)    // 1-bit input: 3-state enable input);IDELAYCTRL #(.SIM_DEVICE("ULTRASCALE")  // Must be set to "ULTRASCALE" )IDELAYCTRL_dq_o_inst (.RDY(),       // 1-bit output: Ready output.REFCLK(clk), // 1-bit input: Reference clock input.RST(1'b0)        // 1-bit input: Active high reset input. Asynchronous assert, synchronous deassert to// REFCLK.);ODELAYE3 #(.CASCADE("NONE"),          // Cascade setting (MASTER, NONE, SLAVE_END, SLAVE_MIDDLE).DELAY_FORMAT("TIME"),     // (COUNT, TIME).DELAY_TYPE("FIXED"),      // Set the type of tap delay line (FIXED, VARIABLE, VAR_LOAD).DELAY_VALUE(55),           // Output delay tap setting (ps).IS_CLK_INVERTED(1'b0),    // Optional inversion for CLK.IS_RST_INVERTED(1'b0),    // Optional inversion for RST.REFCLK_FREQUENCY(1066.098),  // IDELAYCTRL clock input frequency in MHz (200.0-2667.0)..SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,// ULTRASCALE_PLUS_ES2).UPDATE_MODE("ASYNC")      // Determines when updates to the delay will take effect (ASYNC, MANUAL, SYNC))ODELAYE3_dq_o_inst (.CASC_OUT(),       // 1-bit output: Cascade delay output to IDELAY input cascade.CNTVALUEOUT(), // 9-bit output: Counter value output.DATAOUT(ddr_dq_o[i]),         // 1-bit output: Delayed data from ODATAIN input port.CASC_IN(1'b0),         // 1-bit input: Cascade delay input from slave IDELAY CASCADE_OUT.CASC_RETURN(1'b0), // 1-bit input: Cascade delay returning from slave IDELAY DATAOUT.CE(1'b1),                   // 1-bit input: Active high enable increment/decrement input.CLK(clk),                 // 1-bit input: Clock input.CNTVALUEIN(9'b0),   // 9-bit input: Counter value input.EN_VTC(1'b1),           // 1-bit input: Keep delay constant over VT.INC(1'b0),                 // 1-bit input: Increment/Decrement tap delay input.LOAD(1'b0),               // 1-bit input: Load DELAY_VALUE input.ODATAIN(ddr_dq_o_r[i]),         // 1-bit input: Data input.RST(1'b0)                  // 1-bit input: Asynchronous Reset to the DELAY_VALUE);ODDRE1 #(.IS_C_INVERTED(1'b1),  // Optional inversion for C.IS_D1_INVERTED(1'b0), // Unsupported, do not use.IS_D2_INVERTED(1'b0), // Unsupported, do not use.SRVAL(1'b0)           // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1))ODDRE1_dq_o_inst (.Q(ddr_dq_o_r[i]),   // 1-bit output: Data output to IOB.C(clk),   // 1-bit input: High-speed clock input.D1(ddr_dq_o_r_p1[i]), // 1-bit input: Parallel data input 1.D2(ddr_dq_o_r_p2[i]), // 1-bit input: Parallel data input 2.SR(1'b0)  // 1-bit input: Active High Async Reset);IDDRE1 #(.DDR_CLK_EDGE("SAME_EDGE"), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED).IS_CB_INVERTED(1'b1),          // Optional inversion for CB.IS_C_INVERTED(1'b1)            // Optional inversion for C)IDDRE1_dq_inst (.Q1(dq_i_r_p1[i]), // 1-bit output: Registered parallel output 1.Q2(dq_i_r_p2[i]), // 1-bit output: Registered parallel output 2.C(ddr_dqs_i),   // 1-bit input: High-speed clock.CB(~ddr_dqs_i), // 1-bit input: Inversion of High-speed clock C.D(dq_i_r[i]),   // 1-bit input: Serial Data Input.R(1'b0)    // 1-bit input: Active High Async Reset);IDELAYE3 #(.CASCADE("NONE"),          // Cascade setting (MASTER, NONE, SLAVE_END, SLAVE_MIDDLE).DELAY_FORMAT("TIME"),     // Units of the DELAY_VALUE (COUNT, TIME).DELAY_SRC("IDATAIN"),     // Delay input (DATAIN, IDATAIN).DELAY_TYPE("FIXED"),      // Set the type of tap delay line (FIXED, VARIABLE, VAR_LOAD).DELAY_VALUE(75),           // Input delay value setting.IS_CLK_INVERTED(1'b1),    // Optional inversion for CLK.IS_RST_INVERTED(1'b0),    // Optional inversion for RST.REFCLK_FREQUENCY(1066.098),  // IDELAYCTRL clock input frequency in MHz (200.0-2667.0).SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,// ULTRASCALE_PLUS_ES2).UPDATE_MODE("ASYNC")      // Determines when updates to the delay will take effect (ASYNC, MANUAL, SYNC))IDELAYE3_dq_inst (.CASC_OUT(),       // 1-bit output: Cascade delay output to ODELAY input cascade.CNTVALUEOUT(), // 9-bit output: Counter value output.DATAOUT(dq_i_r[i]),         // 1-bit output: Delayed data output.CASC_IN(1'b0),         // 1-bit input: Cascade delay input from slave ODELAY CASCADE_OUT.CASC_RETURN(1'b0), // 1-bit input: Cascade delay returning from slave ODELAY DATAOUT.CE(1'b1),                   // 1-bit input: Active high enable increment/decrement input.CLK(ddr_dqs_i),                 // 1-bit input: Clock input.CNTVALUEIN(9'b0),   // 9-bit input: Counter value input.DATAIN(1'b0),           // 1-bit input: Data input from the logic.EN_VTC(1'b0),           // 1-bit input: Keep delay constant over VT.IDATAIN(ddr_dq_i[i]),         // 1-bit input: Data input from the IOBUF.INC(1'b0),                 // 1-bit input: Increment / Decrement tap delay input.LOAD(1'b0),               // 1-bit input: Load DELAY_VALUE input.RST(1'b0)                  // 1-bit input: Asynchronous Reset to the DELAY_VALUE); endendgenerateODDRE1 #(.IS_C_INVERTED(1'b1),  // Optional inversion for C.IS_D1_INVERTED(1'b0), // Unsupported, do not use.IS_D2_INVERTED(1'b0), // Unsupported, do not use.SRVAL(1'b0)           // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1))ODDRE1_cke_inst (.Q(ddr_cke),   // 1-bit output: Data output to IOB.C(clk),   // 1-bit input: High-speed clock input.D1(ddr_cke_p1), // 1-bit input: Parallel data input 1.D2(ddr_cke_p2), // 1-bit input: Parallel data input 1.SR(1'b0)  // 1-bit input: Active High Async Reset);//OBUFDS OBUFDS_dqs (
//      .O(ddr_dqs_p),   // 1-bit output: Diff_p output (connect directly to top-level port)
//      .OB(ddr_dqs_n), // 1-bit output: Diff_n output (connect directly to top-level port)
//      .I(ddr_dqs)    // 1-bit input: Buffer input
//   );reg [15:0]  ddr_addr_r;reg [2:0]   ddr_ba_r;reg         ddr_cas_n_r;reg [0:0]   ddr_cs_n_r;// reg [0:0]   ddr_dm_r; // no refreg [0:0]   ddr_odt_r;reg         ddr_ras_n_r;reg         ddr_we_n_r;reg         ddr_dq_en_r; reg         ddr_dqs_en_r; always @(negedge clk) beginddr_addr        <=  ddr_addr_r  ;ddr_ba      <=  ddr_ba_r    ;ddr_cas_n       <=  ddr_cas_n_r ;ddr_cs_n        <=  ddr_cs_n_r  ;//    ddr_dm      <=  ddr_dm_r    ;ddr_odt     <=  ddr_odt_r   ;ddr_ras_n       <=  ddr_ras_n_r ;ddr_we_n        <=  ddr_we_n_r  ;ddr_dq_en   <=  ddr_dq_en_r;ddr_dqs_en  <=  ddr_dqs_en_r;endreg [5:0] cs = 0, ns;reg [31:0]  initial_cnt = 0;reg [31:0]  initial_stable_cnt = 0;reg [31:0]  freerun_cnt = 0;reg [5:0]   trcd_cnt = 0;reg [5:0]   twl_cnt = 0;reg [5:0]   trl_cnt = 0;reg [5:0]   twr_cnt = 0;reg [5:0]   tRTP_cnt = 0;reg [5:0]   burst_cnt = 0;reg [3:0]   initial_cmd_ptr = 0;reg [27:0] initial_cmd_seq[0:5] = '{NOP_CMD, MRS1_CMD, MRS2_CMD, MRS3_CMD, MRS4_CMD, ZQCL_CMD};reg initial_finish = 0;always @(negedge clk) begincs <= ns;endalways @(*) begincase (cs)0: beginif (initial_cnt == INITIAL_CYCLE) begin // wait 200usns = 1;end else beginns = 0;endend1: begin // wait 500us if (initial_stable_cnt == INITIAL_STABLE_CYCLE) begin // wait 500usns = 2;end else beginns = 1;endend2: beginns = 3;end3: beginif (freerun_cnt == FREE_CYCLE) beginif (initial_finish) beginns = 4;end else beginns = 2;endend else beginns = 3;endend4: beginif (wren_s) beginns = 5; // Goto ACTIVATE max(tRC, tRRD, tFAW/4), same bank ACTIVATE at least tRC, different bank ACTIVATE at least tRRD, no more than four bank ACT during tFAW      (P161 Fig.67)end else if (rden_s) beginns = 10; // READ Operation tCCD consecutive read end else beginns = 4;endend5: begin // WRITE ACTIVATEif (trcd_cnt == 14) beginns = 6; // WRITE/READ Operation prior to tRCD after ACTend else beginns = 5;end end6: begin // WRITE WRITE-WRITE delay tCCD, DATA provided at posedge of DQS with latency AL+CWL in MR0 and MR2 , tWTR tWR P174 P176if (twl_cnt == 10) begin // tCWL + tAL = 10 ddr_dq_o_r has extra one cycle delay -> 10 - 2ns = 7;end else beginns = 6;endend7: begin // WRITE DATA WL latency
//           if (ddr_dqs_i) begin // tDQSS = 0if (burst_cnt == 4) begin // double burst == 8ns = 8;end else beginns = 7;end//          end else begin//              ns = 7;//          endend8: begin // POSTEAMBLE if (twr_cnt == 16) beginns = 9; // Write to ReCharge tWR >15ns ACT to ReCharge tRAS>33nsend else beginns = 8;endend9: begin // READ PRECHARGEns = 4;end10: begin // READ ACTIVATEif (trcd_cnt == 14) beginns = 11; // WRITE/READ Operation prior to tRCD after ACTend else beginns = 10;end end11: begin // READ P166 Nonconsecutive READif (trl_cnt == 14 + 3) begin // AL + CL + ddr_pipe_delay(idelay,iddrns = 12;end else beginns = 11;endend12: begin // READ DATA CL latencyif (burst_cnt == 4) beginns = 13;end else beginns = 12;endend13: begin // READ POSTAMBLEif (tRTP_cnt == 7) beginns = 14; // Read to ReCharge tRTP>max(7.5ns,4CK) ACT to ReCharge tRAS>33nsend else beginns = 13;endend14: begin // READ PRECHARGEns = 4; enddefault: beginns = 0;endendcaseendalways @(negedge clk) begincase (ns)0: begininitial_cnt <= initial_cnt + 1;enddefault: begininitial_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)1: begininitial_stable_cnt <= initial_stable_cnt + 1;enddefault: begininitial_stable_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)3: beginfreerun_cnt <= freerun_cnt + 1;enddefault: beginfreerun_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)2: beginif (initial_cmd_ptr == 6 - 1) begininitial_finish <= 1;end else begininitial_finish <= 0;endinitial_cmd_ptr <= initial_cmd_ptr + 1;endendcaseendinitial begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en, ddr_dq_en, ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n, ddr_ba, ddr_addr, ddr_odt} <= NOP_CMD;{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= NOP_CMD;endalways @(negedge clk) begincase (ns)5: begintrcd_cnt <= trcd_cnt + 1;end10: begintrcd_cnt <= trcd_cnt + 1;enddefault: begintrcd_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)6: begintwl_cnt <= twl_cnt + 1;enddefault: begintwl_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)11: begintrl_cnt <= trl_cnt + 1;enddefault: begintrl_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)8: begintwr_cnt <= twr_cnt + 1;enddefault: begintwr_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)13: begintRTP_cnt <= tRTP_cnt + 1;enddefault: begintRTP_cnt <= 0;endendcaseendalways @(negedge clk) begincase (ns)7: beginburst_cnt <= burst_cnt + 1; // writeend12: beginburst_cnt <= burst_cnt + 1; // readenddefault: beginburst_cnt <= 0;endendcaseendassign {wraddr_ba_s, wraddr_ra_s, wraddr_ca_s} = s_wraddr;assign wrdata_s = s_wrdata;assign wrstrb_s = s_wrstrb;assign wren_s = s_wren;assign {rdaddr_ba_s, rdaddr_ra_s, rdaddr_ca_s} = s_rdaddr;assign s_rddata = rddata_r;// assign rdstrb_s = s_rdstrb;assign rden_s = s_rden;always @(negedge clk) begincase (ns)5: beginif (trcd_cnt == 0) begin{wraddr_ba_r, wraddr_ra_r, wraddr_ca_r} = s_wraddr;wrdata_r <= s_wrdata;wrstrb_r <= s_wrstrb;wren_r <= s_wren;endend10: beginif (trcd_cnt == 0) begin{rdaddr_ba_r, rdaddr_ra_r, rdaddr_ca_r} = s_rdaddr;// rddata_r <= s_rddata;// rdstrb_r <= s_rdstrb;rden_r <= s_rden;endendendcaseendalways @(negedge clk) begincase (ns)0: beginddr_reset_n <= 1'b0;{ddr_cke_p2, ddr_cke_p1}    <= 2'b0;ddr_dqs_en_r <= 1'b1;ddr_dq_en_r  <= 1'b1;end1: beginddr_reset_n <= 1'b1;{ddr_cke_p2, ddr_cke_p1}    <= 2'b0;ddr_dqs_en_r <= 1'b1;ddr_dq_en_r <= 1'b1;end2: begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= initial_cmd_seq[initial_cmd_ptr];end3: begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= NOP_CMD;end4: begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= NOP_CMD;end5: beginif (trcd_cnt == 0) begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11110011, wraddr_ba_s, wraddr_ra_s, 1'b0}; // ACT_CMD | end else begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= NOP_CMD;endend6: beginif (twl_cnt == 0) begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11010100, wraddr_ba_r, 6'b0, wraddr_ca_r, 1'b0}; // WR_CMD | end else begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11010111, 3'b000, 16'h0000, 1'b0}; //enable dqs clock NOP_CMD | endend7: beginif (burst_cnt == 0) beginddr_dqs_en_r <= 0;ddr_dq_en_r <= 0;ddr_dq_o_r_p1 <= wrdata_r;ddr_dq_o_r_p2 <= 0;ddr_dm_o_r_p1 <= ~wrstrb_r;ddr_dm_o_r_p2 <= 1;end else beginddr_dqs_en_r <= 0;ddr_dq_en_r <= 0;ddr_dq_o_r_p1 <= 0;ddr_dq_o_r_p2 <= 0;ddr_dm_o_r_p1 <= 1;ddr_dm_o_r_p2 <= 1;endend8: beginif (twr_cnt == 0) beginddr_dqs_en_r <= 0;ddr_dq_en_r <= 0;end else beginddr_dqs_en_r <= 1;ddr_dq_en_r <= 1;endddr_dq_o_r_p1 <= 0;ddr_dq_o_r_p2 <= 0;ddr_dm_o_r_p1 <= 1;ddr_dm_o_r_p2 <= 1;end9: begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11110010, wraddr_ba_r, 16'h0000, 1'b0}; // PRECHARGE single bank PRE_CMD | end10: begin // READ ACTIVATEif (trcd_cnt == 0) begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11110011, rdaddr_ba_s, rdaddr_ra_s, 1'b0}; // ACT_CMD | end else begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= NOP_CMD;endend11: begin // READ CMDif (trl_cnt == 0) begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11110101, rdaddr_ba_r, 6'b0, rdaddr_ca_r, 1'b0}; // RD_CMD | end else begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11110111, 3'b000, 16'h0000, 1'b0}; //enable dqs clock NOP_CMD | endend12: begin // READ DATA // tDQSQ(MAX) tQHif (burst_cnt == 0) beginrddata_r <= dq_i_r_p1;end else beginrddata_r <= 'bx;endend13: begin // READ POSTAMBLErddata_r <= 'bz;end14: begin{ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= {8'b11110010, rdaddr_ba_r, 16'h0000, 1'b0}; // PRECHARGE single bank PRE_CMD | enddefault: beginddr_reset_n <= 1'b1;endendcaseendalways @(*) beginddr_dqs_o = clk;endendmodule

上述代码在Vivado 2017.4中进行了仿真测试,可替换ddr示例工程中的example_top自行仿真。
在这里插入图片描述

对应激励如下。

initial begin# 900000000;repeat(100) @(negedge sys_clk_i);s_wren <= 1;s_wraddr <= {3'b110, 16'h4444, 10'h0};s_wrdata <= 8'h66;s_wrstrb <= 1'b1;@(negedge sys_clk_i);s_wren <= 0;repeat(100) @(negedge sys_clk_i);s_rden <= 1;s_rdaddr <= {3'b110, 16'h4444, 10'h0};@(negedge sys_clk_i);s_rden <= 0;
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624964.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

市场复盘总结 20240115

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 昨日主题投资 连板进级率 0% 失效 二进三&#xff1a; 进级率 中位数50% 最常用的二种方法&#xff1a; 方…

记录centos7.9 离线安装fastllm 编译遇到的问题

centos7.9 安装fastllm 编译步骤 Step1安装cmake: 参考: https://bitsanddragons.wordpress.com/2022/09/19/error-cmake-3-1-or-higher-is-required-you-are-running-version-on-centos-7-x/ ​ 问题1&#xff1a;/lib64/libstdc.so.6: version GLIBCXX_3.4.20‘ not found …

解决Qt的release构建下无法进入断点调试的问题

在工作的时候遇到了第三方库只提供release版本的库的情况&#xff0c;我需要在这基础上封装一层自家库&#xff0c;在调试的时候遇到如下问题&#xff0c;但是在Qt环境下&#xff0c;release的库只能在进行release构建和调试。 卡在了一直进不了断点的情况。提示内容如下&#…

数据库知识汇总之MySQL

目录 MySQL数据库特点MySQL下载MySQL配置文件初始化MySQL配置安装MySQL服务 启动MySQL服务登录数据库修改数据库登录密码MySQL错误代码1130 MySQL数据库特点 MySQL是一个开源关系型数据库管理系统(RDBMS)&#xff0c;由Oracle公司维护和开发。它使用SQL语言进行数据库管理和操…

【LeetCode题目详解】59. 螺旋矩阵 II 54. 螺旋矩阵 LCR 146. 螺旋遍历二维数组(c++)

这篇文章的题目稍微难一点 题目建议&#xff1a; 本题关键还是在转圈的逻辑&#xff0c;在二分搜索中提到的区间定义&#xff0c;在这里又用上了。 一、59. 螺旋矩阵 II 题目&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按…

DataX的安装使用

DataX概述&#xff1a; DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台&#xff0c;实现包括 MySQL、Oracle、HDFS、Hive、OceanBase、HBase、OTS、ODPS 等各种异构数据源之间高效的数据同步功能。DataX采用了框架 插件 的模式&#xff0c;目前已开源&#xff0c;代…

如何用GPT制作PPT和写代码?

详情点击链接&#xff1a;如何用GPT制作PPT和写模型代码&#xff1f; 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Claude2二定…

【Docker】快速入门之Docker的安装及使用

一、引言 1、什么是Docker Docker是一个开源的应用容器引擎&#xff0c;它让开发者可以将他们的应用及其依赖打包到一个可移植的镜像中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之…

软件测试|使用pillow给图片添加水印

简介 水印是一种在图片上添加文字或图像的技术&#xff0c;用于标识图片的来源、版权信息或其他附加信息。Pillow 是一个强大的 Python 图像处理库&#xff0c;它提供了许多功能&#xff0c;包括给图片添加水印。本文将详细介绍如何使用 Pillow 给图片添加水印。 创建水印 在…

SpringBoot中整合ElasticSearch快速入门以及踩坑记录

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_本地运行若依前后端分离-CSDN博客 参考上面搭建项目。 ElaticSearch Elasticsearch 是java开发的&#xff0c;基于 Lucene 的搜索引擎。它提供了一…

Android perfetto memory开源工具分析

目录 原理 官网链接 下载heap_profile producer_support.cc 本地编译 push heapprofd 工具使用 pb文件获取 打开*.pb文件 trace文件 提高系统CPU性能 拆解特定函数内存占用 环境配置 工具使用 修改heap_profile 脚本 原理 Android perfetto memory分析工具和ma…

QT图表-折线图、曲线图

时间记录&#xff1a;2024/1/15 一、使用步骤 1.添加图表模块 .pro项目管理文件中添加charts模块 QChart类&#xff1a;图表类 QChartView类&#xff1a;图表显示类 2.ui文件中添加QChartView组件 &#xff08;1&#xff09;选择一个QGrapicsView组件将其拖拽到ui界面上合适位…

pandas查看数据常用方法(以excel为例)

目录 1.查看指定行数的数据head() 2. 查看数据表头columns 3.查看索引index 4.指定索引列index_col 5.按照索引排序 6.按照数据列排序sort_values() 7.查看每列数据类型dtypes 8.查看指定行列数据loc 9.查看数据是否为空isnull() 1.查看指定行数的数据head() &#xff…

二分图带权最大匹配-KM算法详解

文章目录 零、前言一、红娘再牵线二、二分图带权最大完备匹配2.1二分图带权最大匹配2.2概念2.3KM算法2.3.1交错树2.3.2顶标2.3.3相等子图2.3.4算法原理2.3.5算法实现 三、OJ练习3.1奔小康赚大钱3.2Ants 零、前言 关于二分图&#xff1a;二分图及染色法判定-CSDN博客 关于二分…

JVM 一些重要配置参数

1、内存配置参数 -Xmx<size>&#xff1a;设置Java堆的最大内存。如 -Xmx2g 将堆的最大大小设置为2G&#xff0c;推荐配置为系统可用内存的70-80%-Xms<size>&#xff1a;设置Java堆的初始内存。如 -Xms2g 将堆的初始大小设置为2G&#xff0c;推荐配置与-Xmx的值相同…

华为云优惠券介绍、种类、领取入口及使用教程

华为云作为国内领先的云服务提供商&#xff0c;为了吸引用户&#xff0c;经常推出各种优惠活动&#xff0c;其中就包括华为云优惠券。通过领取和使用优惠券&#xff0c;可以降低用户上云成本&#xff0c;提升用户上云的使用体验。本文将详细介绍华为云的优惠券&#xff0c;包括…

Notepad++安装步骤

Notepad是一款文本编辑工具&#xff0c;支持27种编程语言&#xff0c;通吃C,C ,Java ,C#, XML, HTML, PHP,JS 等&#xff0c;该软件拥有完整的中文化接口及支持多国语言编写的功能&#xff0c;不仅可以用来制作一般的纯文字说明文件&#xff0c;还非常适合编写计算机程序代码&a…

2024年,如何打造惊艳的个人博客/出版系统并且赚点小钱?

几年前&#xff0c;我就推荐过用Markdown写作静态博客。静态博客几乎是零托管成本&#xff0c;比较适合个人博客起步。Markdown便于本地搜索&#xff0c;也可当作是个人知识库方案。 现在有了新的进展。我不仅构建了一个视觉上相当不错的个人网站&#xff0c;还美化了github、…

Mybatis配置动态数据源以及参数传递等

Mybatis必知必会 一、Mybatis动态加载数据源 在配置数据源连接时,在企业的真实开发中数据源一般都会写在配置文件中&#xff0c;而不会直接写在mybatis的核心配置文件中 所以,Mybatis为了方便开发人员去动态的获取数据源连接制定了一些特定的标签用于加载这些数据源。 具体做法…