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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [boards/] [xilinx/] [ml501/] [rtl/] [verilog/] [xilinx_ddr2/] [xilinx_ddr2_if.v] - Rev 412

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  Xilinx DDR2 controller Wishbone Interface                   ////
////                                                              ////
////  Description                                                 ////
////  Simple interface to the Xilinx MIG generated DDR2 controller////
////                                                              ////
////  To Do:                                                      ////
////   Increase usage of cache BRAM to maximum (currently only    ////
////   256 bytes out of about 8192)                               ////
////   Make this a Wishbone B3 registered feedback burst friendly ////
////   server.                                                    ////
////                                                              ////
////  Author(s):                                                  ////
////      - Julius Baxter, julius.baxter@orsoc.se                 ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2010 Authors and OPENCORES.ORG                 ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source 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 Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
/*
 * The controller is design to stream lots of data out at the DDR2 controller's
 * rate. All we implement here is enough to do the simplest accesses into a 
 * small cache, which eases the domain crossing headaches.
 * 
 * This was originally written to handle a DDR2 part which is doing burst length
 * of 4 as a minimum via a databus which is 64-bits wide.
 * 
 * This means the smallest accesses is 4*64=256-bits or 32-bytes.
 * 
 * We are bridging to a 32-bit wide system bus, so this means we must handle
 * accesses in 8-word lots.
 * 
 * A simple cache mechanism has been implemented, meaning we check if the cached
 * data has been written to, and therefore needs writing back to the main memory
 * before any other access can occur.
 * 
 * Cache memory:
 * The cache memory is a core-generated module, instantiating something out
 * of the XilinxCoreLib. The reason is because an arrangement or RAMB36s with
 * different sized A and B data in/out ports can't be instantiated directly
 * for some reason.
 * What we have is side A with 32-bits, and side B with 128-bits wide.
 * 
 * TODO:
 * This only supports 8-words for now but can easily be expanded, although 
 * multiple way/associativity caching will require some extra work to handle
 * multiple cached addresses.
 * 
 * But it should be easy enough to make this thing cache as much as its RAMB
 * resources allow (4-RAMB16s becuase due to the 128-bit DDR2-side interface)
 * which is about 8Kbyte.
 * 
 * Multi-cycle paths:
 * Write:
 * To indicate that a writeback is occuring, a system-bus domain (wishbone, in
 * this case) signal is set, and then sampled in the controller domain whenever
 * a system-bus domain clock edge is detected. This register is "do_writeback"
 * and then the controller domain register "ddr2_write_done" is asserted when
 * the data has been written out of the RAMs and into the controller's fifos.
 * "ddr2_write_done" is then sampled by the system-bus domain and "do_writeback"
 * So there are paths between:
 * ( register -> (sampled by) -> register )
 * wb_clk:do_writeback -> ddr2_clk:do_writeback_ddr2_shifter
 * wb_clk:do_writeback -> ddr2_clk:ddr2_write_done
 * ddr2_clk:ddr2_write_done -> wb_clk:do_writeback
 * 
 * Read:
 * The only signal crossing we have here is the one indicating the read data
 * has arrived into the cache RAM from the controller. The controller domain
 * register "ddr2_read_done" is set, and sampled in the system-bus domain by the
 * logic controlling the "do_readfrom" register. "ddr2_read_done" is cleared
 * when the controller domain sees that "do_readfrom" has been de-asserted.
 * So there are paths between:
 * ( register -> (sampled by) -> register )
 * ddr2_clk:ddr2_read_done -> wb_clk:do_readfrom
 * wb_clk:do_readfrom -> ddr2_clk:ddr2_read_done
 * 
 */
