OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [boards/] [actel/] [ordb1a3pe1500/] [rtl/] [verilog/] [versatile_mem_ctrl/] [rtl/] [verilog/] [versatile_mem_ctrl_ddr.v] - Rev 408

Compare with Previous | Blame | View Log

module versatile_mem_ctrl_ddr (
  // DDR2 SDRAM side
  ck_o, ck_n_o, 
  dq_io, dqs_io, dqs_n_io, 
  dm_rdqs_io,
  //rdqs_n_i, odt_o, 
  // Memory controller side
  tx_dat_i, rx_dat_o,
  dq_en, dqm_en,
  rst, clk_0, clk_90, clk_180, clk_270
  );
 
  output        ck_o;
  output        ck_n_o;
  inout  [15:0] dq_io;
  inout   [1:0] dqs_io;
  inout   [1:0] dqs_n_io;
  inout   [1:0] dm_rdqs_io;
  //input   [1:0] rdqs_n_i;
  //output        odt_o;
  input  [35:0] tx_dat_i;
  output [31:0] rx_dat_o;
  input         dq_en;
  input         dqm_en;
  input         rst;
  input         clk_0;
  input         clk_90;
  input         clk_180;
  input         clk_270;
 
  reg    [31:0] dq_rx_reg;
  wire   [31:0] dq_rx;
  wire    [1:0] dqs_o, dqs_n_o, dqm_o;
  wire   [15:0] dq_o;
  wire    [1:0] dqs_delayed, dqs_n_delayed;
 
  wire   [15:0] dq_iobuf;
  wire    [1:0] dqs_iobuf, dqs_n_iobuf;
 
  genvar        i;
 
