Commit a0c1b572 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

more code for ddr3 phy

parent c73e99f3
Loading
Loading
Loading
Loading
+159 −5
Original line number Original line Diff line number Diff line
@@ -24,15 +24,36 @@ module phy_top #(
    parameter IOSTANDARD_DQ =   "SSTL15_T_DCI",
    parameter IOSTANDARD_DQ =   "SSTL15_T_DCI",
    parameter IOSTANDARD_DQS =  "DIFF_SSTL15_T_DCI",
    parameter IOSTANDARD_DQS =  "DIFF_SSTL15_T_DCI",
    parameter IOSTANDARD_CMDA = "SSTL15",
    parameter IOSTANDARD_CMDA = "SSTL15",
    parameter IOSTANDARD_CLK = "DIFF_SSTL15",
    parameter SLEW_DQ =         "SLOW",
    parameter SLEW_DQ =         "SLOW",
    parameter SLEW_DQS =        "SLOW",
    parameter SLEW_DQS =        "SLOW",
    parameter SLEW_CMDA =       "SLOW",
    parameter SLEW_CMDA =       "SLOW",
    parameter SLEW_CLK =       "SLOW",
    parameter IBUF_LOW_PWR =    "TRUE",
    parameter IBUF_LOW_PWR =    "TRUE",
    parameter IODELAY_GRP =     "IODELAY_MEMORY",
    parameter IODELAY_GRP =     "IODELAY_MEMORY",
    parameter real REFCLK_FREQUENCY = 300.0,
    parameter real REFCLK_FREQUENCY = 300.0,
    parameter HIGH_PERFORMANCE_MODE = "FALSE",
    parameter HIGH_PERFORMANCE_MODE = "FALSE",
    parameter integer ADDRESS_NUMBER= 15
    parameter integer ADDRESS_NUMBER= 15,
    parameter PHASE_WIDTH           = 8,
    parameter BANDWIDTH =     "OPTIMIZED",
    // Assuming 100MHz input clock, 800MHz Fvco, 400MHz clk, 200MHz clk_div, 200MHz mclk 
    parameter CLKIN_PERIOD          = 10, //ns >1.25, 600<Fvco<1200
    parameter CLKFBOUT_MULT =       8, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
    parameter CLKFBOUT_MULT_REF =   9, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
    parameter CLKFBOUT_DIV_REF =    3, // To get 300MHz for the reference clock
    parameter DIVCLK_DIVIDE=        1,
    parameter CLKFBOUT_PHASE =      0.000,
    parameter CLKOUT0_PHASE =       0.000,
    parameter CLKOUT1_PHASE =       0.000,
    parameter CLKOUT2_PHASE =       0.000,
    parameter CLKOUT3_PHASE =       0.000,  
    parameter REF_JITTER1 =         0.010,
    parameter SS_EN =              "FALSE",
    parameter SS_MODE =      "CENTER_HIGH",
    parameter SS_MOD_PERIOD =       10000
)(
)(
    output                       ddr3_clk, // DDR3 clock differential output, positive
    output                       ddr3_nclk,// DDR3 clock differential output, negative
    output  [ADDRESS_NUMBER-1:0] ddr3_a,   // output address ports (14:0) for 4Gb device
    output  [ADDRESS_NUMBER-1:0] ddr3_a,   // output address ports (14:0) for 4Gb device
    output                 [2:0]ddr3_ba,  // output bank address ports
    output                 [2:0]ddr3_ba,  // output bank address ports
    output                       ddr3_we,  // output WE port
    output                       ddr3_we,  // output WE port
@@ -49,8 +70,10 @@ module phy_top #(
    inout                        dqsu,     // UDQS I/O pad
    inout                        dqsu,     // UDQS I/O pad
    inout                        ndqsu,    // ~UDQS I/O pad
    inout                        ndqsu,    // ~UDQS I/O pad
    
    
    input                        clk,      // free-running system clock, same frequency as iclk (shared for R/W)
    input                        clk_in,   // master input clock, initially assuming 100MHz
    input                        clk_div,  // free-running half clk frequency, front aligned to clk (shared for R/W)
    output                       clk,      // free-running system clock, same frequency as iclk (shared for R/W),     BUFR output
    output                       clk_div,  // free-running half clk frequency, front aligned to clk (shared for R/W), BUFR output
    output                       mclk,     // same as clk_div, through separate BUFG and static phase adjust
    input                        rst_in,      // reset delays/serdes
    input                        rst_in,      // reset delays/serdes
    
    
    input [2*ADDRESS_NUMBER-1:0] in_a,     // input address, 2 bits per signal (first, second) (29:0) for 4Gb device
    input [2*ADDRESS_NUMBER-1:0] in_a,     // input address, 2 bits per signal (first, second) (29:0) for 4Gb device
@@ -77,7 +100,10 @@ module phy_top #(
    input                  [7:0] dly_data, // delay value (3 LSB - fine delay)
    input                  [7:0] dly_data, // delay value (3 LSB - fine delay)
    input                  [6:0] dly_addr, // select which delay to program
    input                  [6:0] dly_addr, // select which delay to program
    input                        ld_delay, // load delay data to selected iodelayl (clk_iv synchronous)
    input                        ld_delay, // load delay data to selected iodelayl (clk_iv synchronous)
    input                        set       // clk_div synchronous set all delays from previously loaded values
    input                        set,       // clk_div synchronous set all delays from previously loaded values
    output                       locked,
    output                       ps_rdy,
    output     [PHASE_WIDTH-1:0] ps_out 
);
);
  reg rst=1'b0;
  reg rst=1'b0;
  always @(posedge clk or posedge rst_in) begin
  always @(posedge clk or posedge rst_in) begin
