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

More code

parent ea560b4a
......@@ -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),
......
/*******************************************************************************
* 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
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment