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

Subversion Repositories openrisc

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

Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  Xilinx Spartan-6 DDR2 controller Wishbone Interface         ////
////                                                              ////
////  Description                                                 ////
////  Simple interface to the Xilinx MIG generated DDR2 controller////
////                                                              ////
////  To Do:                                                      ////
////   Use full capacity of BRAM                                  ////
////   Employ LRU replacement scheme                              ////
////   Remove hard-coding of things relating to number of lines   ////
////                                                              ////
////  Author(s):                                                  ////
////      - Julius Baxter, julius.baxter@orsoc.se                 ////
////      - Stefan Kristiansson, stefan.kristiansson@saunalahti.fi////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// 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                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
/*
 * This is an interface to the Xilinx MIG-sourced DDR2 controller.
 *
 * The interface is based on the ML501 Virtex-5 board implementation
 * with the following adaptions to suite the Atlys Spartan-6 MIG and 
 * DDR2 memory chip:
 * - Control and data FIFOs are clocked with the Wishbone bus clock
 *   and not the DDR2 clock.
 *   This way alot of clock domain crossing headaches can be avoided
 *   (Virtex-5 MIG demands control and data FIFOs clocks to be
 *   synchronous with the DDR2 clock, Spartan-6 have FIFOs that 
 *   are asynchronous to the DDR2 clock) 
 * - The Atlys board have a DDR2 memory with a 16-bit data bus
 *   apposed to the ML501 64-bit databus. This in combination
 *   with changes in the MIG causes the addressing scheme to be a
 *   bit different. A user port of 128-bit is being used, so
 *   we are doing memory accesses on 128-bit boundaries 
 *   (4 address bits). 
 * 
 * See the Xilinx user guide UG388.pdf for more information on the
 * Spartan-6 FPGA memory controller
 * 
 *  
 * The controller's interface is via FIFO buffers - one for address and control
 * the other is for data. The data FIFO interface is 128-bits wide. 
 * 
 * This module has a cache with different aspects on each port. As we're to 
 * ultimately interface to a 32-bit wide Wishbone bus, one side is 32-bits
 * and the other is 128-bits wide to accommodate the DDR2 controller's data
 * path.
 * 
 * At present, the cache controller doesn't employ associativity, so any
 * line can be used for any location. A round-robin approach to line 
 * use is employed. TODO is LRU scheme instead of round robin.
 * 
 * The cache is a macro generated by Xilinx's IP generation tool. This is 
 * because memories with dual-aspect ratios cannot be inferred via HDL.
 * 
 * The size of lines, as set by the defines, controls how long each read
 * and write burst to/from the SDRAM is.
 * 
 * The control and data FIFOS of the DDR2 interface are asynchronous to the DDR2 bus,
 * so they are clocked with the same clock as the Wisbone interface (i.e. wb_clk)
*/
module xilinx_ddr2_if (
    input [31:0]       wb_adr_i,
    input 	       wb_stb_i,
    input 	       wb_cyc_i,
    input [2:0]        wb_cti_i,
    input [1:0]        wb_bte_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 [2:0]       ddr2_ba,
    output 	       ddr2_ras_n,
    output 	       ddr2_cas_n,
    output 	       ddr2_we_n,
    output             ddr2_rzq,
    output             ddr2_zio,
    output             ddr2_odt,
    output             ddr2_cke,
    output             ddr2_dm,
    output             ddr2_udm,
 
    inout [15:0]       ddr2_dq,		  
    inout              ddr2_dqs,
    inout              ddr2_dqs_n,
    inout              ddr2_udqs,
    inout              ddr2_udqs_n,
    output             ddr2_ck,
    output             ddr2_ck_n,
 
    input 	       ddr2_if_clk,
    input 	       ddr2_if_rst,
    input 	       idly_clk_100,
    input 	       wb_clk,
    input 	       wb_rst);
 
`include "xilinx_ddr2_params.v"
 
   // Define to add a counter, signaling error if the controller locks up
   // (no ack after a certain period of time)
   //`define ERR_COUNTER
 
/*
`define DDR2_CACHE_NUM_LINES 16
`define DDR2_CACHE_NUM_LINES_ENC_WIDTH 4 // log2(`DDR2_CACHE_NUM_LINES)
 */
`define DDR2_CACHE_NUM_LINES 4
`define DDR2_CACHE_NUM_LINES_ENC_WIDTH 2 // log2(`DDR2_CACHE_NUM_LINES)
 
`define DDR2_CACHE_NUM_WORDS_PER_LINE 256
`define DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE 8
`define DDR2_CACHE_TAG_ADDR_WIDTH (32-`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE-2)
 
`define DDR2_CACHE_DDR2_SIDE_NUM_WORDS_PER_LINE (`DDR2_CACHE_NUM_WORDS_PER_LINE/4)
`define DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE (`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE - 2)
`define DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH (`DDR2_CACHE_NUM_LINES_ENC_WIDTH + `DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE)
 
`define DDR2_CACHE_TAG_BITS 31:(`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE+2)
 
   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;
 
   wire 	       wb_req_addr_hit;
 
   wire 	       cached_addr_valid;
 
 
   wire [31:(32 -`DDR2_CACHE_TAG_ADDR_WIDTH)] cached_addr;
 