@@ -87,7 +113,11 @@ module phy_top #(
  wire  ld_data_l = (dly_addr[6:5] == 2'h0) && ld_delay ;             
  wire  ld_data_l = (dly_addr[6:5] == 2'h0) && ld_delay ;             
  wire  ld_data_h = (dly_addr[6:5] == 2'h1) && ld_delay ;             
  wire  ld_data_h = (dly_addr[6:5] == 2'h1) && ld_delay ;             
  wire  ld_cmda =   (dly_addr[6:5] == 2'h2) && ld_delay ;             
  wire  ld_cmda =   (dly_addr[6:5] == 2'h2) && ld_delay ;             
  
  wire  ld_mmcm=    (dly_addr[6:0] == 7'h60) && ld_delay ;
  wire  clkfb_ref, clk_ref_pre; 
  wire  clk_ref; // 200MHz/300Mhz to calibrate I/O delays            
  wire locked_mmcm,locked_pll, dly_ready;
  assign locked=locked_mmcm && locked_pll && dly_ready; // both PLL ready, I/O delay calibrated
  cmd_addr #(
  cmd_addr #(
    .IODELAY_GRP(IODELAY_GRP),
    .IODELAY_GRP(IODELAY_GRP),
    .IOSTANDARD(IOSTANDARD_CMDA),
    .IOSTANDARD(IOSTANDARD_CMDA),
@@ -183,6 +213,130 @@ module phy_top #(
    .ld_delay        (ld_data_h),        // load delay data to selected iodelayl (clk_div synchronous)
    .ld_delay        (ld_data_h),        // load delay data to selected iodelayl (clk_div synchronous)
    .set             (set)               // clk_div synchronous set all delays from previously loaded values
    .set             (set)               // clk_div synchronous set all delays from previously loaded values
);
);
//ddr3_clk
wire iclk; // BUFIO
    oddr_ds #(
        .IOSTANDARD(IOSTANDARD_CLK),
        .SLEW(SLEW_CLK)
    ) oddr_ds_i (
        .clk(iclk), // input
        .ce(1'b1), // input
        .rst(1'b0), // input
        .set(1'b0), // input
        .din(2'b01), // input[1:0] 
        .dq(ddr3_clk), // output
        .ndq(ddr3_nclk) // output
    );
// Clocks: MMCM is used to generate ddr3 differential clock (no dynamic phase shift),
// clk - write bit clock, phase dynamically adjusted, BUFR (initially 400MHz)
// clk_div  half bit frequency clock, phase dynamically adjusted, BUFR. Used also for delay/phase control (200MHz)
// mclk - same frequency as clk_div (same dynamic phase adjust), but with BUFG to be used in other regions. Phase to be
// statically adjusted for clock boundary crossing
// Phase control included, allowing setting phase in +/- 127 steps, each 1/56 of 1/Fvco (~22ps for Fvco=800MHz)
wire clk_pre, clk_div_pre, iclk_pre, mclk_pre, clk_fb;
BUFR clk_bufr_i (.O(clk), .CE(), .CLR(), .I(clk_pre));
BUFR clk_div_bufr_i (.O(clk_div), .CE(), .CLR(), .I(clk_div_pre));
BUFIO iclk_bufio_i (.O(iclk), .I(iclk_pre) );
BUFIO clk_ref_i (.O(clk_ref), .I(clk_ref_pre));
BUFG mclk_i (.O(mclk),.I(mclk_pre) );
    /* Instance template for module mmcm_phase_cntr */
    mmcm_phase_cntr #(
        .PHASE_WIDTH         (PHASE_WIDTH),
        .CLKIN_PERIOD        (CLKIN_PERIOD),
        .BANDWIDTH           (BANDWIDTH),
        .CLKFBOUT_MULT_F     (CLKFBOUT_MULT),
        .DIVCLK_DIVIDE       (DIVCLK_DIVIDE),
        .CLKFBOUT_PHASE      (CLKFBOUT_PHASE),
        .CLKOUT0_PHASE       (CLKOUT0_PHASE),
        .CLKOUT1_PHASE       (CLKOUT1_PHASE),
        .CLKOUT2_PHASE       (CLKOUT2_PHASE),
        .CLKOUT3_PHASE       (CLKOUT3_PHASE),
//        .CLKOUT4_PHASE          (0.000),
//        .CLKOUT5_PHASE          (0.000),
//        .CLKOUT6_PHASE          (0.000),
        .CLKFBOUT_USE_FINE_PS     ("FALSE"),
        .CLKOUT0_USE_FINE_PS      ("FALSE"),
        .CLKOUT1_USE_FINE_PS ("TRUE"),
        .CLKOUT2_USE_FINE_PS ("TRUE"),
        .CLKOUT3_USE_FINE_PS ("TRUE"),
//        .CLKOUT4_USE_FINE_PS("FALSE"),
//        .CLKOUT5_USE_FINE_PS("FALSE"),
//        .CLKOUT6_USE_FINE_PS("FALSE"),
        .CLKOUT0_DIVIDE_F    (2.000),
        .CLKOUT1_DIVIDE      (2),
        .CLKOUT2_DIVIDE      (4),
        .CLKOUT3_DIVIDE      (4),
//        .CLKOUT4_DIVIDE(1),
//        .CLKOUT5_DIVIDE(1),
//        .CLKOUT6_DIVIDE(1),
        .COMPENSATION             ("ZHOLD"),
        .REF_JITTER1         (REF_JITTER1),
//        .REF_JITTER2(0.010),
        .SS_EN               (SS_EN),
        .SS_MODE             (SS_MODE),
        .SS_MOD_PERIOD       (SS_MOD_PERIOD),
        .STARTUP_WAIT             ("FALSE")
    ) mmcm_phase_cntr_i (
        .clkin               (clk_in), // input
        .clkfbin             (clk_fb), // input
        .rst                 (rst), // input
        .pwrdwn                 (1'b0), // input
        .psclk               (clk_div), // input
        .ps_we               (ld_mmcm), // input
        .ps_din              (dly_data), // input[7:0] 
        .ps_ready            (ps_rdy), // output
        .ps_dout             (ps_out), // output[7:0] reg 
        .clkout0             (iclk_pre), // output
        .clkout1             (clk_pre), // output
        .clkout2             (clk_div_pre), // output
        .clkout3             (mclk_pre), // output
        .clkout4(), // output
        .clkout5(), // output
        .clkout6(), // output
        .clkout0b(), // output
        .clkout1b(), // output
        .clkout2b(), // output
        .clkout3b(), // output
        .clkfbout(clk_fb), // output
        .clkfboutb(), // output
        .locked(locked_mmcm) // output
    );

// Generate reference clock for the I/O delays
    /*
         parameter CLKFBOUT_MULT_REF =   9, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
    parameter CLKFBOUT_DIV_REF =   3, // To get 300MHz for the reference clock
     Instance template for module pll_base */
    pll_base #(
        .CLKIN_PERIOD(CLKIN_PERIOD),
        .BANDWIDTH("OPTIMIZED"),
        .CLKFBOUT_MULT(CLKFBOUT_MULT_REF),
        .CLKOUT0_DIVIDE(CLKFBOUT_DIV_REF),
        .REF_JITTER1(0.010),
        .STARTUP_WAIT("FALSE")
    ) pll_base_i (
        .clkin(clk_in), // input
        .clkfbin(clkfb_ref), // input
        .rst(rst), // input
        .pwrdwn(1'b0), // input
        .clkout0(clk_ref_pre), // output
        .clkout1(), // output
        .clkout2(), // output
        .clkout3(), // output
        .clkout4(), // output
        .clkout5(), // output
        .clkfbout(clkfb_ref), // output
        .locked(locked_pll) // output
    );
// Does it need to be re-calibrated periodically?
idelay_ctrl# (
 .IODELAY_GRP("IODELAY_MEMORY")
) idelay_ctrl_i (
    .refclk(clk_ref),
    .rst(rst),
    .rdy(dly_ready)
);



endmodule
endmodule