/*!
* Module:dq_single
* @file dq_single.v
* @date 2014-04-26
* @author Andrey Filippov
*
* @brief Single-bit DDR3 DQ I/O, same used for DM
*
* @copyright Copyright (c) 2014 Elphel, Inc.
*
* License:
*
* dq_single.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.
*
* dq_single.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 .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*/
`timescale 1ns/1ps
module dq_single #(
parameter IODELAY_GRP ="IODELAY_MEMORY",
parameter integer IDELAY_VALUE = 0,
parameter integer ODELAY_VALUE = 0,
parameter IBUF_LOW_PWR ="TRUE",
parameter IOSTANDARD = "SSTL15_T_DCI",
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)
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
);
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
wire dq_di;
oserdes_mem#(
.MODE_DDR("TRUE")
) oserdes_i (
.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
.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
.tout_iob(dq_tri) // tristate out to be connected directly to the tristate control of the output buffer
);
odelay_fine_pipe # (
.IODELAY_GRP(IODELAY_GRP),
.DELAY_VALUE(ODELAY_VALUE),
.REFCLK_FREQUENCY(REFCLK_FREQUENCY),
.HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
) dq_out_dly_i(
.clk(clk_div),
.rst(rst),
.set(set_odelay),
.ld(ld_odelay),
.delay(dly_data[7:0]),
.data_in(d_ser),
.data_out(dq_data_dly)
);
IOBUF_DCIEN #(
.IBUF_LOW_PWR(IBUF_LOW_PWR), //
.IOSTANDARD(IOSTANDARD),
.SLEW(SLEW),
.USE_IBUFDISABLE("FALSE")
) iobufs_dq_i (
.O(dq_di),
.IO(dq),
.DCITERMDISABLE(dci_disable),
.IBUFDISABLE(1'b0),
.I(dq_data_dly), //dqs_data),
.T(dq_tri));
idelay_fine_pipe # (
.IODELAY_GRP(IODELAY_GRP),
.DELAY_VALUE(IDELAY_VALUE),
.REFCLK_FREQUENCY(REFCLK_FREQUENCY),
.HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE)
) dq_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
.comb_out() // output
);
endmodule