module xilinx_ddr2_if ( 
    input [31:0]       wb_adr_i,
    input 	       wb_stb_i,
    input 	       wb_cyc_i,
    input 	       wb_we_i,
    input [3:0]        wb_sel_i,
    input [31:0]       wb_dat_i,
    output [31:0]      wb_dat_o,
    output reg 	       wb_ack_o,
 
    output [12:0]      ddr2_a,
    output [1:0]       ddr2_ba,
    output 	       ddr2_ras_n,
    output 	       ddr2_cas_n,
    output 	       ddr2_we_n,
    output [1:0]       ddr2_cs_n,
    output [1:0]       ddr2_odt,
    output [1:0]       ddr2_cke,
    output [7:0]       ddr2_dm,
 
    inout [63:0]       ddr2_dq,		  
    inout [7:0]        ddr2_dqs,
    inout [7:0]        ddr2_dqs_n,
    output [1:0]       ddr2_ck,
    output [1:0]       ddr2_ck_n,
 
    input 	       ddr2_if_clk,
    input 	       ddr2_if_rst,
    input 	       idly_clk_200,
    input 	       wb_clk,
    input 	       wb_rst);
 
`include "xilinx_ddr2_params.v"
 
   wire 	       ddr2_clk; // DDR2 iface domain clock.
   wire 	       ddr2_rst; // reset from the ddr2 module
 
   wire 	       wb_req;   
   reg 		       wb_req_r;
   reg 		       wb_ack_o_r;   
 
   wire 	       wb_req_new;
   reg 		       wb_req_new_r;
 
   reg 		       wb_req_addr_hit;
 
   reg 		       cached_addr_valid;
 
   reg [31:6] 	       cached_addr;
 
   wire 	       cache_hit;
 
   reg 		       cache_dirty;
 
   reg [2:0] 	       wb_req_cache_word_addr;
 
   wire 	       wb_cache_en;
 
   reg 		       do_writeback, do_writeback_r;
   wire 	       do_writeback_start, do_writeback_finished;
   wire 	       doing_writeback;
 
   reg 		       do_readfrom, do_readfrom_r;   
   wire 	       do_readfrom_start, do_readfrom_finished;
   wire 	       doing_readfrom;
 
 
   // Domain crossing logic
   reg 		       wb_clk_r;
   reg 		       wb_clk_in_ddr2_clk;
 
   reg 		       wb_clk_in_ddr2_clk_r;
   wire 	       wb_clk_edge;   
   reg [2:0] 	       ddr2_clk_phase;
   // Sample when clk phase is 0
   reg [7:0] 	       do_writeback_ddr2_shifter;
   reg [7:0] 	       do_writeback_ddr2_shifter_r;
   reg 		       do_writeback_ddr2_fifo_we;
   reg 		       ddr2_write_done;   
 
   // Currently, ddr2-side of cache is address is a single bit
   reg [1:0] 	       ddr2_cache_addr;
   wire [127:0]        ddr2_cache_data_o;
   reg 		       rd_data_valid_r;
   reg 		       ddr2_read_done;
 
   // DDR2 MIG interface wires
   wire 	       app_af_afull;
   wire 	       app_wdf_afull;
   wire 	       app_wdf_wren;
   wire 	       app_af_wren;
   wire [30:0] 	       app_af_addr;
   wire [2:0] 	       app_af_cmd;
   wire [(APPDATA_WIDTH)-1:0] app_wdf_data;
   wire [(APPDATA_WIDTH/8)-1:0] app_wdf_mask_data;
   wire 			rd_data_valid;
   wire [(APPDATA_WIDTH)-1:0] 	rd_data_fifo_out;
   wire 			phy_init_done;
 
 
   assign cache_hit = (cached_addr ==  wb_adr_i[31:6]) & cached_addr_valid;
 
   // Wishbone request detection
   assign wb_req = wb_stb_i & wb_cyc_i & phy_init_done; 
 
   always @(posedge wb_clk)
     wb_req_r <= wb_req;
 
   assign wb_req_new = wb_req & !wb_req_r;
 
   always @(posedge wb_clk)
     wb_req_new_r <= wb_req_new;
 
   // Register whether it's a hit or not
   // As more lines are added, add them to this check.
   always @(posedge wb_clk)
     if (wb_rst)
       wb_req_addr_hit <= 0;   
     else 
       wb_req_addr_hit <= wb_req & cache_hit & cached_addr_valid;
 
   always @(posedge wb_clk)
     if (wb_rst)
       wb_ack_o <= 0;
     else
       wb_ack_o <= wb_req_addr_hit & !wb_ack_o & !wb_ack_o_r;
 
   always @(posedge wb_clk)
     wb_ack_o_r <= wb_ack_o;
 
   // Address valid logic
   always @(posedge wb_clk)
     if (wb_rst)
       cached_addr_valid <= 0;
     else if (do_readfrom_finished)
       cached_addr_valid <= 1;
     else if ( do_writeback_finished ) // Data written back, cache not valid
       cached_addr_valid <= 0;
     else if (wb_req & !cache_hit & cached_addr_valid & !cache_dirty)
       // Invalidate cache so a readfrom begins
       cached_addr_valid <= 0;
 
   // Address cacheing
   always @(posedge wb_clk)
     if (wb_rst)
       cached_addr <= 0;
     else if (do_readfrom_start)
       cached_addr <= wb_adr_i[31:6];
 
   // Cache dirty signal
   always @(posedge wb_clk)
     if (wb_rst)
       cache_dirty <= 0;
     else if (wb_req & wb_we_i & wb_req_addr_hit & wb_ack_o)
       cache_dirty <= 1;
     else if (!cached_addr_valid & cache_dirty)
       cache_dirty <= 0;
 
   // Wishbone side of cache enable. Important!
   // 1. Enable on first access, if it's not a write
   // 2. Enable if we've just refreshed the cache
   // 3. Enable on ACK'ing for a write
   assign wb_cache_en = (wb_req_new & !wb_we_i) | do_readfrom_finished | 
			(wb_req_addr_hit & wb_stb_i & !wb_we_i & !wb_ack_o) |
			(wb_ack_o & wb_we_i);
 
   // Writeback detect logic
   always @(posedge wb_clk)
     if (wb_rst)
       do_writeback <= 0;
     else if (ddr2_write_done) // DDR2 domain signal
       do_writeback <= 0;
     else if (wb_req & !cache_hit & cached_addr_valid & !doing_writeback & cache_dirty)
       do_writeback <= 1;
 
 
   always @(posedge wb_clk)
     do_writeback_r <= do_writeback;
 
   assign do_writeback_start = do_writeback & !do_writeback_r;
   assign do_writeback_finished = !do_writeback & do_writeback_r;
   assign doing_writeback = do_writeback | do_writeback_r;
 
   // DDR2 Read detect logic
   always @(posedge wb_clk)
     if (wb_rst)
       do_readfrom <= 0;
     else if (ddr2_read_done) // DDR2 domain signal
       do_readfrom <= 0;
     else if (wb_req & !cache_hit & !cached_addr_valid & !doing_readfrom & !cache_dirty)
       do_readfrom <= 1;
 
   always @(posedge wb_clk)
     do_readfrom_r <= do_readfrom;
 
   assign do_readfrom_start = do_readfrom & !do_readfrom_r;
   assign do_readfrom_finished = !do_readfrom & do_readfrom_r;
   assign doing_readfrom = do_readfrom | do_readfrom_r;   
 
   // Address fifo signals
   assign app_af_wren = (do_writeback_finished | do_readfrom_start);
   assign app_af_cmd[0] = do_readfrom_start; // 1 - read, 0 - write
   assign app_af_cmd[2:1] = 0;
   assign app_af_addr = do_readfrom_start ?  {2'd0, wb_adr_i[31:6],3'd0} :
			{2'd0,cached_addr,3'd0};
 
   assign app_wdf_wren = do_writeback_ddr2_fifo_we;
   assign app_wdf_data = ddr2_cache_data_o;
   assign app_wdf_mask_data = 0;   
 
   always @(posedge wb_clk) if (wb_rst) wb_clk_r <= 0; else wb_clk_r <= ~wb_clk_r;
   always @(posedge ddr2_clk) wb_clk_in_ddr2_clk <= wb_clk_r;
   always @(posedge ddr2_clk) wb_clk_in_ddr2_clk_r <= wb_clk_in_ddr2_clk;
 
   assign wb_clk_edge = wb_clk_in_ddr2_clk & !wb_clk_in_ddr2_clk_r;
 
   always @(posedge ddr2_clk)
     if (ddr2_rst)
       ddr2_clk_phase <= 0;
     else if (wb_clk_edge)
       ddr2_clk_phase <= 0;
     else
       ddr2_clk_phase <= ddr2_clk_phase + 1;
 
   always @(posedge ddr2_clk)
     do_writeback_ddr2_fifo_we <= (do_writeback_ddr2_shifter_r[0]) | 
 				  (do_writeback_ddr2_shifter_r[2]) |
				  (do_writeback_ddr2_shifter_r[4]) |
				  (do_writeback_ddr2_shifter_r[6]);
 
   // Kick off counting when we see that the wb_clk domain is
   // doing a writeback.
   always @(posedge ddr2_clk)
     if (ddr2_rst)
       do_writeback_ddr2_shifter <= 4'h0;
     else if  (|do_writeback_ddr2_shifter)
       do_writeback_ddr2_shifter <= {do_writeback_ddr2_shifter[6:0], 1'b0};
     else if (!(|ddr2_clk_phase) & do_writeback & !ddr2_write_done) // sample WB domain
       do_writeback_ddr2_shifter <= 1;
 
 
 
   always @(posedge ddr2_clk)
     do_writeback_ddr2_shifter_r <= do_writeback_ddr2_shifter;
 
   always @(posedge ddr2_clk)
     if (ddr2_rst)
       ddr2_write_done <= 0;
     else if (do_writeback_ddr2_shifter[7])
       ddr2_write_done <= 1;
     else if ((!(|ddr2_clk_phase)) & !do_writeback) // sample WB domain
       ddr2_write_done <= 0;
 
   always @(posedge ddr2_clk)
     if (ddr2_rst)
       ddr2_cache_addr <= 0;
     else if (rd_data_valid | do_writeback_ddr2_fifo_we)
       ddr2_cache_addr <= ddr2_cache_addr + 1;
 
   always @(posedge ddr2_clk)
     rd_data_valid_r <= rd_data_valid;
 
   // Read done signaling to WB domain
   always @(posedge ddr2_clk)
     if (ddr2_rst)
       ddr2_read_done <= 0;
     else if (!rd_data_valid & rd_data_valid_r) // Detect read data valid falling edge
       ddr2_read_done <= 1;
     else if (!(|ddr2_clk_phase) & !do_readfrom) // Read WB domain
       ddr2_read_done <= 0;
 
   wire [3:0] 			wb_cache_adr;
   assign wb_cache_adr = wb_adr_i[5:2];   
   wire [3:0] 			wb_cache_sel_we;   
   assign wb_cache_sel_we = {4{wb_we_i}} & wb_sel_i;
   wire 			ddr2_cache_en;
   wire [15:0] 			ddr2_cache_we;
   assign ddr2_cache_en = rd_data_valid | (|do_writeback_ddr2_shifter);   
   assign ddr2_cache_we = {16{rd_data_valid}};
 
 
   // Xilinx Coregen true dual-port RAMB array.
   // Wishbone side : 32-bit
   // DDR2 side : 128-bit
   xilinx_ddr2_if_cache cache_mem0
     (
      // Wishbone side
      .clka(wb_clk),
      .ena(wb_cache_en),
      .wea(wb_cache_sel_we),
      .addra({8'd0,wb_cache_adr}),
      .dina(wb_dat_i),
      .douta(wb_dat_o),
 
      // DDR2 controller side
      .clkb(ddr2_clk),
      .enb(ddr2_cache_en),
      .web(ddr2_cache_we),
      .addrb({8'd0,ddr2_cache_addr}),
      .dinb(rd_data_fifo_out),
      .doutb(ddr2_cache_data_o));
 
   ddr2_mig #
     (
      .BANK_WIDTH            (BANK_WIDTH),
      .CKE_WIDTH             (CKE_WIDTH),
      .CLK_WIDTH             (CLK_WIDTH),
      .COL_WIDTH             (COL_WIDTH),
      .CS_NUM                (CS_NUM),
      .CS_WIDTH              (CS_WIDTH),
      .CS_BITS               (CS_BITS),
      .DM_WIDTH              (DM_WIDTH),
      .DQ_WIDTH              (DQ_WIDTH),
      .DQ_PER_DQS            (DQ_PER_DQS),
      .DQ_BITS               (DQ_BITS),
      .DQS_WIDTH             (DQS_WIDTH),
      .DQS_BITS              (DQS_BITS),
      .HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE),
      .ODT_WIDTH             (ODT_WIDTH),
      .ROW_WIDTH             (ROW_WIDTH),
      .APPDATA_WIDTH         (APPDATA_WIDTH),
      .ADDITIVE_LAT          (ADDITIVE_LAT),
      .BURST_LEN             (BURST_LEN),
      .BURST_TYPE            (BURST_TYPE),
      .CAS_LAT               (CAS_LAT),
      .ECC_ENABLE            (ECC_ENABLE),
      .MULTI_BANK_EN         (MULTI_BANK_EN),
      .ODT_TYPE              (ODT_TYPE),
      .REDUCE_DRV            (REDUCE_DRV),
      .REG_ENABLE            (REG_ENABLE),
      .TREFI_NS              (TREFI_NS),
      .TRAS                  (TRAS),
      .TRCD                  (TRCD),
      .TRFC                  (TRFC),
      .TRP                   (TRP),
      .TRTP                  (TRTP),
      .TWR                   (TWR),
      .TWTR                  (TWTR),
      .SIM_ONLY              (SIM_ONLY),
      .RST_ACT_LOW           (RST_ACT_LOW),
      .CLK_TYPE              (CLK_TYPE),
      .DLL_FREQ_MODE         (DLL_FREQ_MODE),
      .CLK_PERIOD            (CLK_PERIOD)
      )
   ddr2_mig0
     (
      .sys_clk           (ddr2_if_clk),
      .idly_clk_200      (idly_clk_200),
      .sys_rst_n         (ddr2_if_rst), // Act. high, sync. to ddr2_if_clk
      .ddr2_ras_n        (ddr2_ras_n),
      .ddr2_cas_n        (ddr2_cas_n),
      .ddr2_we_n         (ddr2_we_n),
      .ddr2_cs_n         (ddr2_cs_n),
      .ddr2_cke          (ddr2_cke),
      .ddr2_odt          (ddr2_odt),
      .ddr2_dm           (ddr2_dm),
      .ddr2_dq           (ddr2_dq),
      .ddr2_dqs          (ddr2_dqs),
      .ddr2_dqs_n        (ddr2_dqs_n),
      .ddr2_ck           (ddr2_ck),
      .ddr2_ck_n         (ddr2_ck_n),
      .ddr2_ba           (ddr2_ba),
      .ddr2_a            (ddr2_a),
 
      .clk0_tb           (ddr2_clk),
      .rst0_tb           (ddr2_rst),
      .usr_clk           (wb_clk),
      .app_af_afull      (app_af_afull),
      .app_wdf_afull     (app_wdf_afull),
      .rd_data_valid     (rd_data_valid),
      .rd_data_fifo_out  (rd_data_fifo_out),
      .app_af_wren       (app_af_wren),
      .app_af_cmd        (app_af_cmd),
      .app_af_addr       (app_af_addr),
      .app_wdf_wren      (app_wdf_wren),
      .app_wdf_data      (app_wdf_data),
      .app_wdf_mask_data (app_wdf_mask_data),
      .phy_init_done     (phy_init_done)
      );
 
 
endmodule // ml501_ddr2_if
// Local Variables:
// verilog-library-directories:("." "ddr2_mig")
// verilog-library-extensions:(".v" ".h")
// End:
 

Go to most recent revision | 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.