// Spartan-6 MIG doesn't have any defines for the DDR2 burst length, 
// only burst length for user data.
// Our user port is 128-bit
//`define DDR2_BURSTLENGTH_1
//`define DDR2_BURSTLENGTH_2
//`define DDR2_BURSTLENGTH_4
//`define DDR2_BURSTLENGTH_8
`define DDR2_BURSTLENGTH_16
 
`ifdef DDR2_BURSTLENGTH_1
  `define DDR2_BURST_DW128_ADDR_WIDTH 2 // = log2(burst of 1 128-bits = 4 words)
  `define DDR2_ADDR_ALIGN             4
`elsif DDR2_BURSTLENGTH_2
  `define DDR2_BURST_DW128_ADDR_WIDTH 3 // = log2(burst of 2 128-bits = 8 words)
  `define DDR2_ADDR_ALIGN             5
`elsif DDR2_BURSTLENGTH_4
  `define DDR2_BURST_DW128_ADDR_WIDTH 4 // = log2(burst of 4 128-bits = 16 words)
  `define DDR2_ADDR_ALIGN             6
`elsif DDR2_BURSTLENGTH_8
  `define DDR2_BURST_DW128_ADDR_WIDTH 5 // = log2(burst of 8 128-bits = 32 words)
  `define DDR2_ADDR_ALIGN             7
`elsif DDR2_BURSTLENGTH_16
  `define DDR2_BURST_DW128_ADDR_WIDTH 6 // = log2(burst of 16 128-bits = 64 words)
  `define DDR2_ADDR_ALIGN             8