///////////////////////////////////////////////////////////////////////////////
// Common for both Xilinx and Altera
///////////////////////////////////////////////////////////////////////////////
 
  // Generate clock with equal delay as data
  ddr_ff_out ddr_ff_out_ck (
    .Q(ck_o),
    .C0(clk_0),
    .C1(clk_180),
    .CE(1'b1),
    .D0(1'b1),
    .D1(1'b0),
    .R(1'b0),
    .S(1'b0));
 
  ddr_ff_out ddr_ff_out_ck_n (
    .Q(ck_n_o),
    .C0(clk_0),
    .C1(clk_180),
    .CE(1'b1),
    .D0(1'b0),
    .D1(1'b1),
    .R(wb_rst),
    .S(1'b0));
 
  // Generate strobe with equal delay as data
  generate
    for (i=0; i<2; i=i+1) begin:dqs_oddr
      ddr_ff_out ddr_ff_out_dqs (
        .Q(dqs_o[i]),
        .C0(clk_0),
        .C1(clk_180),
        .CE(1'b1),
        .D0(1'b1),
        .D1(1'b0),
        .R(1'b0),
        .S(1'b0));
    end
  endgenerate
 
  generate
    for (i=0; i<2; i=i+1) begin:dqs_n_oddr
      ddr_ff_out ddr_ff_out_dqs_n (
        .Q(dqs_n_o[i]),
        .C0(clk_0),
        .C1(clk_180),
        .CE(1'b1),
        .D0(1'b0),
        .D1(1'b1),
        .R(wb_rst),
        .S(1'b0));
    end
  endgenerate
 
 
 
///////////////////////////////////////////////////////////////////////////////
// Xilinx
///////////////////////////////////////////////////////////////////////////////
 
`ifdef XILINX   
 
  reg  [15:0] dq_tx_reg;
  wire [15:0] dq_tx;
  reg   [3:0] dqm_tx_reg;
  wire  [3:0] dqm_tx;
 
  // IO BUFFER
  // DDR data to/from DDR2 SDRAM
  generate
    for (i=0; i<16; i=i+1) begin:iobuf_dq
      IOBUF u_iobuf_dq (
        .I(dq_o[i]),
        .T(!dq_en),
        .IO(dq_io[i]),
        .O(dq_iobuf[i]));
    end
  endgenerate
 
  // DQS strobe to/from DDR2 SDRAM
  generate
    for (i=0; i<2; i=i+1) begin:iobuf_dqs
      IOBUF u_iobuf_dqs (
        .I(dqs_o[i]),
        .T(!dq_en),
        .IO(dqs_io[i]),
        .O(dqs_iobuf[i]));
    end
  endgenerate
 
  // DQS strobe to/from DDR2 SDRAM
  generate
    for (i=0; i<2; i=i+1) begin:iobuf_dqs_n
      IOBUF u_iobuf_dqs_n (
        .I(dqs_n_o[i]),
        .T(!dq_en),
        .IO(dqs_n_io[i]),
        .O(dqs_n_iobuf[i]));
    end
  endgenerate
 
 
  // Data from Tx FIFO
  always @ (posedge clk_270 or posedge wb_rst)
    if (wb_rst)
      dq_tx_reg[15:0] <= 16'h0;
    else
      if (dqm_en)
        dq_tx_reg[15:0] <= tx_dat_i[19:4];
      else
        dq_tx_reg[15:0] <= tx_dat_i[19:4];
 
  assign dq_tx[15:0] = tx_dat_i[35:20];
 
  // Output Data DDR flip-flops
  generate
    for (i=0; i<16; i=i+1) begin:data_out_oddr
      ddr_ff_out ddr_ff_out_inst_0 (
        .Q(dq_o[i]),
        .C0(clk_270),
        .C1(clk_90),
        .CE(dq_en),
        .D0(dq_tx[i]),
        .D1(dq_tx_reg[i]),
        .R(wb_rst),
        .S(1'b0));
    end
  endgenerate
 
  // Data mask from Tx FIFO
  always @ (posedge clk_270 or posedge wb_rst)
    if (wb_rst)
      dqm_tx_reg[1:0] <= 2'b00;
    else
      if (dqm_en)
        dqm_tx_reg[1:0] <= 2'b00;
      else
        dqm_tx_reg[1:0] <= tx_dat_i[1:0];
 
  always @ (posedge clk_180 or posedge wb_rst)
    if (wb_rst)
      dqm_tx_reg[3:2] <= 2'b00;
    else
      if (dqm_en)
        dqm_tx_reg[3:2] <= 2'b00;
      else
        dqm_tx_reg[3:2] <= tx_dat_i[3:2];
 
  assign dqm_tx[1:0] = (dqm_en) ? 2'b00 : tx_dat_i[3:2];
 
  // Mask output DDR flip-flops
  generate
    for (i=0; i<2; i=i+1) begin:data_mask_oddr
      ddr_ff_out ddr_ff_out_inst_1 (
        .Q(dqm_o[i]),
        .C0(clk_270),
        .C1(clk_90),
        .CE(dq_en),
        .D0(!dqm_tx[i]),
        .D1(!dqm_tx_reg[i]),
        .R(wb_rst),
        .S(1'b0));
    end
  endgenerate
 
  // Data mask to DDR2 SDRAM
  generate
    for (i=0; i<2; i=i+1) begin:iobuf_dqm
      IOBUF u_iobuf_dqm (
        .I(dqm_o[i]),
        .T(!dq_en),
        .IO(dm_rdqs_io[i]),
        .O());
    end
  endgenerate
 
 
`ifdef INT_CLOCKED_DATA_CAPTURE
  // Data in
  // DDR flip-flops
  generate
    for (i=0; i<16; i=i+1) begin:iddr2gen
      ddr_ff_in ddr_ff_in_inst_0 (
        .Q0(dq_rx[i]), 
        .Q1(dq_rx[i+16]), 
        .C0(clk_270), 
        .C1(clk_90),
        .CE(1'b1), 
        .D(dq_io[i]),   
        .R(wb_rst),  
        .S(1'b0));
    end
  endgenerate
 
  // Data to Rx FIFO
  always @ (posedge clk_0 or posedge wb_rst)
    if (wb_rst)
      dq_rx_reg[31:16] <= 16'h0;
    else
      dq_rx_reg[31:16] <= dq_rx[31:16];
 
  always @ (posedge clk_180 or posedge wb_rst)
    if (wb_rst)
      dq_rx_reg[15:0] <= 16'h0;
    else
      dq_rx_reg[15:0] <= dq_rx[15:0];
 
  assign rx_dat_o = dq_rx_reg;
`endif   // INT_CLOCKED_DATA_CAPTURE
 
 
`ifdef DEL_DQS_DATA_CAPTURE_1
 
  wire  [1:0] dqs_iodelay, dqs_n_iodelay;
 
  // Delay DQS
  assign # 2 dqs_iodelay   = dqs_iobuf;
  assign # 2 dqs_n_iodelay = dqs_n_iobuf;
 
  // IDDR FF
  generate
    for (i=0; i<16; i=i+1) begin:iddr_dq
      ddr_ff_in ddr_ff_in_inst_0 (
        .Q0(dq_rx[i]), 
        .Q1(dq_rx[i+16]), 
        .C0(dqs_iodelay[0]), 
        .C1(dqs_n_iodelay[0]), 
        .CE(1'b1), 
        .D(dq_iobuf[i]),
        .R(wb_rst),  
        .S(1'b0));
    end
  endgenerate
 
  // Data to Rx FIFO
  always @ (posedge clk_0 or posedge wb_rst)
    if (wb_rst)
      dq_rx_reg[31:16] <= 16'h0;
    else
      dq_rx_reg[31:16] <= dq_rx[31:16];
 
  always @ (posedge clk_0 or posedge wb_rst)
    if (wb_rst)
      dq_rx_reg[15:0] <= 16'h0;
    else
      dq_rx_reg[15:0] <= dq_rx[15:0];
 
  assign rx_dat_o = dq_rx_reg;
 
`endif   // DEL_DQS_DATA_CAPTURE_1
 
 
`ifdef DEL_DQS_DATA_CAPTURE_2
 
  wire [15:0] dq_iodelay;
  wire  [1:0] dqs_iodelay, dqs_n_iodelay;
  wire [15:0] dq_iddr_fall, dq_iddr_rise;
  reg  [15:0] dq_fall_1, dq_rise_1;
  reg  [15:0] dq_fall_2, dq_rise_2;
  reg  [15:0] dq_fall_3, dq_rise_3;
 
 
  // Delay data
  // IODELAY is available in the Xilinx Virtex FPGAs
  /*IODELAY # (
    .DELAY_SRC(),
    .IDELAY_TYPE(),
    .HIGH_PERFORMANCE_MODE(),
    .IDELAY_VALUE(),
    .ODELAY_VALUE())
   u_idelay_dq (
      .DATAOUT(),
      .C(),
      .CE(),
      .DATAIN(),
      .IDATAIN(),
      .INC(),
      .ODATAIN(),
      .RST(),
      .T());*/
  // IODELAY is NOT available in the Xilinx Spartan FPGAs, 
  // equivalent delay can be implemented using a chain of LUT
  /*lut_delay lut_delay_dq (
    .clk_i(),
    .d_i(dq_iobuf),
    .d_o(dq_iodelay));*/
 
  // IDDR FF
  generate
    for (i=0; i<16; i=i+1) begin:iddr_dq
      ddr_ff_in ddr_ff_in_inst_0 (
        .Q0(dq_iddr_fall[i]), 
        .Q1(dq_iddr_rise[i]), 
        .C0(dqs_iodelay[0]), 
        .C1(dqs_n_iodelay[0]),
        .CE(1'b1), 
        .D(dq_iobuf[i]),
        .R(wb_rst),  
        .S(1'b0));
    end
  endgenerate
 
  // Rise & fall clocked FF
  always @ (posedge clk_0 or posedge wb_rst)
    if (wb_rst) begin
      dq_fall_1 <= 16'h0;
      dq_rise_1 <= 16'h0;
    end else begin
      dq_fall_1 <= dq_iddr_fall;
      dq_rise_1 <= dq_iddr_rise;
    end
 
  always @ (posedge clk_180 or posedge wb_rst)
    if (wb_rst) begin
      dq_fall_2 <= 16'h0;
      dq_rise_2 <= 16'h0;
    end else begin
      dq_fall_2 <= dq_iddr_fall;
      dq_rise_2 <= dq_iddr_rise;
    end
 
  // Fall sync FF
  always @ (posedge clk_0 or posedge wb_rst)
    if (wb_rst) begin
      dq_fall_3 <= 16'h0;
      dq_rise_3 <= 16'h0;
    end else begin
      dq_fall_3 <= dq_fall_2;
      dq_rise_3 <= dq_rise_2;
    end
 
  // Mux
  assign rx_dat_o[31:16] = dq_fall_1;
  assign rx_dat_o[15:0]  = dq_rise_1;
 
  // DDR DQS to IODUFDS
  // Delay DQS
  // IODELAY is NOT available in the Xilinx Spartan FPGAs, 
  // equivalent delay can be implemented using a chain of LUTs
/*
  generate
    for (i=0; i<2; i=i+1) begin:lut_delay_dqs
      lut_delay lut_delay_dqs (
        .d_i(dqs_iobuf[i]),
        .d_o(dqs_iodelay[i]));
    end
  endgenerate
  generate
    for (i=0; i<2; i=i+1) begin:lut_delay_dqs_n
      lut_delay lut_delay_dqs_n (
        .d_i(dqs_n_iobuf[i]),
        .d_o(dqs_n_iodelay[i]));
    end
  endgenerate
*/
 
  assign # 2 dqs_iodelay   = dqs_iobuf;
  assign # 2 dqs_n_iodelay = dqs_n_iobuf;
 
 
  // BUFIO (?)
`endif   // DEL_DQS_DATA_CAPTURE_2
 
`endif   // XILINX
 
 
///////////////////////////////////////////////////////////////////////////////
// Altera
///////////////////////////////////////////////////////////////////////////////
 
`ifdef ALTERA
 
  wire  [3:0] dqm_tx;
 
  // Data out
  // DDR flip-flops
  generate
    for (i=0; i<16; i=i+1) begin:data_out_oddr
      ddr_ff_out ddr_ff_out_inst_0 (
        .Q(dq_o[i]),
        .C0(clk_270),
        .C1(clk_90),
        .CE(dq_en),
        .D0(tx_dat_i[i+16+4]),
        .D1(tx_dat_i[i+4]),
        .R(wb_rst),
        .S(1'b0));
    end
  endgenerate
 
  // Assign outport
  assign dq_io = dq_en ? dq_o : {16{1'bz}};
 
  // Data mask
  // Data mask from Tx FIFO
  assign dqm_tx = dqm_en ? {4{1'b0}} : tx_dat_i[3:0];
 
  // DDR flip-flops
  generate
    for (i=0; i<2; i=i+1) begin:data_mask_oddr
      ddr_ff_out ddr_ff_out_inst_1 (
        .Q(dqm_o[i]),
        .C0(clk_270),
        .C1(clk_90),
        .CE(dq_en),
        .D0(!dqm_tx[i+2]),
        .D1(!dqm_tx[i]),
        .R(wb_rst),
        .S(1'b0));
    end
  endgenerate
 
  // Assign outport
  assign dm_rdqs_io = dq_en ? dqm_o : 2'bzz;
 
 
  // Data in
`ifdef INT_CLOCKED_DATA_CAPTURE
  // DDR flip-flops
  generate
    for (i=0; i<16; i=i+1) begin:iddr2gen
      ddr_ff_in ddr_ff_in_inst_0 (
        .Q0(dq_rx[i]), 
        .Q1(dq_rx[i+16]), 
        .C0(clk_270), 
        .C1(clk_90),
        .CE(1'b1), 
        .D(dq_io[i]),   
        .R(wb_rst),  
        .S(1'b0));
    end
  endgenerate
 
  // Data to Rx FIFO
  always @ (posedge clk_180 or posedge wb_rst)
    if (wb_rst)
      dq_rx_reg <= 32'h0;
    else
      dq_rx_reg <= dq_rx;
 
  assign rx_dat_o = dq_rx_reg;
`endif   // INT_CLOCKED_DATA_CAPTURE
 
`ifdef DEL_DQS_DATA_CAPTURE_1
   // Delay DQS
   // DDR FF
`endif   // DEL_DQS_DATA_CAPTURE_1
 
`ifdef DEL_DQS_DATA_CAPTURE_2
   // DDR data to IOBUFFER
   // Delay data (?)
   // DDR FF
   // Rise & fall clocked FF
   // Fall sync FF
   // Mux
   // DDR DQS to IODUFDS
   // Delay DQS
   // BUFIO (?)
`endif   // DEL_DQS_DATA_CAPTURE_2
 
`endif   // ALTERA
 
 
endmodule   // versatile_mem_ctrl_ddr
 
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.