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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [boards/] [xilinx/] [s3adsp1800/] [rtl/] [verilog/] [xilinx_s3adsp_ddr2/] [xilinx_s3adsp_ddr2_if.v] - Rev 592

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

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  Xilinx Spartan 3A DSP DDR2 controller from MIG              ////
////                                                              ////
////  Description                                                 ////
////                                                              ////
////  To Do:                                                      ////
////   Employ LRU replacement scheme                              ////
////   Remove hard-coding of things relating to number of lines   ////
////                                                              ////
////  Author(s):                                                  ////
////      - Julius Baxter, julius@opencores.org                   ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2011 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                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
// Cache generated by coregen, uses 2x18kbit block RAMS, or 4KByte
// Currently only using 4 lines x 8 words * 32-bits (4bytes) = 128 bytes
// Could potentially have up to (4096/(8*4)) 128 lines.
 
// Addressing for DDR2 interface is as follows.
// SDRAM is 128MB, so up to 0x08000000 (28 bits)
// DDR2 MIG configured in burst length of 8 (8*32 per request)
// DDR2 MIG takes 25 bit address (row[12:0],col[9:0],ba[1:0])
 
// So for every address on DDR2 MIG address interface, we get 8*32-bit words
// or (8*4) 32 bytes. 5-bits of address on the Wishbone bus.
 
// Current setting is just 4-lines of cache with 8-words per line
// We'll have 3-bits for words in the line.
// Tag will be 28-3-2 (final 2 is due to 4-bytes per word) so 23-bits.
 
// So address to the DDR2 interface should be the 23 bits of tag, and 2'b00
// for the 4 column addresses we burst over.
 
 
module xilinx_s3adsp_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,
 
    inout [31:0]  ddr2_dq,
    output [12:0] ddr2_a,
    output [1:0]  ddr2_ba,
    output 	  ddr2_cke,
    output 	  ddr2_cs_n,
    output 	  ddr2_ras_n,
    output 	  ddr2_cas_n,
    output 	  ddr2_we_n,
    output 	  ddr2_odt,
    output [3:0]  ddr2_dm,
    inout [3:0]   ddr2_dqs,
    inout [3:0]   ddr2_dqs_n,
    output [1:0]  ddr2_ck,
    output [1:0]  ddr2_ck_n,
    input 	  ddr2_rst_dqs_div_in,
    output 	  ddr2_rst_dqs_div_out,
    input 	  clk133_i,
 
    input 	  wb_clk,
    input 	  wb_rst);
 
 
   // 128MB, so 0x800_0000
