2012-02-20 10:13:56 -05:00
|
|
|
/*
|
|
|
|
* 1:2 DDR PHY for Spartan-6
|
|
|
|
*
|
|
|
|
* Command path:
|
|
|
|
* posedge sys_clk + 1
|
2012-02-20 17:55:20 -05:00
|
|
|
* posedge clk2x_270 + 0.375
|
|
|
|
* negedge clk2x_270 + 0.125
|
|
|
|
* Command latency: 1.5 cycles
|
2012-02-20 10:13:56 -05:00
|
|
|
*
|
|
|
|
* Data write path (phase 0, word 0):
|
|
|
|
* posedge sys_clk [oserdes] + 1
|
|
|
|
* strobe [oserdes] + 1
|
|
|
|
* Data write latency: 2 cycles
|
|
|
|
*
|
|
|
|
* DQS OE path:
|
|
|
|
* posedge sys_clk + 1
|
2012-02-20 17:55:20 -05:00
|
|
|
* posedge clk2x_270 + 0.375
|
|
|
|
* negedge clk2x_270 [oddr] + 0.125
|
|
|
|
* DQS OE latency 1.5 cycles
|
2012-02-20 10:13:56 -05:00
|
|
|
*
|
|
|
|
* Data read path:
|
|
|
|
*/
|
2012-02-19 12:43:42 -05:00
|
|
|
module s6ddrphy #(
|
|
|
|
parameter NUM_AD = 0,
|
|
|
|
parameter NUM_BA = 0,
|
|
|
|
parameter NUM_D = 0 /* < number of data lines per DFI phase */
|
|
|
|
) (
|
|
|
|
/* Clocks */
|
|
|
|
input sys_clk,
|
2012-02-20 17:55:20 -05:00
|
|
|
input clk2x_270,
|
2012-02-19 12:43:42 -05:00
|
|
|
input clk4x_wr,
|
|
|
|
input clk4x_wr_strb,
|
|
|
|
input clk4x_rd,
|
|
|
|
input clk4x_rd_strb,
|
|
|
|
|
|
|
|
/* DFI phase 0 */
|
|
|
|
input [NUM_AD-1:0] dfi_address_p0,
|
|
|
|
input [NUM_BA-1:0] dfi_bank_p0,
|
|
|
|
input dfi_cs_n_p0,
|
|
|
|
input dfi_cke_p0,
|
|
|
|
input dfi_ras_n_p0,
|
|
|
|
input dfi_cas_n_p0,
|
|
|
|
input dfi_we_n_p0,
|
|
|
|
input dfi_wrdata_en_p0,
|
|
|
|
input [NUM_D/8-1:0] dfi_wrdata_mask_p0,
|
|
|
|
input [NUM_D-1:0] dfi_wrdata_p0,
|
|
|
|
input dfi_rddata_en_p0,
|
|
|
|
output [NUM_D-1:0] dfi_rddata_w0,
|
|
|
|
output dfi_rddata_valid_w0,
|
|
|
|
|
|
|
|
/* DFI phase 1 */
|
|
|
|
input [NUM_AD-1:0] dfi_address_p1,
|
|
|
|
input [NUM_BA-1:0] dfi_bank_p1,
|
|
|
|
input dfi_cs_n_p1,
|
|
|
|
input dfi_cke_p1,
|
|
|
|
input dfi_ras_n_p1,
|
|
|
|
input dfi_cas_n_p1,
|
|
|
|
input dfi_we_n_p1,
|
|
|
|
input dfi_wrdata_en_p1,
|
|
|
|
input [NUM_D/8-1:0] dfi_wrdata_mask_p1,
|
|
|
|
input [NUM_D-1:0] dfi_wrdata_p1,
|
|
|
|
input dfi_rddata_en_p1,
|
|
|
|
output [NUM_D-1:0] dfi_rddata_w1,
|
|
|
|
output dfi_rddata_valid_w1,
|
|
|
|
|
|
|
|
/* DDR SDRAM pads */
|
|
|
|
output sd_clk_out_p,
|
|
|
|
output sd_clk_out_n,
|
2012-02-19 14:49:56 -05:00
|
|
|
output reg [NUM_AD-1:0] sd_a,
|
|
|
|
output reg [NUM_BA-1:0] sd_ba,
|
|
|
|
output reg sd_cs_n,
|
|
|
|
output reg sd_cke,
|
|
|
|
output reg sd_ras_n,
|
|
|
|
output reg sd_cas_n,
|
|
|
|
output reg sd_we_n,
|
2012-02-19 12:43:42 -05:00
|
|
|
inout [NUM_D/2-1:0] sd_dq,
|
|
|
|
output [NUM_D/16-1:0] sd_dm,
|
|
|
|
inout [NUM_D/16-1:0] sd_dqs
|
|
|
|
);
|
|
|
|
|
2012-02-19 14:49:56 -05:00
|
|
|
/*
|
|
|
|
* SDRAM clock
|
|
|
|
*/
|
|
|
|
ODDR2 #(
|
|
|
|
.DDR_ALIGNMENT("NONE"),
|
|
|
|
.INIT(1'b0),
|
|
|
|
.SRTYPE("SYNC")
|
|
|
|
) sd_clk_forward_p (
|
|
|
|
.Q(sd_clk_out_p),
|
2012-02-20 17:55:20 -05:00
|
|
|
.C0(clk2x_270),
|
|
|
|
.C1(~clk2x_270),
|
2012-02-19 14:49:56 -05:00
|
|
|
.CE(1'b1),
|
|
|
|
.D0(1'b1),
|
|
|
|
.D1(1'b0),
|
|
|
|
.R(1'b0),
|
|
|
|
.S(1'b0)
|
|
|
|
);
|
|
|
|
ODDR2 #(
|
|
|
|
.DDR_ALIGNMENT("NONE"),
|
|
|
|
.INIT(1'b0),
|
|
|
|
.SRTYPE("SYNC")
|
|
|
|
) sd_clk_forward_n (
|
|
|
|
.Q(sd_clk_out_n),
|
2012-02-20 17:55:20 -05:00
|
|
|
.C0(clk2x_270),
|
|
|
|
.C1(~clk2x_270),
|
2012-02-19 14:49:56 -05:00
|
|
|
.CE(1'b1),
|
|
|
|
.D0(1'b0),
|
|
|
|
.D1(1'b1),
|
|
|
|
.R(1'b0),
|
|
|
|
.S(1'b0)
|
|
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Command/address
|
|
|
|
*/
|
|
|
|
|
|
|
|
reg phase_sel;
|
2012-02-20 17:55:20 -05:00
|
|
|
always @(negedge clk2x_270)
|
2012-02-19 14:49:56 -05:00
|
|
|
phase_sel <= sys_clk;
|
|
|
|
|
|
|
|
reg [NUM_AD-1:0] r_dfi_address_p0;
|
|
|
|
reg [NUM_BA-1:0] r_dfi_bank_p0;
|
|
|
|
reg r_dfi_cs_n_p0;
|
|
|
|
reg r_dfi_cke_p0;
|
|
|
|
reg r_dfi_ras_n_p0;
|
|
|
|
reg r_dfi_cas_n_p0;
|
|
|
|
reg r_dfi_we_n_p0;
|
|
|
|
reg [NUM_AD-1:0] r_dfi_address_p1;
|
|
|
|
reg [NUM_BA-1:0] r_dfi_bank_p1;
|
|
|
|
reg r_dfi_cs_n_p1;
|
|
|
|
reg r_dfi_cke_p1;
|
|
|
|
reg r_dfi_ras_n_p1;
|
|
|
|
reg r_dfi_cas_n_p1;
|
|
|
|
reg r_dfi_we_n_p1;
|
|
|
|
|
|
|
|
always @(posedge sys_clk) begin
|
|
|
|
r_dfi_address_p0 <= dfi_address_p0;
|
|
|
|
r_dfi_bank_p0 <= dfi_bank_p0;
|
|
|
|
r_dfi_cs_n_p0 <= dfi_cs_n_p0;
|
|
|
|
r_dfi_cke_p0 <= dfi_cke_p0;
|
|
|
|
r_dfi_ras_n_p0 <= dfi_ras_n_p0;
|
|
|
|
r_dfi_cas_n_p0 <= dfi_cas_n_p0;
|
|
|
|
r_dfi_we_n_p0 <= dfi_we_n_p0;
|
|
|
|
|
|
|
|
r_dfi_address_p1 <= dfi_address_p1;
|
|
|
|
r_dfi_bank_p1 <= dfi_bank_p1;
|
|
|
|
r_dfi_cs_n_p1 <= dfi_cs_n_p1;
|
|
|
|
r_dfi_cke_p1 <= dfi_cke_p1;
|
|
|
|
r_dfi_ras_n_p1 <= dfi_ras_n_p1;
|
|
|
|
r_dfi_cas_n_p1 <= dfi_cas_n_p1;
|
|
|
|
r_dfi_we_n_p1 <= dfi_we_n_p1;
|
|
|
|
end
|
|
|
|
|
|
|
|
reg [NUM_AD-1:0] r2_dfi_address_p0;
|
|
|
|
reg [NUM_BA-1:0] r2_dfi_bank_p0;
|
|
|
|
reg r2_dfi_cs_n_p0;
|
|
|
|
reg r2_dfi_cke_p0;
|
|
|
|
reg r2_dfi_ras_n_p0;
|
|
|
|
reg r2_dfi_cas_n_p0;
|
|
|
|
reg r2_dfi_we_n_p0;
|
|
|
|
reg [NUM_AD-1:0] r2_dfi_address_p1;
|
|
|
|
reg [NUM_BA-1:0] r2_dfi_bank_p1;
|
|
|
|
reg r2_dfi_cs_n_p1;
|
|
|
|
reg r2_dfi_cke_p1;
|
|
|
|
reg r2_dfi_ras_n_p1;
|
|
|
|
reg r2_dfi_cas_n_p1;
|
|
|
|
reg r2_dfi_we_n_p1;
|
|
|
|
|
2012-02-20 17:55:20 -05:00
|
|
|
always @(posedge clk2x_270) begin
|
2012-02-19 14:49:56 -05:00
|
|
|
r2_dfi_address_p0 <= r_dfi_address_p0;
|
|
|
|
r2_dfi_bank_p0 <= r_dfi_bank_p0;
|
|
|
|
r2_dfi_cs_n_p0 <= r_dfi_cs_n_p0;
|
|
|
|
r2_dfi_cke_p0 <= r_dfi_cke_p0;
|
|
|
|
r2_dfi_ras_n_p0 <= r_dfi_ras_n_p0;
|
|
|
|
r2_dfi_cas_n_p0 <= r_dfi_cas_n_p0;
|
|
|
|
r2_dfi_we_n_p0 <= r_dfi_we_n_p0;
|
|
|
|
|
|
|
|
r2_dfi_address_p1 <= r_dfi_address_p1;
|
|
|
|
r2_dfi_bank_p1 <= r_dfi_bank_p1;
|
|
|
|
r2_dfi_cs_n_p1 <= r_dfi_cs_n_p1;
|
|
|
|
r2_dfi_cke_p1 <= r_dfi_cke_p1;
|
|
|
|
r2_dfi_ras_n_p1 <= r_dfi_ras_n_p1;
|
|
|
|
r2_dfi_cas_n_p1 <= r_dfi_cas_n_p1;
|
|
|
|
r2_dfi_we_n_p1 <= r_dfi_we_n_p1;
|
|
|
|
end
|
|
|
|
|
2012-02-20 17:55:20 -05:00
|
|
|
always @(negedge clk2x_270) begin
|
2012-02-19 14:49:56 -05:00
|
|
|
if(phase_sel) begin
|
|
|
|
sd_a <= r2_dfi_address_p0;
|
|
|
|
sd_ba <= r2_dfi_bank_p0;
|
|
|
|
sd_cs_n <= r2_dfi_cs_n_p0;
|
|
|
|
sd_cke <= r2_dfi_cke_p0;
|
|
|
|
sd_ras_n <= r2_dfi_ras_n_p0;
|
|
|
|
sd_cas_n <= r2_dfi_cas_n_p0;
|
|
|
|
sd_we_n <= r2_dfi_we_n_p0;
|
2012-02-20 17:55:20 -05:00
|
|
|
end else begin
|
|
|
|
sd_a <= r2_dfi_address_p1;
|
|
|
|
sd_ba <= r2_dfi_bank_p1;
|
|
|
|
sd_cs_n <= r2_dfi_cs_n_p1;
|
|
|
|
sd_cke <= r2_dfi_cke_p1;
|
|
|
|
sd_ras_n <= r2_dfi_ras_n_p1;
|
|
|
|
sd_cas_n <= r2_dfi_cas_n_p1;
|
|
|
|
sd_we_n <= r2_dfi_we_n_p1;
|
2012-02-19 14:49:56 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-02-20 07:45:57 -05:00
|
|
|
/*
|
|
|
|
* DQ/DQS/DM data
|
|
|
|
*/
|
|
|
|
|
|
|
|
genvar i;
|
|
|
|
|
2012-02-20 17:55:20 -05:00
|
|
|
wire drive_dqs;
|
2012-02-20 07:45:57 -05:00
|
|
|
wire [NUM_D/16-1:0] dqs_o;
|
|
|
|
wire [NUM_D/16-1:0] dqs_t;
|
2012-02-20 17:55:20 -05:00
|
|
|
reg postamble;
|
2012-02-20 07:45:57 -05:00
|
|
|
generate
|
|
|
|
for(i=0;i<NUM_D/16;i=i+1)
|
|
|
|
begin: gen_dqs
|
|
|
|
ODDR2 #(
|
2012-02-20 10:13:56 -05:00
|
|
|
.DDR_ALIGNMENT("C1"),
|
2012-02-20 07:45:57 -05:00
|
|
|
.INIT(1'b0),
|
|
|
|
.SRTYPE("ASYNC")
|
|
|
|
) dqs_o_oddr (
|
|
|
|
.Q(dqs_o[i]),
|
2012-02-20 17:55:20 -05:00
|
|
|
.C0(clk2x_270),
|
|
|
|
.C1(~clk2x_270),
|
2012-02-20 07:45:57 -05:00
|
|
|
.CE(1'b1),
|
|
|
|
.D0(1'b0),
|
|
|
|
.D1(1'b1),
|
|
|
|
.R(1'b0),
|
|
|
|
.S(1'b0)
|
|
|
|
);
|
|
|
|
ODDR2 #(
|
2012-02-20 10:13:56 -05:00
|
|
|
.DDR_ALIGNMENT("C1"),
|
2012-02-20 07:45:57 -05:00
|
|
|
.INIT(1'b0),
|
|
|
|
.SRTYPE("ASYNC")
|
|
|
|
) dqs_t_oddr (
|
|
|
|
.Q(dqs_t[i]),
|
2012-02-20 17:55:20 -05:00
|
|
|
.C0(clk2x_270),
|
|
|
|
.C1(~clk2x_270),
|
2012-02-20 07:45:57 -05:00
|
|
|
.CE(1'b1),
|
2012-02-20 17:55:20 -05:00
|
|
|
.D0(~(drive_dqs | postamble)),
|
|
|
|
.D1(~drive_dqs),
|
2012-02-20 07:45:57 -05:00
|
|
|
.R(1'b0),
|
|
|
|
.S(1'b0)
|
|
|
|
);
|
|
|
|
OBUFT dqs_obuft(
|
|
|
|
.I(dqs_o[i]),
|
|
|
|
.T(dqs_t[i]),
|
|
|
|
.O(sd_dqs[i])
|
|
|
|
);
|
|
|
|
end
|
|
|
|
endgenerate
|
2012-02-20 17:55:20 -05:00
|
|
|
always @(posedge clk2x_270)
|
|
|
|
postamble <= drive_dqs;
|
2012-02-20 07:45:57 -05:00
|
|
|
|
2012-02-20 17:55:20 -05:00
|
|
|
wire drive_dq;
|
2012-02-20 07:45:57 -05:00
|
|
|
wire [NUM_D/2-1:0] dq_i;
|
|
|
|
wire [NUM_D/2-1:0] dq_o;
|
|
|
|
wire [NUM_D/2-1:0] dq_t;
|
|
|
|
generate
|
|
|
|
for(i=0;i<NUM_D/2;i=i+1)
|
|
|
|
begin: gen_dq
|
|
|
|
OSERDES2 #(
|
|
|
|
.DATA_WIDTH(4),
|
|
|
|
.DATA_RATE_OQ("SDR"),
|
|
|
|
.DATA_RATE_OT("SDR"),
|
|
|
|
.SERDES_MODE("NONE"),
|
|
|
|
.OUTPUT_MODE("SINGLE_ENDED")
|
|
|
|
) dq_oserdes (
|
|
|
|
.OQ(dq_o[i]),
|
|
|
|
.OCE(1'b1),
|
|
|
|
.CLK0(clk4x_wr),
|
|
|
|
.CLK1(1'b0),
|
|
|
|
.IOCE(clk4x_wr_strb),
|
2012-02-20 17:55:20 -05:00
|
|
|
.RST(1'b0),
|
2012-02-20 07:45:57 -05:00
|
|
|
.CLKDIV(sys_clk),
|
2012-02-20 17:55:20 -05:00
|
|
|
.D1(dfi_wrdata_p0[i+NUM_D/2]),
|
|
|
|
.D2(dfi_wrdata_p0[i]),
|
|
|
|
.D3(dfi_wrdata_p1[i+NUM_D/2]),
|
|
|
|
.D4(dfi_wrdata_p1[i]),
|
2012-02-20 07:45:57 -05:00
|
|
|
.TQ(dq_t[i]),
|
2012-02-20 17:55:20 -05:00
|
|
|
.T1(~drive_dq),
|
|
|
|
.T2(~drive_dq),
|
|
|
|
.T3(~drive_dq),
|
|
|
|
.T4(~drive_dq),
|
2012-02-20 07:45:57 -05:00
|
|
|
.TRAIN(1'b0),
|
|
|
|
.TCE(1'b1),
|
|
|
|
.SHIFTIN1(1'b0),
|
|
|
|
.SHIFTIN2(1'b0),
|
|
|
|
.SHIFTIN3(1'b0),
|
|
|
|
.SHIFTIN4(1'b0),
|
|
|
|
.SHIFTOUT1(),
|
|
|
|
.SHIFTOUT2(),
|
|
|
|
.SHIFTOUT3(),
|
|
|
|
.SHIFTOUT4()
|
|
|
|
);
|
|
|
|
ISERDES2 #(
|
|
|
|
.DATA_WIDTH(4),
|
|
|
|
.DATA_RATE("SDR"),
|
|
|
|
.BITSLIP_ENABLE("FALSE"),
|
|
|
|
.SERDES_MODE("NONE"),
|
|
|
|
.INTERFACE_TYPE("RETIMED")
|
|
|
|
) dq_iserdes (
|
|
|
|
.D(dq_i[i]),
|
|
|
|
.CE0(1'b1),
|
|
|
|
.CLK0(clk4x_rd),
|
|
|
|
.CLK1(1'b0),
|
|
|
|
.IOCE(clk4x_rd_strb),
|
2012-02-20 17:55:20 -05:00
|
|
|
.RST(1'b0),
|
2012-02-20 07:45:57 -05:00
|
|
|
.CLKDIV(clk),
|
|
|
|
.SHIFTIN(),
|
|
|
|
.BITSLIP(1'b0),
|
|
|
|
.FABRICOUT(),
|
2012-02-20 17:55:20 -05:00
|
|
|
.Q1(dfi_rddata_w0[i+NUM_D/2]),
|
|
|
|
.Q2(dfi_rddata_w0[i]),
|
|
|
|
.Q3(dfi_rddata_w1[i+NUM_D/2]),
|
|
|
|
.Q4(dfi_rddata_w1[i]),
|
2012-02-20 07:45:57 -05:00
|
|
|
.DFB(),
|
|
|
|
.CFB0(),
|
|
|
|
.CFB1(),
|
|
|
|
.VALID(),
|
|
|
|
.INCDEC(),
|
|
|
|
.SHIFTOUT()
|
|
|
|
);
|
|
|
|
IOBUF dq_iobuf(
|
|
|
|
.I(dq_o[i]),
|
|
|
|
.O(dq_i[i]),
|
|
|
|
.T(dq_t[i]),
|
|
|
|
.IO(sd_dq[i])
|
|
|
|
);
|
|
|
|
end
|
|
|
|
endgenerate
|
|
|
|
|
|
|
|
generate
|
|
|
|
for(i=0;i<NUM_D/16;i=i+1)
|
|
|
|
begin: gen_dm_oserdes
|
|
|
|
OSERDES2 #(
|
|
|
|
.DATA_WIDTH(4),
|
|
|
|
.DATA_RATE_OQ("SDR"),
|
|
|
|
.DATA_RATE_OT("SDR"),
|
|
|
|
.SERDES_MODE("NONE"),
|
|
|
|
.OUTPUT_MODE("SINGLE_ENDED")
|
|
|
|
) dm_oserdes (
|
|
|
|
.OQ(sd_dm[i]),
|
|
|
|
.OCE(1'b1),
|
|
|
|
.CLK0(clk4x_wr),
|
|
|
|
.CLK1(1'b0),
|
|
|
|
.IOCE(clk4x_wr_strb),
|
2012-02-20 17:55:20 -05:00
|
|
|
.RST(1'b0),
|
2012-02-20 07:45:57 -05:00
|
|
|
.CLKDIV(sys_clk),
|
2012-02-20 17:55:20 -05:00
|
|
|
.D1(dfi_wrdata_mask_p0[i+NUM_D/16]),
|
|
|
|
.D2(dfi_wrdata_mask_p0[i]),
|
|
|
|
.D3(dfi_wrdata_mask_p1[i+NUM_D/16]),
|
|
|
|
.D4(dfi_wrdata_mask_p1[i]),
|
2012-02-20 07:45:57 -05:00
|
|
|
.TQ(),
|
|
|
|
.T1(),
|
|
|
|
.T2(),
|
|
|
|
.T3(),
|
|
|
|
.T4(),
|
|
|
|
.TRAIN(1'b0),
|
|
|
|
.TCE(1'b0),
|
|
|
|
.SHIFTIN1(1'b0),
|
|
|
|
.SHIFTIN2(1'b0),
|
|
|
|
.SHIFTIN3(1'b0),
|
|
|
|
.SHIFTIN4(1'b0),
|
|
|
|
.SHIFTOUT1(),
|
|
|
|
.SHIFTOUT2(),
|
|
|
|
.SHIFTOUT3(),
|
|
|
|
.SHIFTOUT4()
|
|
|
|
);
|
|
|
|
end
|
|
|
|
endgenerate
|
2012-02-19 14:49:56 -05:00
|
|
|
|
2012-02-20 07:45:57 -05:00
|
|
|
/*
|
|
|
|
* DQ/DQS/DM control
|
|
|
|
*/
|
|
|
|
|
2012-02-20 10:13:56 -05:00
|
|
|
reg r_dfi_wrdata_en_p0;
|
|
|
|
reg r_dfi_wrdata_en_p1;
|
|
|
|
|
|
|
|
always @(posedge sys_clk) begin
|
|
|
|
r_dfi_wrdata_en_p0 <= dfi_wrdata_en_p0;
|
|
|
|
r_dfi_wrdata_en_p1 <= dfi_wrdata_en_p1;
|
|
|
|
end
|
|
|
|
|
|
|
|
reg r2_dfi_wrdata_en_p0;
|
|
|
|
reg r2_dfi_wrdata_en_p1;
|
|
|
|
|
2012-02-20 17:55:20 -05:00
|
|
|
always @(posedge clk2x_270) begin
|
2012-02-20 10:13:56 -05:00
|
|
|
r2_dfi_wrdata_en_p0 <= r_dfi_wrdata_en_p0;
|
|
|
|
r2_dfi_wrdata_en_p1 <= r_dfi_wrdata_en_p1;
|
|
|
|
end
|
|
|
|
|
2012-02-20 17:55:20 -05:00
|
|
|
assign drive_dqs = r2_dfi_wrdata_en_p0 | r2_dfi_wrdata_en_p1;
|
|
|
|
assign drive_dq = dfi_wrdata_en_p0 | dfi_wrdata_en_p1;
|
2012-02-20 07:45:57 -05:00
|
|
|
|
2012-02-20 10:13:56 -05:00
|
|
|
// TODO: dfi_rddata_valid_w0/1?
|
2012-02-20 07:45:57 -05:00
|
|
|
|
2012-02-19 12:43:42 -05:00
|
|
|
endmodule
|