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 858
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