`define ADDR_BIT_MAX 28
 
/*
`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_LINES 32
//`define DDR2_CACHE_NUM_LINES_ENC_WIDTH 5 // log2(`DDR2_CACHE_NUM_LINES)
 
 
`define DDR2_CACHE_NUM_WORDS_PER_LINE 8
`define DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE 3
`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/2)
`define DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE (`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE - 1)
`define DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH (`DDR2_CACHE_NUM_LINES_ENC_WIDTH + `DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE)
 
`define BYTES_PER_WORD 4
`define BYTES_PER_WORD_ADDR_WIDTH 2
 
   // Board has 128MB of memory, so highest address is 27'h7ff_ffff
`define DDR2_CACHE_TAG_BITS (`ADDR_BIT_MAX-1):(`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE + \
				`BYTES_PER_WORD_ADDR_WIDTH)
 
 
   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 [`DDR2_CACHE_TAG_BITS] cache_line_tag;
 
   wire 		       cache_write;
 
   wire 		       cache_hit;
 
   wire 		       wb_cache_en;
 
   reg 			       do_writeback;   
 
   reg 			       do_readfrom;
   reg 			       do_readfrom_ddr2_sync, do_readfrom_ddr2_sync2, 
			       do_readfrom_ddr2_sync3;
   wire 		       do_readfrom_start_ddr2;
 
   reg 			       do_writeback_ddr2_sync, do_writeback_ddr2_sync2, 
			       do_writeback_ddr2_sync3;
   wire 		       do_writeback_start_ddr2;
 
   reg 			       ddr2_readfrom_done;
   reg 			       wb_readfrom_done_sync,wb_readfrom_done_sync2;
   wire 		       wb_readfrom_done;
 
   reg 			       ddr2_writeback_done;
   reg 			       wb_writeback_done_sync,wb_writeback_done_sync2;
   wire 		       wb_writeback_done;
 
   reg 			       ddr2_readfrom_done_wb_sync, ddr2_readfrom_done_wb_sync2;
   reg 			       ddr2_writeback_done_wb_sync, ddr2_writeback_done_wb_sync2;
 
 
   wire 		       ddr2_if_clk_90;
   wire 		       ddr2_if_clk;
   wire 		       ddr2_rst, ddr2_rst_90, ddr2_rst_180;
   reg [24:0] 		       ddr2_if_input_address;
   wire [63:0] 		       ddr2_if_wdata;
   wire [63:0] 		       ddr2_if_rdata;
   wire 		       ddr2_if_rdata_valid;
   reg [2:0] 		       ddr2_if_cmd;
 
   wire 		       ddr2_if_ref_req, ddr2_if_cmd_ack;
   wire 		       ddr2_if_af_done, ddr2_if_burst_done;
   reg 			       ddr2_if_init_sent;
 
 
   // [0] - Waiting for ddr2_if_cmd_ack
   // [4:1] - data0-data3 out from RAM
   // [8:5] - ddr2_if_burst_done high for 4 cycles
   // [9] - finish
   reg [9:0] 		       ddr2_write_state_shr;
 
   // [0] - waiting for ddr2_if_cmd_ack
   // [4:1] - asserting ddr2_if_burst_done
   // [5] - waiting for ddr2_if_cmd_ack to be deasserted
   // [6] - finish
   reg [6:0] 		       ddr2_read_state_shr;
 
   reg [4:0] 		       ddr2_read_dv_counter_shr;
 
 
   wire 		       phy_init_done;
 
   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 [3:0] 			       wb_cache_sel_we;
   // DDR side
   wire 			       ddr2_cache_en;
   wire [7:0] 			       ddr2_cache_we;
 
   reg 				       wb_bursting; // Are we bursting?
   reg [2:0] 			       wb_burst_addr; // Burst counter, up to 8
   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;
 
   wire [`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE-1:0] wb_cache_word;
 
   // 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;
   reg [`DDR2_CACHE_NUM_LINES_ENC_WIDTH-1:0] 	    selected_cache_line_enc_ddr2_if_clk;
 
   reg 						    ddr2_cache_line_word_use_next_addr;
   wire [`DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE - 1:0] ddr2_cache_line_word_addr;
   reg [`DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE - 1:0] ddr2_cache_line_word_addr_r;
   wire [`DDR2_CACHE_DDR2_SIDE_ADDR_WIDTH_NUM_WORDS_PER_LINE - 1:0] ddr2_cache_line_word_addr_next;
 
 
   genvar 							   i;
   generate
      for (i=0;i<`DDR2_CACHE_NUM_LINES;i=i+1) begin : cache_addr
	 ddr2_wb_if_cache_addr_reg
	     #(.full_addr_width(28), // 128MB
	       .line_addr_width(`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE))
	 cache_addr_reg_inst
	     ( .addr_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]), 
	       .addr_valid(cache_line_addr_valid[i]),
	       .cached_addr_o(cache_line_addr[i]),
	       .clk(wb_clk), 
	       .rst(wb_rst));
      end   
   endgenerate
 
   wire start_writeback, start_fill;
 
   ddr2_wb_if_cache_control 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			(wb_writeback_done),
      .fill_done			(wb_readfrom_done),
      .sync_start                       (sync_start),
      .wb_clk				(wb_clk),
      .wb_rst				(wb_rst));
 
   defparam ddr2_wb_if_cache_control0.num_lines = `DDR2_CACHE_NUM_LINES;
   defparam ddr2_wb_if_cache_control0.num_lines_log2 = `DDR2_CACHE_NUM_LINES_ENC_WIDTH;
 
   assign cache_line_tag = 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] :
			   /*
			   selected_cache_line[4] ? cache_line_addr[4] :
			   selected_cache_line[5] ? cache_line_addr[5] :
			   selected_cache_line[6] ? cache_line_addr[6] :
			   selected_cache_line[7] ? cache_line_addr[7] :
			   selected_cache_line[8] ? cache_line_addr[8] :
			   selected_cache_line[9] ? cache_line_addr[9] :
			   selected_cache_line[10] ? cache_line_addr[10] :
			   selected_cache_line[11] ? cache_line_addr[11] :
			   selected_cache_line[12] ? cache_line_addr[12] :
			   selected_cache_line[13] ? cache_line_addr[13] :
			   selected_cache_line[14] ? cache_line_addr[14] :
			   selected_cache_line[15] ? cache_line_addr[15] :
			   selected_cache_line[16] ? cache_line_addr[16] :
			   selected_cache_line[17] ? cache_line_addr[17] :
			   selected_cache_line[18] ? cache_line_addr[18] :
			   selected_cache_line[19] ? cache_line_addr[19] :
			   selected_cache_line[20] ? cache_line_addr[20] :
			   selected_cache_line[21] ? cache_line_addr[21] :
			   selected_cache_line[22] ? cache_line_addr[22] :
			   selected_cache_line[23] ? cache_line_addr[23] :
			   selected_cache_line[24] ? cache_line_addr[24] :
			   selected_cache_line[25] ? cache_line_addr[25] :
			   selected_cache_line[26] ? cache_line_addr[26] :
			   selected_cache_line[27] ? cache_line_addr[27] :
			   selected_cache_line[28] ? cache_line_addr[28] :
			   selected_cache_line[29] ? cache_line_addr[29] :
			   selected_cache_line[30] ? cache_line_addr[30] :
			   selected_cache_line[31] ? cache_line_addr[31] :
			    */
			   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 & phy_init_done & !sync; 
 
   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[4:2] :
		    wb_bte_i==2'b01 ? {wb_adr_i[4], wb_burst_addr_4beat }:
		    wb_bte_i==2'b10 ? {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;
   */
   assign ack_err = 0;
   always @(posedge wb_clk)
     ack_err_r <= 0;
 
   assign wb_err_o = 0;
 
 
   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
 
   // 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 (wb_writeback_done)
       do_writeback <= 0;
     else if (start_writeback)
       do_writeback <= 1;
 
   // DDR2 Read detect logic
   always @(posedge wb_clk)
     if (wb_rst)
       do_readfrom <= 0;
     else if (wb_readfrom_done)
       do_readfrom <= 0;
     else if (start_fill)
       do_readfrom <= 1;
 
   // Domain cross of WB control signals
   always @(negedge ddr2_if_clk) begin
      do_writeback_ddr2_sync <= do_writeback;
      do_writeback_ddr2_sync2 <= do_writeback_ddr2_sync;
      do_writeback_ddr2_sync3 <= do_writeback_ddr2_sync2;
      do_readfrom_ddr2_sync <= do_readfrom;
      do_readfrom_ddr2_sync2 <= do_readfrom_ddr2_sync;
      do_readfrom_ddr2_sync3 <= do_readfrom_ddr2_sync2;
   end
 
   assign do_readfrom_start_ddr2 = !do_readfrom_ddr2_sync3 & 
				   do_readfrom_ddr2_sync2;
 
   assign do_writeback_start_ddr2 = !do_writeback_ddr2_sync3 & 
				   do_writeback_ddr2_sync2;
 
   always @(negedge ddr2_if_clk)
     if (ddr2_rst)
       ddr2_readfrom_done <= 0;
     else if (ddr2_readfrom_done_wb_sync2)
       ddr2_readfrom_done <= 0;
     else if (ddr2_read_state_shr[6])
       ddr2_readfrom_done <= 1;
 
   // Get readfrom_done into Wishbone domain
   always @(posedge wb_clk)
     if (wb_rst) begin
	wb_readfrom_done_sync <= 0;
	wb_readfrom_done_sync2 <= 0;
     end 
     else begin
	wb_readfrom_done_sync <= ddr2_readfrom_done;
	wb_readfrom_done_sync2 <= wb_readfrom_done_sync;
     end
 
   assign wb_readfrom_done = !wb_readfrom_done_sync2 & wb_readfrom_done_sync;
 
   // Read this back to DDR2 domain
   always @(negedge ddr2_if_clk)
     if (ddr2_rst) begin
	ddr2_readfrom_done_wb_sync <= 0;
	ddr2_readfrom_done_wb_sync2 <= 0;
     end
     else begin
	ddr2_readfrom_done_wb_sync <= wb_readfrom_done_sync2;
	ddr2_readfrom_done_wb_sync2 <= ddr2_readfrom_done_wb_sync;
     end
 
 
   // Writeback finished/done logic
   always @(negedge ddr2_if_clk)
     if (ddr2_rst)
       ddr2_writeback_done <= 0;
     else if (ddr2_writeback_done_wb_sync2)
       ddr2_writeback_done <= 0;
     else if (ddr2_write_state_shr[6])
       ddr2_writeback_done <= 1;
 
   // Get writeback_done into Wishbone domain
   always @(posedge wb_clk)
     if (wb_rst) begin
	wb_writeback_done_sync <= 0;
	wb_writeback_done_sync2 <= 0;
     end 
     else begin
	wb_writeback_done_sync <= ddr2_writeback_done;
	wb_writeback_done_sync2 <= wb_writeback_done_sync;
     end
 
   assign wb_writeback_done = !wb_writeback_done_sync2 & wb_writeback_done_sync;
 
   // Read this back to DDR2 domain
   always @(negedge ddr2_if_clk)
     if (ddr2_rst) begin
	ddr2_writeback_done_wb_sync <= 0;
	ddr2_writeback_done_wb_sync2 <= 0;
     end
     else begin
	ddr2_writeback_done_wb_sync <= wb_writeback_done_sync2;
	ddr2_writeback_done_wb_sync2 <= ddr2_writeback_done_wb_sync;
     end
 
 
   // Have we passed init command to the controller?
   always @(negedge ddr2_if_clk or posedge ddr2_rst_180)
     if (ddr2_rst_180)
       ddr2_if_init_sent <= 0;
     else if (!ddr2_rst & !ddr2_rst_90 & !ddr2_rst_180 & !ddr2_if_init_sent)
       ddr2_if_init_sent <= 1;
 
   // MIG Command
   always @(negedge ddr2_if_clk or posedge ddr2_rst_180)
     if (ddr2_rst_180)
       ddr2_if_cmd <= 3'b000;
     else if (!phy_init_done) begin
	if (!ddr2_rst & !ddr2_rst_90 & !ddr2_rst_180 & !ddr2_if_init_sent)
	  ddr2_if_cmd <= 3'b010; // Init
	else
	  ddr2_if_cmd <= 3'b000; // NOP
     end
     else if ((ddr2_if_cmd==3'b000) & do_writeback_ddr2_sync2 &
	      !ddr2_if_cmd_ack & !(|ddr2_write_state_shr[9:1]) & !ddr2_writeback_done)
       ddr2_if_cmd <= 3'b100;  // Write
     else if (ddr2_write_state_shr[6]) // End of write
       ddr2_if_cmd <= 3'b000; // NOP
     else if ((ddr2_if_cmd==3'b000) & do_readfrom_ddr2_sync2 &
	      !ddr2_if_cmd_ack & !(|ddr2_read_state_shr[6:1]) & !ddr2_readfrom_done)
       ddr2_if_cmd <= 3'b110;  // Read
     else if (ddr2_read_state_shr[3])
       ddr2_if_cmd <= 3'b000; // NOP
 
   // State shift register
   // [0] - Waiting for ddr2_if_cmd_ack
   // [4:1] - data0-data3 out from RAM
   // [8:5] - ddr2_if_burst_done high for 4 cycles
   // [9] - waiting for ddr2_if_cmd_ack to be deasserted
   always @(negedge ddr2_if_clk or posedge ddr2_rst_180)
     if (ddr2_rst_180)
       ddr2_write_state_shr <= 0;
     else if (!(|ddr2_write_state_shr) & !ddr2_if_cmd_ack &
	      do_writeback_start_ddr2 & !ddr2_writeback_done )
       ddr2_write_state_shr <=  1;
     else if (((|ddr2_write_state_shr[8:0]) & ddr2_if_cmd_ack) |
	      (ddr2_write_state_shr[9] & !ddr2_if_cmd_ack))
       ddr2_write_state_shr <= {ddr2_write_state_shr[8:0],1'b0};
 
   // [0] - waiting for ddr2_if_cmd_ack
   // [4:1] - asserting ddr2_if_burst_done
   // [5] - waiting for ddr2_if_cmd_ack to be deasserted
   // [6] - finish
   always @(negedge ddr2_if_clk or posedge ddr2_rst_180)
     if (ddr2_rst_180)
       ddr2_read_state_shr <= 0;
     else if (!(|ddr2_read_state_shr) & do_readfrom_ddr2_sync2 & 
	      !ddr2_if_cmd_ack & !ddr2_readfrom_done)
       ddr2_read_state_shr <= 1; // Start read
     else if ((ddr2_read_state_shr[0] & ddr2_if_cmd_ack) |
	      (|ddr2_read_state_shr[4:1]) | ddr2_read_state_shr[6] |
	      (ddr2_read_state_shr[5] & !ddr2_if_cmd_ack & !(|ddr2_read_dv_counter_shr)))
       ddr2_read_state_shr <= {ddr2_read_state_shr[6:0],1'b0};
 
   always @(posedge ddr2_if_clk_90 or posedge ddr2_rst_90)
     if (ddr2_rst_90)
       ddr2_read_dv_counter_shr <= 0;
     else if (do_readfrom_start_ddr2)
       ddr2_read_dv_counter_shr <= 1;
     else if (ddr2_read_dv_counter_shr[4] & !ddr2_if_cmd_ack)
       ddr2_read_dv_counter_shr <= 0;
     else if (ddr2_if_rdata_valid)
       ddr2_read_dv_counter_shr <= {ddr2_read_dv_counter_shr[3:0],1'b0};
 
 
   assign ddr2_cache_line_word_addr_next = ddr2_cache_line_word_addr_r + 1;
 
   always @(posedge ddr2_if_clk_90 or posedge ddr2_rst_90)
     if (ddr2_rst_90)
       ddr2_cache_line_word_addr_r <= 0;
     else if (do_writeback_ddr2_sync2) begin
	// Write
	if (do_writeback_start_ddr2)
	  ddr2_cache_line_word_addr_r <= 0;
	else if (ddr2_write_state_shr[4:1])
	  ddr2_cache_line_word_addr_r <= ddr2_cache_line_word_addr_next;
     end
     else if (do_readfrom_ddr2_sync2) begin
	// Read
	if (do_readfrom_start_ddr2)
	  ddr2_cache_line_word_addr_r <= 0;
	else if (ddr2_if_rdata_valid)
	  ddr2_cache_line_word_addr_r <= ddr2_cache_line_word_addr_next;
     end
 
   always @(posedge ddr2_if_clk_90 or posedge ddr2_rst_90)
     if (ddr2_rst_90)
       ddr2_cache_line_word_use_next_addr <= 0;
     else
       ddr2_cache_line_word_use_next_addr <= ((|ddr2_write_state_shr) & ddr2_if_cmd_ack);
 
   // Cache line word address to DDR2-side of cache. When writing, need address earlier,
   // so use the combinatorial value, otherwise the registered value.
   assign ddr2_cache_line_word_addr = ddr2_cache_line_word_use_next_addr  ?
				      ddr2_cache_line_word_addr_next : 
				      ddr2_cache_line_word_addr_r;
 
 
   assign ddr2_if_burst_done = (|ddr2_write_state_shr[7:4]) |
			       (|ddr2_read_state_shr[4:1]);
 
   // Lower word address uses potentially bursting address counter
   assign wb_cache_word = wb_bursting ?
			  wb_burst_addr :
			  wb_adr_i[(`DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE+2)-1:2];
/*		
 Here `DDR2_CACHE_ADDR_WIDTH_WORDS_PER_LINE==3, which is < width of wb_burst_addr
 so just use wb_burst_addr.
 If cache lines get longer, would have to do something like this.
       {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_if_rdata_valid |do_writeback_ddr2_sync3);
   assign ddr2_cache_we = {8{ddr2_if_rdata_valid}};
 
   always @(negedge ddr2_if_clk)
      selected_cache_line_enc_ddr2_if_clk <= selected_cache_line_enc;
 
   always @(negedge ddr2_if_clk) 
     if (do_writeback_start_ddr2)
       ddr2_if_input_address <= {cache_line_tag,3'd0};
     else if (do_readfrom_start_ddr2)
       ddr2_if_input_address <= {wb_adr_i[`DDR2_CACHE_TAG_BITS],3'd0};
 
 
 
    // True dual port ram, with dual aspect ration
   // Wishbone side - 32-bit, DDR2 side - 64-bit
   // Is 4KByte, so WB addr is 10-bits, DDR2 9-bits
   s3adsp_ddr2_cache s3adsp_ddr2_cache
     (
      // A-side - Wishbone
      .clka(wb_clk),
      .ena(wb_cache_en),
      .wea(({4{wb_cache_en}}&wb_cache_sel_we)),
      .addra({5'd0,selected_cache_line_enc,wb_cache_word}),
      .dina(wb_dat_i),
      .douta(wb_dat_o),
 
      // B-side - DDR2
      .clkb(ddr2_if_clk_90),
      .enb(ddr2_cache_en),
      .web(ddr2_cache_we),
      .addrb({5'd0,selected_cache_line_enc_ddr2_if_clk,ddr2_cache_line_word_addr}),
      .dinb(ddr2_if_rdata),
      .doutb(ddr2_if_wdata)
      );
 
   s3adsp_ddr2 s3adsp_ddr2
     (
      .cntrl0_ddr2_dq(ddr2_dq),
      .cntrl0_ddr2_a(ddr2_a),
      .cntrl0_ddr2_ba(ddr2_ba),
      .cntrl0_ddr2_cke(ddr2_cke),
      .cntrl0_ddr2_cs_n(ddr2_cs_n),
      .cntrl0_ddr2_ras_n(ddr2_ras_n),
      .cntrl0_ddr2_cas_n(ddr2_cas_n),
      .cntrl0_ddr2_we_n(ddr2_we_n),
      .cntrl0_ddr2_odt(ddr2_odt),
      .cntrl0_ddr2_dm(ddr2_dm),
      .cntrl0_rst_dqs_div_in(ddr2_rst_dqs_div_in),
      .cntrl0_rst_dqs_div_out(ddr2_rst_dqs_div_out),
      .sys_clk_in(clk133_i),
      .reset_in_n(~wb_rst),
 
      .cntrl0_burst_done(ddr2_if_burst_done),
      .cntrl0_init_done(phy_init_done),
      .cntrl0_ar_done(ddr2_if_af_done),
      .cntrl0_user_data_valid(ddr2_if_rdata_valid),
 
      .cntrl0_auto_ref_req(ddr2_if_ref_req),
      .cntrl0_user_cmd_ack(ddr2_if_cmd_ack),
      .cntrl0_user_command_register(ddr2_if_cmd),
 
      .cntrl0_clk_tb(ddr2_if_clk),
      .cntrl0_clk90_tb(ddr2_if_clk_90),
 
      .cntrl0_sys_rst_tb(ddr2_rst),
      .cntrl0_sys_rst90_tb(ddr2_rst_90),
      .cntrl0_sys_rst180_tb(ddr2_rst_180),
 
      .cntrl0_user_data_mask(8'h00),
      .cntrl0_user_output_data(ddr2_if_rdata),
      .cntrl0_user_input_data(ddr2_if_wdata),
      .cntrl0_user_input_address({ddr2_if_input_address[22:0],
				  ddr2_if_input_address[24:23]}),
      .cntrl0_ddr2_dqs(ddr2_dqs),
      .cntrl0_ddr2_dqs_n(ddr2_dqs_n),
      .cntrl0_ddr2_ck(ddr2_ck),
      .cntrl0_ddr2_ck_n(ddr2_ck_n)
   );
 
endmodule // xilinx_s3adsp_ddr2_if2
 
 
// Local Variables:
// verilog-library-directories:("." "ddr2_mig")
// verilog-library-extensions:(".v" ".h")
// End:
 
 
module ddr2_wb_if_cache_addr_reg
  (addr_i, validate, invalidate,
   cached_addr_o, cache_hit, addr_valid,
   clk, rst);
 
   parameter full_addr_width = 32;
   parameter word_addr_width = 2; // 4 bytes per word   
   parameter line_addr_width = 5; // 32 words per "line"
 
   parameter tag_width = full_addr_width - line_addr_width - word_addr_width;
 
 
   input [full_addr_width-1: word_addr_width + line_addr_width] addr_i;
   input 		 validate;
   input 		 invalidate;
   output [full_addr_width-1: word_addr_width + line_addr_width] cached_addr_o;   
   output 		  cache_hit;
   output reg 		  addr_valid;
 
   input 		  clk, rst;
 
   reg [tag_width-1:0] 	  cached_adr;
 
   assign cached_addr_o = cached_adr;   
 
   always @(posedge clk)
     if (rst)
       cached_adr <= 0;
     else if (validate)
       cached_adr <= addr_i;
 
   always @(posedge clk)
     if (rst)
       addr_valid <= 0;
     else if (validate)
       addr_valid <= 1;
     else if (invalidate)
       addr_valid <= 0;
 
   assign cache_hit = (addr_i == cached_adr);
 
endmodule // ddr2_wb_if_cache_addr_reg
 
module 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 = 4;
   parameter num_lines_log2 = 2;
 
   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 is very simple round robin
   // TODO - if clean lines available on miss, evict them before causing a
   // writeback, to save time on cache miss.
   // TOOD - would benefit a lot from a LRU scheme.
   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;
   /*
     else if (selected_cache_line_r[4])
       selected_cache_line_enc <= 4;
     else if (selected_cache_line_r[5])
       selected_cache_line_enc <= 5;
     else if (selected_cache_line_r[6])
       selected_cache_line_enc <= 6;
     else if (selected_cache_line_r[7])
       selected_cache_line_enc <= 7;
     else if (selected_cache_line_r[8])
       selected_cache_line_enc <= 8;
     else if (selected_cache_line_r[9])
       selected_cache_line_enc <= 9;
     else if (selected_cache_line_r[10])
       selected_cache_line_enc <= 10;
     else if (selected_cache_line_r[11])
       selected_cache_line_enc <= 11;
     else if (selected_cache_line_r[12])
       selected_cache_line_enc <= 12;
     else if (selected_cache_line_r[13])
       selected_cache_line_enc <= 13;
     else if (selected_cache_line_r[14])
       selected_cache_line_enc <= 14;
     else if (selected_cache_line_r[15])
       selected_cache_line_enc <= 15;
     else if (selected_cache_line_r[16])
       selected_cache_line_enc <= 16;
     else if (selected_cache_line_r[17])
       selected_cache_line_enc <= 17;
     else if (selected_cache_line_r[18])
       selected_cache_line_enc <= 18;
     else if (selected_cache_line_r[19])
       selected_cache_line_enc <= 19;
     else if (selected_cache_line_r[20])
       selected_cache_line_enc <= 20;
     else if (selected_cache_line_r[21])
       selected_cache_line_enc <= 21;
     else if (selected_cache_line_r[22])
       selected_cache_line_enc <= 22;
     else if (selected_cache_line_r[23])
       selected_cache_line_enc <= 23;
     else if (selected_cache_line_r[24])
       selected_cache_line_enc <= 24;
     else if (selected_cache_line_r[25])
       selected_cache_line_enc <= 25;
     else if (selected_cache_line_r[26])
       selected_cache_line_enc <= 26;
     else if (selected_cache_line_r[27])
       selected_cache_line_enc <= 27;
     else if (selected_cache_line_r[28])
       selected_cache_line_enc <= 28;
     else if (selected_cache_line_r[29])
       selected_cache_line_enc <= 29;
     else if (selected_cache_line_r[30])
       selected_cache_line_enc <= 30;
     else if (selected_cache_line_r[31])
       selected_cache_line_enc <= 31;
    */
   // 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 // ddr2_wb_if_cache_control
 

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.