`endif
 
   // This counts how many addresses we should write to the fifo - the number 
   // of discrete FIFO transactions.
   reg [`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE-`DDR2_BURST_DW128_ADDR_WIDTH - 1:0] addr_counter;
 
   wire 	       cache_write;
 
   wire 	       cache_hit;
 
   wire 	       wb_cache_en;
 
   reg 		       do_writeback, do_writeback_r;
   wire 	       do_writeback_start, do_writeback_finished;
   // Wire to indicate writing to data FIFO of MIG has completed
   reg   	       do_writeback_data_finished;
 
   // Wire to indicate that address FIFO of MIG should be written to to 
   // initiate memory accesses.
   reg 		       do_writeback_addresses, do_writeback_addresses_r;
 
   reg 		       do_readfrom, do_readfrom_r;   
   wire 	       do_readfrom_start, do_readfrom_finished;
   wire 	       doing_readfrom;
 
   reg 		       do_af_write;   
 
   reg		       do_writeback_ddr2_fifo_we;
   reg 		       ddr2_write_done;   
   reg [`DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE - 1:0] ddr2_cache_line_word_addr;   
   wire [127:0]        ddr2_cache_data_o;
   reg 		       rd_data_valid_r;
   reg 		       ddr2_read_done;
 
   // DDR2 MIG interface wires
   wire 	       ddr2_p0_cmd_en;
   wire [30:0]         ddr2_p0_cmd_byte_addr;
   wire [2:0] 	       ddr2_p0_cmd_instr;
   wire 	       ddr2_p0_cmd_full;
   wire                ddr2_p0_cmd_empty;
   wire [5:0]          ddr2_p0_cmd_bl;
   wire 	       ddr2_p0_wr_en;
   wire [(C3_P0_DATA_PORT_SIZE)-1:0] ddr2_p0_wr_data;
   wire [(C3_P0_MASK_SIZE)-1:0]      ddr2_p0_wr_mask;
   wire 	       ddr2_p0_wr_full;
   wire                ddr2_p0_wr_empty;
   wire [6:0]          ddr2_p0_wr_count;
   wire                ddr2_p0_wr_underrun;
   wire                ddr2_p0_wr_error;
   wire                ddr2_p0_rd_en;
   wire [(C3_P0_DATA_PORT_SIZE)-1:0] ddr2_p0_rd_data;
   wire                ddr2_p0_rd_full;
   wire                ddr2_p0_rd_empty;
   wire [6:0]          ddr2_p0_rd_count;
   wire                ddr2_p0_rd_overflow;
   wire                ddr2_p0_rd_error;
   wire 	       ddr2_calib_done;
   reg [1:0]           ddr2_calib_done_r;
 
   wire [30:0]         readfrom_af_addr;
   wire [30:0] 	       writeback_af_addr;
 
   wire [`DDR2_CACHE_NUM_LINES - 1 :0] 	cache_line_addr_validate;
   wire [`DDR2_CACHE_NUM_LINES - 1 :0] 	cache_line_addr_invalidate;
   wire [`DDR2_CACHE_NUM_LINES - 1 :0] 	cache_line_addr_valid;
   wire [`DDR2_CACHE_NUM_LINES - 1 :0] 	cache_line_hit;
   wire [`DDR2_CACHE_TAG_BITS] 	cache_line_addr [0:`DDR2_CACHE_NUM_LINES-1] ;
 
   // Cache control signals
   // Wishbone side
   wire [`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE-1:0] wb_cache_adr;
   wire [3:0] 			wb_cache_sel_we;
   // DDR side
   wire 			ddr2_cache_en;
   wire [15:0] 			ddr2_cache_we;
 
   reg 				wb_bursting; // Indicate if burst is enabled
   reg [3:0] 			wb_burst_addr; // Burst counter, up to 16
   wire [1:0] 			wb_burst_addr_4beat;
   wire [2:0] 			wb_burst_addr_8beat;
   wire 			wb_burst_addr_incr;
   wire 			ack_err;
   reg 				ack_err_r;
 
 
   // Synchronisation signals
   reg                          sync, sync_r;
   wire 			sync_start;
   wire 			sync_done;
 
   // Decoded select line
   wire [`DDR2_CACHE_NUM_LINES-1:0] selected_cache_line;
   wire [`DDR2_CACHE_NUM_LINES_ENC_WIDTH-1:0] selected_cache_line_enc;
 
   genvar 				      i;
   generate
      for (i=0;i<`DDR2_CACHE_NUM_LINES;i=i+1) begin : cache_addr
	 xilinx_ddr2_wb_if_cache_adr_reg cache_addr_reg_inst
	   ( .adr_i(wb_adr_i[`DDR2_CACHE_TAG_BITS]), 
	     .validate(cache_line_addr_validate[i]), 
	     .invalidate(cache_line_addr_invalidate[i]), 
	     .cache_hit(cache_line_hit[i]), 
	     .adr_valid(cache_line_addr_valid[i]),
	     .cached_adr_o(cache_line_addr[i]),
	     .clk(wb_clk), 
	     .rst(wb_rst));
      end   
   endgenerate
 
   wire start_writeback, start_fill;
 
   xilinx_ddr2_wb_if_cache_control xilinx_ddr2_wb_if_cache_control0
     (
      // Outputs
      .start_writeback			(start_writeback),
      .start_fill			(start_fill),
      .cache_line_validate		(cache_line_addr_validate),
      .cache_line_invalidate		(cache_line_addr_invalidate),
      .selected_cache_line		(selected_cache_line),
      .selected_cache_line_enc		(selected_cache_line_enc),
      .sync_done                        (sync_done),
      // Inputs
      .cache_line_addr_valid		(cache_line_addr_valid),
      .cache_line_addr_hit		(cache_line_hit),
      .wb_req				(wb_req),
      .cache_write			(cache_write),
      .writeback_done			(do_writeback_finished),
      .fill_done			(do_readfrom_finished),
      .sync_start                       (sync_start),
      .wb_clk				(wb_clk),
      .wb_rst				(wb_rst));
 
   defparam xilinx_ddr2_wb_if_cache_control0.num_lines = `DDR2_CACHE_NUM_LINES;
   defparam xilinx_ddr2_wb_if_cache_control0.num_lines_log2 = `DDR2_CACHE_NUM_LINES_ENC_WIDTH;
 
   assign cached_addr = selected_cache_line[0] ? cache_line_addr[0] :
			selected_cache_line[1] ? cache_line_addr[1] :
			selected_cache_line[2] ? cache_line_addr[2] :
			selected_cache_line[3] ? cache_line_addr[3] : 0;   
 
   assign cache_write = wb_req & wb_we_i & wb_ack_o;
 
   assign cache_hit = |(selected_cache_line & cache_line_hit);
 
   assign cached_addr_valid = |(selected_cache_line & cache_line_addr_valid);
 
   assign wb_req_addr_hit = (wb_req & cache_hit & cached_addr_valid);
 
   // Wishbone request detection
   assign wb_req = wb_stb_i & wb_cyc_i & ddr2_calib_done_r[0] & !sync;
 
   always @ (posedge wb_clk)
     ddr2_calib_done_r[1:0] <= {ddr2_calib_done, ddr2_calib_done_r[1]};
 
   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;
 
   always @(posedge wb_clk)
     if (wb_rst)
       wb_bursting <= 0;
   // Reset if acking end of transfer
     else if (wb_ack_o && wb_cti_i == 3'b111)
       wb_bursting <= 0;
   // Set if beginning new transaction and incrementing burst indicated
   // TODO - double check if this burst is going to go over a cache line
   // boundary - if so don't allow burst, fall back to classic cycles.
     else if (wb_req_new)
       wb_bursting <= (wb_cti_i == 3'b010);
 
   // Help constrain additions to appropriate bit-width for wrapping
   assign wb_burst_addr_4beat = wb_adr_i[3:2] + 1;
   assign wb_burst_addr_8beat = wb_adr_i[4:2] + 1;
 
   // Increment burst address whenever we get a hit when reading, or
   // when acking and writing.
   assign wb_burst_addr_incr = (wb_req_addr_hit & (!wb_we_i | 
						(wb_we_i & wb_ack_o)));
 
   // Calculate burst address depending on burst type indicator
   always @(posedge wb_clk)
     if (wb_rst)
       wb_burst_addr <= 0;
     else if (wb_req_new)
       // When we have a bursting read to an address which is in cache then
       // initialise the address to the next word in the burst sequence.
       // If it's a miss, or it's a write, then we just take what's on the
       // bus.
       wb_burst_addr <= !(wb_req_addr_hit & !wb_we_i) ? wb_adr_i[5:2] :
		    wb_bte_i==2'b01 ? {wb_adr_i[5:4], wb_burst_addr_4beat }:
		    wb_bte_i==2'b10 ? {wb_adr_i[5], wb_burst_addr_8beat }:
		    wb_bte_i==2'b11 ? wb_adr_i[5:2] + 1 :
		    wb_adr_i[5:2];
     else if (wb_burst_addr_incr & wb_bte_i==2'b01)
       wb_burst_addr[1:0] <= wb_burst_addr[1:0] + 1;
     else if (wb_burst_addr_incr & wb_bte_i==2'b10)
       wb_burst_addr[2:0] <= wb_burst_addr[2:0] + 1;
     else if (wb_burst_addr_incr & wb_bte_i==2'b11)
       wb_burst_addr[3:0] <= wb_burst_addr[3:0] + 1;
 
`ifdef ERR_COUNTER
   reg [26:0] ack_err_cntr;
 
   always @(posedge wb_clk)
     if (wb_rst)
       ack_err_cntr <= 0;
     else if (!wb_req)
       ack_err_cntr <= 0;
     else if (|ack_err_cntr)
       ack_err_cntr <= ack_err_cntr + 1;
     else if (wb_req_new & !(|ack_err_cntr))
       ack_err_cntr <= 1;
 
   assign ack_err = (&ack_err_cntr);
 
   always @(posedge wb_clk)
     ack_err_r <= ack_err;
 
   assign wb_err_o = ack_err_r;
 
`else // !`ifdef ERR_COUNTER
 
   assign ack_err = 0;
   always @(posedge wb_clk)
     ack_err_r <= 0;
 
   assign wb_err_o = 0;
 
`endif
 
   always @(posedge wb_clk)
     if (wb_rst)
       wb_ack_o <= 0;
     else
       wb_ack_o <= wb_req_addr_hit &
		   (
		    // Simple acks on classic cycles
		    (!wb_bursting && !wb_ack_o && !wb_ack_o_r)
		    // De-assert ack when we see the final transaction
		    || (wb_bursting && !(wb_cti_i==3'b111))
		    );
 
   always @(posedge wb_clk)
     wb_ack_o_r <= wb_ack_o;
 
   // Logic controling synchronisation
   always @(posedge wb_clk)
     if (wb_rst)
       sync <= 0;
     else if (sync_done) // Sync. done indicator from cache controller
       sync <= 0;
 
   always @(posedge wb_clk)
     sync_r <= sync;
 
   assign sync_start = sync & !sync_r;
 
   task do_sync;
      begin
	 // Wait for us to not be doing a transaction.
	 while(wb_req)
	   @wb_clk;
	 // Cache not busy, initiate sync.
	 sync = 1;
      end
   endtask // do_sync
 
   // Writeback/readfrom lower address generation
   always @(posedge wb_clk)
     if (wb_rst)
       addr_counter <= 0;
     else if (ddr2_p0_cmd_en)
       addr_counter <= addr_counter+1;
 
   // Determine if we're writing access requests into DDR2 interface AF
   always @(posedge wb_clk)
     if (wb_rst)
       do_af_write <= 0;
     else if (do_readfrom_start | do_writeback_data_finished)
       do_af_write <= 1;
     else if ((&addr_counter) & !ddr2_p0_cmd_full) // Stop when counter rolls over
       do_af_write <= 0;	 
 
   // Wishbone side of cache enable. Always enabled unless doing DDR2-side
   // things (fill or writeback).
   assign wb_cache_en =	!(do_readfrom | do_writeback);
 
 
   // Writeback detect logic
   always @(posedge wb_clk)
     if (wb_rst)
       do_writeback <= 0;
     else if (start_writeback)
       do_writeback <= 1;
     else if (&ddr2_cache_line_word_addr)
       do_writeback <= 0;
 
   always @(posedge wb_clk)
     do_writeback_r <= do_writeback;
 
   // Detect falling edge of do_writeback
   always @(posedge wb_clk)
     do_writeback_data_finished <= !do_writeback & do_writeback_r;
 
   always @(posedge wb_clk)
     if (wb_rst)
       do_writeback_addresses <= 0;
     else if (do_writeback_data_finished)
       do_writeback_addresses <= 1;
     else if ((&addr_counter) & !ddr2_p0_cmd_full)
       do_writeback_addresses <= 0;
 
   always @(posedge wb_clk)
     do_writeback_addresses_r <= do_writeback_addresses;
 
   // Detect rising edge of do_writeback
   assign do_writeback_start = do_writeback & !do_writeback_r;
   // Detect falling edge of address writing control signal
   assign do_writeback_finished = !do_writeback_addresses & 
				  do_writeback_addresses_r;
 
   // DDR2 Read detect logic
   always @(posedge wb_clk)
     if (wb_rst)
       do_readfrom <= 0;
     else if (start_fill)
       do_readfrom <= 1;
     else if ((&ddr2_cache_line_word_addr))
       do_readfrom <= 0;
 
   always @(posedge wb_clk)
     do_readfrom_r <= do_readfrom;
 
   // Detect line fill request rising edge
   assign do_readfrom_start = do_readfrom & !do_readfrom_r;
   // Detect line fill request falling edge
   assign do_readfrom_finished = !do_readfrom & do_readfrom_r;
   assign doing_readfrom = do_readfrom | do_readfrom_r;   
 
   // Address fifo signals
   assign ddr2_p0_cmd_en = ((do_readfrom_r & ddr2_p0_wr_empty) | (do_writeback_addresses_r & !ddr2_p0_wr_empty)) & 
                           !ddr2_p0_cmd_full & do_af_write;   
   assign ddr2_p0_cmd_instr[0] = doing_readfrom; // 1 - read, 0 - write
   assign ddr2_p0_cmd_instr[2:1] = 0;
 
   assign writeback_af_addr = {cached_addr, addr_counter, `DDR2_ADDR_ALIGN'd0};
 
   assign readfrom_af_addr = {wb_adr_i[`DDR2_CACHE_TAG_BITS], addr_counter, `DDR2_ADDR_ALIGN'd0};
 
   assign ddr2_p0_cmd_byte_addr = doing_readfrom ?  readfrom_af_addr : writeback_af_addr;
   assign ddr2_p0_wr_en         = do_writeback_ddr2_fifo_we;
   assign ddr2_p0_wr_data       = ddr2_cache_data_o;
   assign ddr2_p0_wr_mask       = 0;   
 
   always @(posedge wb_clk)
     if (wb_rst)
       ddr2_cache_line_word_addr <= 0;
     else if (!ddr2_p0_rd_empty | (do_writeback & !ddr2_p0_wr_full))
       ddr2_cache_line_word_addr <= ddr2_cache_line_word_addr + 1;
     else if (ddr2_write_done | ddr2_read_done)
       ddr2_cache_line_word_addr <= 0;
 
   always @(posedge wb_clk)
     do_writeback_ddr2_fifo_we <= (do_writeback & !ddr2_p0_wr_full);
 
   always @(posedge wb_clk)
     if (wb_rst)
       ddr2_write_done <= 0;
     else if ((&ddr2_cache_line_word_addr) & do_writeback)
       ddr2_write_done <= 1;
     else if (!do_writeback) // sample WB domain
       ddr2_write_done <= 0;
 
   always @(posedge wb_clk)
     rd_data_valid_r <= !ddr2_p0_rd_empty;
 
   // Read done signaling to WB domain
   always @(posedge wb_clk)
     if (wb_rst)
       ddr2_read_done <= 0;
     else if (rd_data_valid_r & (&ddr2_cache_line_word_addr))
       ddr2_read_done <= 1;
     else if (!do_readfrom) // Read WB domain
       ddr2_read_done <= 0;
 
   // Lower word address uses potentially bursting address counter
   assign wb_cache_adr = wb_bursting ?
       {wb_adr_i[(`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE+2)-1:6],wb_burst_addr}:
       wb_adr_i[(`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE+2)-1:2];
 
   assign wb_cache_sel_we = {4{wb_we_i & wb_ack_o}} & wb_sel_i;
   assign ddr2_cache_en = (!ddr2_p0_rd_empty |do_writeback);   
   assign ddr2_cache_we = {16{!ddr2_p0_rd_empty}};
 
   // Read enable always on
   assign ddr2_p0_rd_en = 1'b1;
 
`ifdef DDR2_BURSTLENGTH_1
   assign ddr2_p0_cmd_bl = 0; // burst of 1 * 128-bit
`elsif DDR2_BURSTLENGTH_2
   assign ddr2_p0_cmd_bl = 1; // burst of 2 * 128-bit
`elsif DDR2_BURSTLENGTH_4
   assign ddr2_p0_cmd_bl = 3; // burst of 4 * 128-bit
`elsif DDR2_BURSTLENGTH_8
   assign ddr2_p0_cmd_bl = 7; // burst of 8 * 128-bit
`elsif DDR2_BURSTLENGTH_16
   assign ddr2_p0_cmd_bl = 15; // burst of 16 * 128-bit
`endif   
 
   // Xilinx Coregen true dual-port RAMB
   // 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({2'd0, selected_cache_line_enc,wb_cache_adr}),
      .dina(wb_dat_i),
      .douta(wb_dat_o),
 
      // DDR2 controller side
      .clkb(wb_clk),
      .enb(ddr2_cache_en),
      .web(ddr2_cache_we),
      .addrb({2'd0, selected_cache_line_enc,
	      ddr2_cache_line_word_addr}),
      .dinb(ddr2_p0_rd_data),
      .doutb(ddr2_cache_data_o));
 
 ddr2_mig  #
  (
   .C3_P0_MASK_SIZE       (C3_P0_MASK_SIZE),
   .C3_P0_DATA_PORT_SIZE  (C3_P0_DATA_PORT_SIZE),
   .DEBUG_EN              (DEBUG_EN),       
   .C3_MEMCLK_PERIOD      (C3_MEMCLK_PERIOD),       
   .C3_CALIB_SOFT_IP      (C3_CALIB_SOFT_IP),       
   .C3_SIMULATION         (C3_SIMULATION),       
   .C3_RST_ACT_LOW        (C3_RST_ACT_LOW),       
   .C3_INPUT_CLK_TYPE     (C3_INPUT_CLK_TYPE),       
   .C3_MEM_ADDR_ORDER     (C3_MEM_ADDR_ORDER),       
   .C3_NUM_DQ_PINS        (C3_NUM_DQ_PINS),       
   .C3_MEM_ADDR_WIDTH     (C3_MEM_ADDR_WIDTH),       
   .C3_MEM_BANKADDR_WIDTH (C3_MEM_BANKADDR_WIDTH)       
   )
   ddr2_mig
   (
 
    .mcb3_dram_dq         (ddr2_dq),
    .mcb3_dram_a          (ddr2_a),
    .mcb3_dram_ba         (ddr2_ba),
    .mcb3_dram_ras_n      (ddr2_ras_n),
    .mcb3_dram_cas_n      (ddr2_cas_n),
    .mcb3_dram_we_n       (ddr2_we_n),
    .mcb3_dram_odt        (ddr2_odt),
    .mcb3_dram_cke        (ddr2_cke),
    .mcb3_dram_dm         (ddr2_dm),
    .mcb3_dram_udqs       (ddr2_udqs),        
    .mcb3_dram_udqs_n     (ddr2_udqs_n), 
    .mcb3_rzq             (ddr2_rzq),
    .mcb3_zio             (ddr2_zio),
    .mcb3_dram_udm        (ddr2_udm),
    .c3_sys_clk           (ddr2_if_clk),
    .c3_sys_rst_n         (ddr2_if_rst),
    .c3_calib_done        (ddr2_calib_done),
    .c3_clk0              (ddr2_clk),
    .c3_rst0              (ddr2_rst),
    .mcb3_dram_dqs        (ddr2_dqs),
    .mcb3_dram_dqs_n      (ddr2_dqs_n),
    .mcb3_dram_ck         (ddr2_ck),          
    .mcb3_dram_ck_n       (ddr2_ck_n),
    .c3_p0_cmd_clk        (wb_clk),
    .c3_p0_cmd_en         (ddr2_p0_cmd_en),
    .c3_p0_cmd_instr      (ddr2_p0_cmd_instr),
    .c3_p0_cmd_bl         (ddr2_p0_cmd_bl),
    .c3_p0_cmd_byte_addr  (ddr2_p0_cmd_byte_addr[29:0]),
    .c3_p0_cmd_empty      (ddr2_p0_cmd_empty),
    .c3_p0_cmd_full       (ddr2_p0_cmd_full),
    .c3_p0_wr_clk         (wb_clk),
    .c3_p0_wr_en          (ddr2_p0_wr_en),
    .c3_p0_wr_mask        (ddr2_p0_wr_mask),
    .c3_p0_wr_data        (ddr2_p0_wr_data),
    .c3_p0_wr_full        (ddr2_p0_wr_full),
    .c3_p0_wr_empty       (ddr2_p0_wr_empty),
    .c3_p0_wr_count       (ddr2_p0_wr_count),
    .c3_p0_wr_underrun    (ddr2_p0_wr_underrun),
    .c3_p0_wr_error       (ddr2_p0_wr_error),
    .c3_p0_rd_clk         (wb_clk),
    .c3_p0_rd_en          (ddr2_p0_rd_en),
    .c3_p0_rd_data        (ddr2_p0_rd_data),
    .c3_p0_rd_full        (ddr2_p0_rd_full),
    .c3_p0_rd_empty       (ddr2_p0_rd_empty),
    .c3_p0_rd_count       (ddr2_p0_rd_count),
    .c3_p0_rd_overflow    (ddr2_p0_rd_overflow),
    .c3_p0_rd_error       (ddr2_p0_rd_error)
   );
 
endmodule // xilinx_ddr2_if2
 
// Local Variables:
// verilog-library-directories:("." "ddr2_mig")
// verilog-library-extensions:(".v" ".h")
// End:
 
 
module xilinx_ddr2_wb_if_cache_adr_reg
  (adr_i, validate, invalidate,
   cached_adr_o, cache_hit, adr_valid,
   clk, rst);
 
   parameter full_adr_width = 32;
   parameter word_adr_width = 2; // 4 bytes per word   
   parameter line_adr_width = 8; // 256 words per "line"
 
   parameter tag_width = full_adr_width - line_adr_width - word_adr_width;
 
 
   input [full_adr_width-1: word_adr_width + line_adr_width] adr_i;
   input 		 validate;
   input 		 invalidate;
   output [full_adr_width-1: word_adr_width + line_adr_width] cached_adr_o;   
   output 		  cache_hit;
   output reg 		  adr_valid;
 
   input 		  clk, rst;
 
   reg [tag_width-1:0] 	  cached_adr;
 
   assign cached_adr_o = cached_adr;   
 
   always @(posedge clk)
     if (rst)
       cached_adr <= 0;
     else if (validate)
       cached_adr <= adr_i;
 
   always @(posedge clk)
     if (rst)
       adr_valid <= 0;
     else if (validate)
       adr_valid <= 1;
     else if (invalidate)
       adr_valid <= 0;
 
   assign cache_hit = (adr_i == cached_adr);
 
endmodule // xilinx_ddr2_wb_if_cache_adr_reg
 
module xilinx_ddr2_wb_if_cache_control
  ( cache_line_addr_valid, cache_line_addr_hit,
    wb_req,
    cache_write,
    writeback_done, fill_done,
    sync_start, sync_done,
    start_writeback, start_fill,
    cache_line_validate, cache_line_invalidate,   
    selected_cache_line, selected_cache_line_enc,
    wb_clk, wb_rst);
 
   parameter num_lines = 16;
   parameter num_lines_log2 = 4;
 
   input [num_lines-1:0] cache_line_addr_valid;
   input [num_lines-1:0] cache_line_addr_hit;
 
   input 		 wb_req;
   input 		 cache_write;   
   input 		 writeback_done, fill_done;
 
   input 		 sync_start;
   output 		 sync_done;
 
   output reg 		 start_writeback;
   output reg 		 start_fill;
   output reg [num_lines-1:0] cache_line_validate;
   output reg [num_lines-1:0] cache_line_invalidate;
 
   output [num_lines-1:0]     selected_cache_line;
   output reg [num_lines_log2-1:0] selected_cache_line_enc;
 
   input 			   wb_clk, wb_rst;
 
   reg [num_lines-1:0] 		   lines_dirty;
 
   reg [num_lines-1:0] 		   selected_cache_line_from_miss;
 
   reg 				   selected_cache_line_new;
 
   reg 				   invalidate_clean_line;
 
   reg [num_lines-1:0] 		   selected_cache_line_r;
   reg [num_lines-1:0] 		   selected_cache_line_r2;   
 
   reg 				   wb_req_r;
 
   wire 			   wb_req_new;
   reg 				   wb_req_new_r;
 
   parameter sync_line_check_wait = 4;
   reg [num_lines-1:0] 		   sync_line_counter;
   reg 				   sync_doing;
   reg [sync_line_check_wait-1:0]  sync_line_select_wait_counter_shr;
   reg 				   sync_line_done;
   wire 			   sync_writeback_line;
 
 
   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;
 
   // Select a cache line when we miss. Currently very simply is round robin
   always @(posedge wb_clk)
     if (wb_rst)
       selected_cache_line_from_miss <= 1;
     else if (wb_req_new_r & !(|selected_cache_line_r)) // miss,no line selected
       // Shift select bit one
       selected_cache_line_from_miss 
	 <= {selected_cache_line_from_miss[num_lines-2:0], 
	     selected_cache_line_from_miss[num_lines-1]};
 
 
   // Line selection logic, when line address is valid and hit, we select
   always @(posedge wb_clk)
     if (wb_rst)
       selected_cache_line_r <= 0;   
     else if (wb_req_new)
       selected_cache_line_r <= cache_line_addr_valid & cache_line_addr_hit;
     else if (wb_req_new_r & !(|selected_cache_line_r))
       selected_cache_line_r <= selected_cache_line_from_miss;
     else if (sync_doing)
       selected_cache_line_r <= sync_line_counter;
 
   always @(posedge wb_clk)
     selected_cache_line_r2 <= selected_cache_line_r;
 
   assign selected_cache_line = selected_cache_line_r2;   
 
   // A new line of cache has been selected
   always @(posedge wb_clk)
     if (wb_rst)
       selected_cache_line_new <= 0;
     else if (wb_req_new & (&(cache_line_addr_valid & cache_line_addr_hit)))
       // New line address selected
       selected_cache_line_new <= 1;
     else if ((!selected_cache_line_new) & wb_req_new_r)
       // Didn't select one last time, so we must have forced ourselves to 
       // select a new one
       selected_cache_line_new <= 1;
     else if (selected_cache_line_new)
       selected_cache_line_new <= 0;
 
   always @(posedge wb_clk)
     if (wb_rst)
       lines_dirty <= 0;
     else if (cache_write)
       lines_dirty <= lines_dirty | selected_cache_line_r;
     else if (writeback_done)
       lines_dirty <= lines_dirty & ~(selected_cache_line_r);
 
   // Validate the cache line address in the register when line filled
   always @(posedge wb_clk)
     if (wb_rst)
       cache_line_validate <= 0;
     else if (fill_done)
       cache_line_validate <= selected_cache_line_r;
     else if (|cache_line_validate)
       cache_line_validate <= 0;
 
   // Invalidate the cache line address in the register when line written back
   always @(posedge wb_clk)
     if (wb_rst)
       cache_line_invalidate <= 0;
     else if ((writeback_done & !sync_doing) | invalidate_clean_line)
       cache_line_invalidate <= selected_cache_line_r;
     else if (|cache_line_invalidate)
       cache_line_invalidate <= 0;
 
   // Initiate-writeback logic
   always @(posedge wb_clk)
     if (wb_rst)
       start_writeback <= 0;
     else if (start_writeback)
       start_writeback <= 0;
     else if (selected_cache_line_new & 
	      (|(lines_dirty & selected_cache_line_r)) &
	      (|(selected_cache_line_r & cache_line_addr_valid)) & 
	      !(|(cache_line_addr_hit & selected_cache_line_r)))
       start_writeback <= 1;
     else if (sync_writeback_line)
       start_writeback <= 1;
 
   // Invalidate lines which we haven't written to so we can fill them
   always @(posedge wb_clk)
     if (wb_rst)
       invalidate_clean_line <= 0;
     else if (invalidate_clean_line)
       invalidate_clean_line <= 0;
     else if ((selected_cache_line_new) &  // New line selected
	      !(|(lines_dirty & selected_cache_line_r)) & // It's not dirty
	      // It's valid, but we've selected it so we're trashing it
	      (|(selected_cache_line_r & cache_line_addr_valid)) & 
	      !(|(cache_line_addr_hit & selected_cache_line_r))) // Not a hit
       invalidate_clean_line <= 1;
 
   reg 			  invalidate_clean_line_r;   
   always @(posedge wb_clk)
     invalidate_clean_line_r <= invalidate_clean_line;
 
 
   // Initiate-fill logic
   always @(posedge wb_clk)
     if (wb_rst)
       start_fill <= 0;
     else if (((selected_cache_line_new) & // New line selected
	       // not valid
	       !(|(cache_line_addr_valid & selected_cache_line_r))) | 
	      (writeback_done & !sync_doing) | invalidate_clean_line_r
	      )
       start_fill <= 1;
     else if (start_fill)
       start_fill <= 0;
 
   // Hardcoded to 4 lines currently.
   always @(posedge wb_clk)
     if (selected_cache_line_r[0])
       selected_cache_line_enc <= 0;
     else if (selected_cache_line_r[1])
       selected_cache_line_enc <= 1;	     
     else if (selected_cache_line_r[2])
       selected_cache_line_enc <= 2;	     
     else if (selected_cache_line_r[3])
       selected_cache_line_enc <= 3;
 
 
   // Synchronisation control
 
   always @(posedge wb_clk)
     if (wb_rst)
       sync_doing <= 0;
     else if (sync_start)
       sync_doing <= 1;
     else if (sync_done)
       sync_doing <= 0;
 
   always @(posedge wb_clk)
     if (wb_rst)
       sync_line_counter <= 0;
     else if (sync_start)
       // Set first line to check
       sync_line_counter[0] <= 1'b1;
     else if (sync_line_done)
       // Shift along, check next line
       sync_line_counter <=  {sync_line_counter[num_lines-2:0], 1'b0};
 
   // Pulse this on finishing of checking lines
   assign sync_done = sync_line_counter[num_lines-1] & sync_line_done;
 
   // Pulses when a dirty line is detected and should be written back.
   assign sync_writeback_line = sync_doing & 
				sync_line_select_wait_counter_shr[0] & 
				cache_line_addr_valid &
				|(sync_line_counter & lines_dirty);
 
   always @(posedge wb_clk)
     if (wb_rst)
       sync_line_select_wait_counter_shr <= 0;
     else if (|sync_line_select_wait_counter_shr)
       sync_line_select_wait_counter_shr
	 <= {1'b0,sync_line_select_wait_counter_shr[sync_line_check_wait-1:1]};
     else if (sync_start | (sync_line_done & !sync_done))
       sync_line_select_wait_counter_shr[sync_line_check_wait-1] <= 1'b1;
 
   always @(posedge wb_clk)
     if (wb_rst)
       sync_line_done <= 1'b0;
     else if (sync_line_done)
       sync_line_done <= 1'b0;   
   // Either line doesn't need writeback
     else if (sync_line_select_wait_counter_shr[0] & !sync_writeback_line)
       sync_line_done <= 1'b1;
   // Or writeback finished
     else if  (writeback_done & sync_doing)
       sync_line_done <= 1'b1;
 
 
endmodule // xilinx_ddr2_wb_if_cache_control
 

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.