Commit 2aa6f1d2 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

More code

parent ea560b4a
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
 * Module: byte_lane
 * Date:2014-04-26  
 * Author: Andrey Filippov
 * Description: DDR3 byte lane, ingluding DQS I/O, 8xDQ I/O and DM output 
 * Description: DDR3 byte lane, including DQS I/O, 8xDQ I/O and DM output 
 *
 * Copyright (c) 2014 Elphel, Inc.
 * byte_lane.v is free software; you can redistribute it and/or modify
@@ -44,7 +44,7 @@ module byte_lane #(
    input   [3:0] tin_dq,          // tristate for data out (sent out earlier than data!) and dm 
    input   [3:0] din_dqs,         // parallel data to be sent out over DQS
    input   [3:0] tin_dqs,         // tristate for DQS out (sent out earlier than data!) 
    output [31:0] dout,            // parallel data received from DDR3 memory, 4 bits per DG I/O
    output [31:0] dout,            // parallel data received from DDR3 memory, 4 bits per DQ I/O
    input   [7:0] dly_data,        // delay value (3 LSB - fine delay)
    input   [4:0] dly_addr,        // select which delay to program
    input         ld_delay,        // load delay data to selected iodelayl (clk_iv synchronous)
@@ -91,7 +91,7 @@ end

generate
    genvar i;
    for (i=0; i<7; i=i+1) begin: dq_block
    for (i=0; i < 8; i=i+1) begin: dq_block
    dq_single #(
        .IODELAY_GRP(IODELAY_GRP),
        .IBUF_LOW_PWR(IBUF_LOW_PWR),

phy/cmd_addr.v

0 → 100644
+259 −0
Original line number Diff line number Diff line
/*******************************************************************************
 * Module: cmd_addr
 * Date:2014-04-26  
 * Author: Andrey Filippov
 * Description: DDR3 command/address signals 
 *
 * Copyright (c) 2014 Elphel, Inc.
 * cmd_addr.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  cmd_addr.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
 *******************************************************************************/
`timescale 1ns/1ps

module  cmd_addr #(
    parameter IODELAY_GRP = "IODELAY_MEMORY",
    parameter IOSTANDARD =  "SSTL15",
    parameter SLEW =        "SLOW",
    parameter real REFCLK_FREQUENCY = 300.0,
    parameter HIGH_PERFORMANCE_MODE = "FALSE",
    parameter ADDRESS_NUMBER=         15
)(
    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                       ddr3_we,  // output WE port
    output                       ddr3_ras, // output RAS port
    output                       ddr3_cas, // output CAS port
    output                       ddr3_cke, // output Clock Enable port
    output                       ddr3_odt, // output ODT port
    input                        clk,      // free-running system clock, same frequency as iclk (shared for R/W)
    input                        clk_div,  // free-running half clk frequency, front aligned to clk (shared for R/W)
    input                        rst,      // 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                  [5:0] in_ba,    // input bank address, 2 bits per signal (first, second)
    input                  [1:0] in_we,    // input WE, 2 bits (first, second)
    input                  [1:0] in_ras,   // input RAS, 2 bits (first, second)
    input                  [1:0] in_cas,   // input CAS, 2 bits (first, second)
    input                  [1:0] in_cke,   // input CKE, 2 bits (first, second)
    input                  [1:0] in_odt,   // input ODT, 2 bits (first, second)
    input                  [1:0] in_tri,   // tristate command/address outputs - same timing, but no odelay
    input                  [7:0] dly_data, // delay value (3 LSB - fine delay)
    input                  [4:0] dly_addr, // select which delay to program
    input                        ld_delay, // load delay data to selected iodelayl (clk_iv synchronous)
    input                        set       // clk_div synchronous set all delays from previously loaded values
);
reg  [2*ADDRESS_NUMBER-1:0] in_a_r=0;
reg  [5:0] in_ba_r=0;
reg  [1:0] in_we_r=2'h3, in_ras_r=2'h3, in_cas_r=2'h3, in_cke_r=2'h3, in_odt_r=2'h0;
reg  [1:0] in_tri_r=2'h0; // or tri-state on reset?
reg  [7:0] dly_data_r=0; 
reg        set_r=0;
reg  [7:0] ld_dly_cmd=8'b0;
reg  [ADDRESS_NUMBER-1:0] ld_dly_addr=0;
wire  [ADDRESS_NUMBER-1:0] decode_addr;
wire [7:0] decode_sel={
    (dly_addr[2:0]==7)?1'b1:1'b0,
    (dly_addr[2:0]==6)?1'b1:1'b0,
    (dly_addr[2:0]==5)?1'b1:1'b0,
    (dly_addr[2:0]==4)?1'b1:1'b0,
    (dly_addr[2:0]==3)?1'b1:1'b0,
    (dly_addr[2:0]==2)?1'b1:1'b0,
    (dly_addr[2:0]==1)?1'b1:1'b0,
    (dly_addr[2:0]==0)?1'b1:1'b0};

always @ (posedge clk_div or posedge rst) begin
    if (rst) begin
        in_a_r <= 0; in_ba_r <= 6'b0;
        in_we_r <= 2'h3; in_ras_r <= 2'h3; in_cas_r <= 2'h3; in_cke_r <= 2'h3; in_odt_r <= 2'h0;
        in_tri_r <= 2'h0; // or tri-state on reset?
        dly_data_r<=8'b0;set_r<=1'b0;
        ld_dly_cmd <= 8'b0; ld_dly_addr <= 0;
    end else begin
        in_a_r <= in_a;
        in_ba_r <= in_ba; 
        in_we_r <= in_we; in_ras_r <= in_ras; in_cas_r <= in_cas; in_cke_r <= in_cke; in_odt_r <= in_odt;
        in_tri_r <= in_tri;
        dly_data_r<=dly_data;set_r<=set;
        ld_dly_cmd <=  {8 { dly_addr[4] & dly_addr[3] & ld_delay}} & decode_sel[7:0];
        ld_dly_addr <= {(ADDRESS_NUMBER-1) {ld_delay}} & decode_addr;
    end
end     

// All addresses
generate
    genvar i;
    for (i=0; i<ADDRESS_NUMBER; i=i+1) begin: addr_block
       assign decode_addr[i]=(ld_dly_addr[4:0] == i)?1'b1:1'b0;
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_addr_i (
    .dq(ddr3_a),               // I/O pad (appears on the output 1/2 clk_div earlier, than DDR data)
    .clk(clk),          // free-running system clock, same frequency as iclk (shared for R/W)
    .clk_div(clk_div),      // free-running half clk frequency, front aligned to clk (shared for R/W)
    .rst(rst),
    .dly_data(dly_data_r[7:0]),     // delay value (3 LSB - fine delay)
    .din(in_a_r[2*i+1:2*i]),      // parallel data to be sent out
    .tin(in_tri_r[1:0]),          // tristate for data out (sent out earlier than data!) 
    .set_delay(set_r),             // clk_div synchronous load odelay value from dly_data
    .ld_delay(ld_dly_addr[i])      // clk_div synchronous set odealy value from loaded
);       
    end
endgenerate
// Bank addresses
// ba0
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_ba0_i (
    .dq(ddr3_ba[0]),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_ba_r[1:0]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[0]));
// ba1
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_ba1_i (
    .dq(ddr3_ba[1]),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_ba_r[3:2]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[1]));
// ba2
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_ba2_i (
    .dq(ddr3_ba[2]),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_ba_r[5:4]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[2]));

// we
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_we_i (
    .dq(ddr3_we),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_we_r[1:0]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[3]));

// ras
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_ras_i (
    .dq(ddr3_ras),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_ras_r[1:0]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[4]));

// cas
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_cas_i(
    .dq(ddr3_cas),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_cas_r[1:0]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[5]));

// cke
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_cke_i (
    .dq(ddr3_cke),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_cke_r[1:0]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[6]));

// odt
    cmda_single #(
         .IODELAY_GRP(IODELAY_GRP),
         .IOSTANDARD(IOSTANDARD),
         .SLEW(SLEW),
         .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
         .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
    ) cmda_odt_i (
    .dq(ddr3_odt),
    .clk(clk),
    .clk_div(clk_div),
    .rst(rst),
    .dly_data(dly_data_r[7:0]),
    .din(in_odt_r[1:0]),
    .tin(in_tri_r[1:0]), 
    .set_delay(set_r),
    .ld_delay(ld_dly_cmd[7]));

endmodule
+13 −58
Original line number Diff line number Diff line
@@ -22,36 +22,24 @@

module  cmda_single #(
    parameter IODELAY_GRP ="IODELAY_MEMORY",
    parameter IBUF_LOW_PWR ="TRUE",
    parameter IOSTANDARD = "SSTL15",
    parameter SLEW = "SLOW",
    parameter real REFCLK_FREQUENCY = 300.0,
    parameter HIGH_PERFORMANCE_MODE = "FALSE"
)(
    inout        dq,           // I/O pad
    input        iclk,         // source-synchronous clock (BUFR from DQS)
    output       dq,           // I/O pad (appears on the output 1/2 clk_div earlier, than DDR data)
    input        clk,          // free-running system clock, same frequency as iclk (shared for R/W)
    input        clk_div,      // free-running half clk frequency, front aligned to clk (shared for R/W)
    input        inv_clk_div,  // invert clk_div for R channel (clk_div is shared between R and W)
    input        rst,
    input        dci_disable,  // disable DCI termination during writes and idle
    input  [7:0] dly_data,     // delay value (3 LSB - fine delay)
    input  [3:0] din,          // parallel data to be sent out
    input  [3:0] tin,          // tristate for data out (sent out earlier than data!) 
    output [3:0] dout,         // parallel data received from DDR3 memory
    input        set_odelay,   // clk_div synchronous load odelay value from dly_data
    input        ld_odelay,    // clk_div synchronous set odealy value from loaded
    input        set_idelay,   // clk_div synchronous load idelay value from dly_data
    input        ld_idelay     // clk_div synchronous set idealy value from loaded
    input  [1:0] din,          // parallel data to be sent out
    input  [1:0] tin,          // tristate for data out (sent out earlier than data!) 
    input        set_delay,    // clk_div synchronous load odelay value from dly_data
    input        ld_delay      // clk_div synchronous set odealy value from loaded
);
wire d_ser;
wire dq_tri;
wire dq_data_dly;
wire dq_dly;
// keep IOBUF_DCIEN.O to user as output only (UDM/LDM), so the rest of tyhe read channel will be optimized out, but I/O will stay the same
(* keep = "true" *)
wire dq_di;


oserdes_mem#(
    .MODE_DDR("FALSE")
@@ -59,8 +47,8 @@ oserdes_mem#(
    .clk(clk),          // serial output clock
    .clk_div(clk_div),  // oclk divided by 2, front aligned
    .rst(rst),          // reset
    .din(din[3:0]),     // parallel data in
    .tin(tin[3:0]),     // parallel tri-state in
    .din(din[1:0]),     // parallel data in
    .tin(tin[1:0]),     // parallel tri-state in
    .dout_dly(d_ser),   // data out to be connected to odelay input
    .dout_iob(),        // data out to be connected directly to the output buffer
    .tout_dly(),        // tristate out to be connected to odelay input
@@ -74,53 +62,20 @@ odelay_fine_pipe # (
) dqs_out_dly_i(
    .clk(clk_div),
    .rst(rst),
    .set(set_odelay),
    .ld(ld_odelay),
    .set(set_delay),
    .ld(ld_delay),
    .delay(dly_data[7:0]),
    .data_in(d_ser),
    .data_out(dq_data_dly)
);

IOBUF_DCIEN #(
    .IBUF_LOW_PWR(IBUF_LOW_PWR), //
OBUFT #(
    .IOSTANDARD(IOSTANDARD),
    .SLEW(SLEW),
    .USE_IBUFDISABLE("FALSE")
    .SLEW(SLEW)
) iobufs_dqs_i (
    .O(dq_di),
    .IO(dq),
    .DCITERMDISABLE(dci_disable),
    .IBUFDISABLE(1'b0),
    .I(dq_data_dly), //dqs_data),
    .O(dq),
    .I(dq_data_dly),
    .T(dq_tri));

idelay_fine_pipe # (
    .IODELAY_GRP(IODELAY_GRP),
    .DELAY_VALUE(0),
    .REFCLK_FREQUENCY(REFCLK_FREQUENCY),
    .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
) dqs_in_dly_i(
    .clk(clk_div),
    .rst(rst),
    .set(set_idelay),
    .ld(ld_idelay),
    .delay(dly_data[7:0]),
    .data_in(dq_di),
    .data_out(dq_dly)
);

iserdes_mem #(
    .DYN_CLKDIV_INV_EN("FALSE")
) iserdes_mem_i (
    .iclk(iclk),              // source-synchronous clock
    .oclk(clk),               // system clock, phase should allow iclk-to-oclk jitter with setup/hold margin
    .oclk_div(clk_div),       // oclk divided by 2, front aligned
    .inv_clk_div(inv_clk_div),       // invert oclk_div (this clock is shared between iserdes and oserdes. Works only in MEMORY_DDR3 mode?
    .rst(rst),                // reset
    .d_direct(1'b0),          // direct input from IOB, normally not used, controlled by IOBDELAY parameter (set to "NONE")
    .ddly(dq_dly),            // serial input from idelay 
    .dout(dout[3:0])          // parallel data out
);

endmodule