URL
https://opencores.org/ocsvn/usb_fpga_2_14/usb_fpga_2_14/trunk
Subversion Repositories usb_fpga_2_14
[/] [usb_fpga_2_14/] [trunk/] [examples/] [memfifo/] [fpga-2.14/] [memfifo.srcs/] [sources_1/] [ip/] [mig_7series_0/] [mig_7series_0/] [user_design/] [rtl/] [ui/] [mig_7series_v2_3_ui_wr_data.v] - Rev 2
Compare with Previous | Blame | View Log
//***************************************************************************** // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. // // This file contains confidential and proprietary information // of Xilinx, Inc. and is protected under U.S. and // international copyright and other intellectual property // laws. // // DISCLAIMER // This disclaimer is not a license and does not grant any // rights to the materials distributed herewith. Except as // otherwise provided in a valid license issued to you by // Xilinx, and to the maximum extent permitted by applicable // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and // (2) Xilinx shall not be liable (whether in contract or tort, // including negligence, or under any other theory of // liability) for any loss or damage of any kind or nature // related to, arising under or in connection with these // materials, including for any direct, or any indirect, // special, incidental, or consequential loss or damage // (including loss of data, profits, goodwill, or any type of // loss or damage suffered as a result of any action brought // by a third party) even if such damage or loss was // reasonably foreseeable or Xilinx had been advised of the // possibility of the same. // // CRITICAL APPLICATIONS // Xilinx products are not designed or intended to be fail- // safe, or for use in any application requiring fail-safe // performance, such as life-support or safety devices or // systems, Class III medical devices, nuclear facilities, // applications related to the deployment of airbags, or any // other applications that could lead to death, personal // injury, or severe property or environmental damage // (individually and collectively, "Critical // Applications"). Customer assumes the sole risk and // liability of any use of Xilinx products in Critical // Applications, subject only to applicable laws and // regulations governing limitations on product liability. // // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS // PART OF THIS FILE AT ALL TIMES. // //***************************************************************************** // ____ ____ // / /\/ / // /___/ \ / Vendor : Xilinx // \ \ \/ Version : %version // \ \ Application : MIG // / / Filename : ui_wr_data.v // /___/ /\ Date Last Modified : $date$ // \ \ / \ Date Created : Tue Jun 30 2009 // \___\/\___\ // //Device : 7-Series //Design Name : DDR3 SDRAM //Purpose : //Reference : //Revision History : //***************************************************************************** // User interface write data buffer. Consists of four counters, // a pointer RAM and the write data storage RAM. // // All RAMs are implemented with distributed RAM. // // Whe ordering is set to STRICT or NORM, data moves through // the write data buffer in strictly FIFO order. In RELAXED // mode, data may be retired from the write data RAM in any // order relative to the input order. This implementation // supports all ordering modes. // // The pointer RAM stores a list of pointers to the write data storage RAM. // This is a list of vacant entries. As data is written into the RAM, a // pointer is pulled from the pointer RAM and used to index the write // operation. In a semi autonomously manner, pointers are also pulled, in // the same order, and provided to the command port as the data_buf_addr. // // When the MC reads data from the write data buffer, it uses the // data_buf_addr provided with the command to extract the data from the // write data buffer. It also writes this pointer into the end // of the pointer RAM. // // The occupancy counter keeps track of how many entries are valid // in the write data storage RAM. app_wdf_rdy and app_rdy will be // de-asserted when there is no more storage in the write data buffer. // // Three sequentially incrementing counters/indexes are used to maintain // and use the contents of the pointer RAM. // // The write buffer write data address index generates the pointer // used to extract the write data address from the pointer RAM. It // is incremented with each buffer write. The counter is actually one // ahead of the current write address so that the actual data buffer // write address can be registered to give a full state to propagate to // the write data distributed RAMs. // // The data_buf_addr counter is used to extract the data_buf_addr for // the command port. It is incremented as each command is written // into the MC. // // The read data index points to the end of the list of free // buffers. When the MC fetches data from the write data buffer, it // provides the buffer address. The buffer address is used to fetch // the data, but is also written into the pointer at the location indicated // by the read data index. // // Enter and exiting a buffer full condition generates corner cases. Upon // entering a full condition, incrementing the write buffer write data // address index must be inhibited. When exiting the full condition, // the just arrived pointer must propagate through the pointer RAM, then // indexed by the current value of the write buffer write data // address counter, the value is registered in the write buffer write // data address register, then the counter can be advanced. // // The pointer RAM must be initialized with valid data after reset. This is // accomplished by stepping through each pointer RAM entry and writing // the locations address into the pointer RAM. For the FIFO modes, this means // that buffer address will always proceed in a sequential order. In the // RELAXED mode, the original write traversal will be in sequential // order, but once the MC begins to retire out of order, the entries in // the pointer RAM will become randomized. The ui_rd_data module provides // the control information for the initialization process. `timescale 1 ps / 1 ps module mig_7series_v2_3_ui_wr_data # ( parameter TCQ = 100, parameter APP_DATA_WIDTH = 256, parameter APP_MASK_WIDTH = 32, parameter ECC = "OFF", parameter nCK_PER_CLK = 2 , parameter ECC_TEST = "OFF", parameter CWL = 5 ) (/*AUTOARG*/ // Outputs app_wdf_rdy, wr_req_16, wr_data_buf_addr, wr_data, wr_data_mask, raw_not_ecc, // Inputs rst, clk, app_wdf_data, app_wdf_mask, app_raw_not_ecc, app_wdf_wren, app_wdf_end, wr_data_offset, wr_data_addr, wr_data_en, wr_accepted, ram_init_done_r, ram_init_addr ); input rst; input clk; input [APP_DATA_WIDTH-1:0] app_wdf_data; input [APP_MASK_WIDTH-1:0] app_wdf_mask; input [2*nCK_PER_CLK-1:0] app_raw_not_ecc; input app_wdf_wren; input app_wdf_end; reg [APP_DATA_WIDTH-1:0] app_wdf_data_r1; reg [APP_MASK_WIDTH-1:0] app_wdf_mask_r1; reg [2*nCK_PER_CLK-1:0] app_raw_not_ecc_r1 = 4'b0; reg app_wdf_wren_r1; reg app_wdf_end_r1; reg app_wdf_rdy_r; //Adding few copies of the app_wdf_rdy_r signal in order to meet //timing. This is signal has a very high fanout. So grouped into //few functional groups and alloted one copy per group. (* equivalent_register_removal = "no" *) reg app_wdf_rdy_r_copy1; (* equivalent_register_removal = "no" *) reg app_wdf_rdy_r_copy2; (* equivalent_register_removal = "no" *) reg app_wdf_rdy_r_copy3; (* equivalent_register_removal = "no" *) reg app_wdf_rdy_r_copy4; wire [APP_DATA_WIDTH-1:0] app_wdf_data_ns1 = ~app_wdf_rdy_r_copy2 ? app_wdf_data_r1 : app_wdf_data; wire [APP_MASK_WIDTH-1:0] app_wdf_mask_ns1 = ~app_wdf_rdy_r_copy2 ? app_wdf_mask_r1 : app_wdf_mask; wire app_wdf_wren_ns1 = ~rst && (~app_wdf_rdy_r_copy2 ? app_wdf_wren_r1 : app_wdf_wren); wire app_wdf_end_ns1 = ~rst && (~app_wdf_rdy_r_copy2 ? app_wdf_end_r1 : app_wdf_end); generate if (ECC_TEST != "OFF") begin : ecc_on always @(app_raw_not_ecc) app_raw_not_ecc_r1 = app_raw_not_ecc; end endgenerate // Be explicit about the latch enable on these registers. always @(posedge clk) begin app_wdf_data_r1 <= #TCQ app_wdf_data_ns1; app_wdf_mask_r1 <= #TCQ app_wdf_mask_ns1; app_wdf_wren_r1 <= #TCQ app_wdf_wren_ns1; app_wdf_end_r1 <= #TCQ app_wdf_end_ns1; end // The signals wr_data_addr and wr_data_offset come at different // times depending on ECC and the value of CWL. The data portion // always needs to look a the raw wires, the control portion needs // to look at a delayed version when ECC is on and CWL != 8. The // currently supported write data delays do not require this // functionality, but preserve for future use. input wr_data_offset; input [3:0] wr_data_addr; reg wr_data_offset_r; reg [3:0] wr_data_addr_r; generate if (ECC == "OFF" || CWL >= 0) begin : pass_wr_addr always @(wr_data_offset) wr_data_offset_r = wr_data_offset; always @(wr_data_addr) wr_data_addr_r = wr_data_addr; end else begin : delay_wr_addr always @(posedge clk) wr_data_offset_r <= #TCQ wr_data_offset; always @(posedge clk) wr_data_addr_r <= #TCQ wr_data_addr; end endgenerate // rd_data_cnt is the pointer RAM index for data read from the write data // buffer. Ie, its the data on its way out to the DRAM. input wr_data_en; wire new_rd_data = wr_data_en && ~wr_data_offset_r; reg [3:0] rd_data_indx_r; reg rd_data_upd_indx_r; generate begin : read_data_indx reg [3:0] rd_data_indx_ns; always @(/*AS*/new_rd_data or rd_data_indx_r or rst) begin rd_data_indx_ns = rd_data_indx_r; if (rst) rd_data_indx_ns = 5'b0; else if (new_rd_data) rd_data_indx_ns = rd_data_indx_r + 5'h1; end always @(posedge clk) rd_data_indx_r <= #TCQ rd_data_indx_ns; always @(posedge clk) rd_data_upd_indx_r <= #TCQ new_rd_data; end endgenerate // data_buf_addr_cnt generates the pointer for the pointer RAM on behalf // of data buf address that comes with the wr_data_en. // The data buf address is written into the memory // controller along with the command and address. input wr_accepted; reg [3:0] data_buf_addr_cnt_r; generate begin : data_buf_address_counter reg [3:0] data_buf_addr_cnt_ns; always @(/*AS*/data_buf_addr_cnt_r or rst or wr_accepted) begin data_buf_addr_cnt_ns = data_buf_addr_cnt_r; if (rst) data_buf_addr_cnt_ns = 4'b0; else if (wr_accepted) data_buf_addr_cnt_ns = data_buf_addr_cnt_r + 4'h1; end always @(posedge clk) data_buf_addr_cnt_r <= #TCQ data_buf_addr_cnt_ns; end endgenerate // Control writing data into the write data buffer. wire wdf_rdy_ns; always @( posedge clk ) begin app_wdf_rdy_r_copy1 <= #TCQ wdf_rdy_ns; app_wdf_rdy_r_copy2 <= #TCQ wdf_rdy_ns; app_wdf_rdy_r_copy3 <= #TCQ wdf_rdy_ns; app_wdf_rdy_r_copy4 <= #TCQ wdf_rdy_ns; end wire wr_data_end = app_wdf_end_r1 && app_wdf_rdy_r_copy1 && app_wdf_wren_r1; wire [3:0] wr_data_pntr; wire [4:0] wb_wr_data_addr; wire [4:0] wb_wr_data_addr_w; reg [3:0] wr_data_indx_r; generate begin : write_data_control wire wr_data_addr_le = (wr_data_end && wdf_rdy_ns) || (rd_data_upd_indx_r && ~app_wdf_rdy_r_copy1); // For pointer RAM. Initialize to one since this is one ahead of // what's being registered in wb_wr_data_addr. Assumes pointer RAM // has been initialized such that address equals contents. reg [3:0] wr_data_indx_ns; always @(/*AS*/rst or wr_data_addr_le or wr_data_indx_r) begin wr_data_indx_ns = wr_data_indx_r; if (rst) wr_data_indx_ns = 4'b1; else if (wr_data_addr_le) wr_data_indx_ns = wr_data_indx_r + 4'h1; end always @(posedge clk) wr_data_indx_r <= #TCQ wr_data_indx_ns; // Take pointer from pointer RAM and set into the write data address. // Needs to be split into zeroth bit and everything else because synthesis // tools don't always allow assigning bit vectors seperately. Bit zero of the // address is computed via an entirely different algorithm. reg [4:1] wb_wr_data_addr_ns; reg [4:1] wb_wr_data_addr_r; always @(/*AS*/rst or wb_wr_data_addr_r or wr_data_addr_le or wr_data_pntr) begin wb_wr_data_addr_ns = wb_wr_data_addr_r; if (rst) wb_wr_data_addr_ns = 4'b0; else if (wr_data_addr_le) wb_wr_data_addr_ns = wr_data_pntr; end always @(posedge clk) wb_wr_data_addr_r <= #TCQ wb_wr_data_addr_ns; // If we see the first getting accepted, then // second half is unconditionally accepted. reg wb_wr_data_addr0_r; wire wb_wr_data_addr0_ns = ~rst && ((app_wdf_rdy_r_copy3 && app_wdf_wren_r1 && ~app_wdf_end_r1) || (wb_wr_data_addr0_r && ~app_wdf_wren_r1)); always @(posedge clk) wb_wr_data_addr0_r <= #TCQ wb_wr_data_addr0_ns; assign wb_wr_data_addr = {wb_wr_data_addr_r, wb_wr_data_addr0_r}; assign wb_wr_data_addr_w = {wb_wr_data_addr_ns, wb_wr_data_addr0_ns}; end endgenerate // Keep track of how many entries in the queue hold data. input ram_init_done_r; output wire app_wdf_rdy; generate begin : occupied_counter //reg [4:0] occ_cnt_ns; //reg [4:0] occ_cnt_r; //always @(/*AS*/occ_cnt_r or rd_data_upd_indx_r or rst // or wr_data_end) begin // occ_cnt_ns = occ_cnt_r; // if (rst) occ_cnt_ns = 5'b0; // else case ({wr_data_end, rd_data_upd_indx_r}) // 2'b01 : occ_cnt_ns = occ_cnt_r - 5'b1; // 2'b10 : occ_cnt_ns = occ_cnt_r + 5'b1; // endcase // case ({wr_data_end, rd_data_upd_indx_r}) //end //always @(posedge clk) occ_cnt_r <= #TCQ occ_cnt_ns; //assign wdf_rdy_ns = !(rst || ~ram_init_done_r || occ_cnt_ns[4]); //always @(posedge clk) app_wdf_rdy_r <= #TCQ wdf_rdy_ns; //assign app_wdf_rdy = app_wdf_rdy_r; reg [15:0] occ_cnt; always @(posedge clk) begin if ( rst ) occ_cnt <= #TCQ 16'h0000; else case ({wr_data_end, rd_data_upd_indx_r}) 2'b01 : occ_cnt <= #TCQ {1'b0,occ_cnt[15:1]}; 2'b10 : occ_cnt <= #TCQ {occ_cnt[14:0],1'b1}; endcase // case ({wr_data_end, rd_data_upd_indx_r}) end assign wdf_rdy_ns = !(rst || ~ram_init_done_r || (occ_cnt[14] && wr_data_end && ~rd_data_upd_indx_r) || (occ_cnt[15] && ~rd_data_upd_indx_r)); always @(posedge clk) app_wdf_rdy_r <= #TCQ wdf_rdy_ns; assign app_wdf_rdy = app_wdf_rdy_r; `ifdef MC_SVA wr_data_buffer_full: cover property (@(posedge clk) (~rst && ~app_wdf_rdy_r)); // wr_data_buffer_inc_dec_15: cover property (@(posedge clk) // (~rst && wr_data_end && rd_data_upd_indx_r && (occ_cnt_r == 5'hf))); // wr_data_underflow: assert property (@(posedge clk) // (rst || !((occ_cnt_r == 5'b0) && (occ_cnt_ns == 5'h1f)))); // wr_data_overflow: assert property (@(posedge clk) // (rst || !((occ_cnt_r == 5'h10) && (occ_cnt_ns == 5'h11)))); `endif end // block: occupied_counter endgenerate // Keep track of how many write requests are in the memory controller. We // must limit this to 16 because we only have that many data_buf_addrs to // hand out. Since the memory controller queue and the write data buffer // queue are distinct, the number of valid entries can be different. // Throttle request acceptance once there are sixteen write requests in // the memory controller. Note that there is still a requirement // for a write reqeusts corresponding write data to be written into the // write data queue with two states of the request. output wire wr_req_16; generate begin : wr_req_counter reg [4:0] wr_req_cnt_ns; reg [4:0] wr_req_cnt_r; always @(/*AS*/rd_data_upd_indx_r or rst or wr_accepted or wr_req_cnt_r) begin wr_req_cnt_ns = wr_req_cnt_r; if (rst) wr_req_cnt_ns = 5'b0; else case ({wr_accepted, rd_data_upd_indx_r}) 2'b01 : wr_req_cnt_ns = wr_req_cnt_r - 5'b1; 2'b10 : wr_req_cnt_ns = wr_req_cnt_r + 5'b1; endcase // case ({wr_accepted, rd_data_upd_indx_r}) end always @(posedge clk) wr_req_cnt_r <= #TCQ wr_req_cnt_ns; assign wr_req_16 = (wr_req_cnt_ns == 5'h10); `ifdef MC_SVA wr_req_mc_full: cover property (@(posedge clk) (~rst && wr_req_16)); wr_req_mc_full_inc_dec_15: cover property (@(posedge clk) (~rst && wr_accepted && rd_data_upd_indx_r && (wr_req_cnt_r == 5'hf))); wr_req_underflow: assert property (@(posedge clk) (rst || !((wr_req_cnt_r == 5'b0) && (wr_req_cnt_ns == 5'h1f)))); wr_req_overflow: assert property (@(posedge clk) (rst || !((wr_req_cnt_r == 5'h10) && (wr_req_cnt_ns == 5'h11)))); `endif end // block: wr_req_counter endgenerate // Instantiate pointer RAM. Made up of RAM32M in single write, two read // port mode, 2 bit wide mode. input [3:0] ram_init_addr; output wire [3:0] wr_data_buf_addr; localparam PNTR_RAM_CNT = 2; generate begin : pointer_ram wire pointer_we = new_rd_data || ~ram_init_done_r; wire [3:0] pointer_wr_data = ram_init_done_r ? wr_data_addr_r : ram_init_addr; wire [3:0] pointer_wr_addr = ram_init_done_r ? rd_data_indx_r : ram_init_addr; genvar i; for (i=0; i<PNTR_RAM_CNT; i=i+1) begin : rams RAM32M #(.INIT_A(64'h0000000000000000), .INIT_B(64'h0000000000000000), .INIT_C(64'h0000000000000000), .INIT_D(64'h0000000000000000) ) RAM32M0 ( .DOA(), .DOB(wr_data_buf_addr[i*2+:2]), .DOC(wr_data_pntr[i*2+:2]), .DOD(), .DIA(2'b0), .DIB(pointer_wr_data[i*2+:2]), .DIC(pointer_wr_data[i*2+:2]), .DID(2'b0), .ADDRA(5'b0), .ADDRB({1'b0, data_buf_addr_cnt_r}), .ADDRC({1'b0, wr_data_indx_r}), .ADDRD({1'b0, pointer_wr_addr}), .WE(pointer_we), .WCLK(clk) ); end // block : rams end // block: pointer_ram endgenerate // Instantiate write data buffer. Depending on width of DQ bus and // DRAM CK to fabric ratio, number of RAM32Ms is variable. RAM32Ms are // used in single write, single read, 6 bit wide mode. localparam WR_BUF_WIDTH = APP_DATA_WIDTH + APP_MASK_WIDTH + (ECC_TEST == "OFF" ? 0 : 2*nCK_PER_CLK); localparam FULL_RAM_CNT = (WR_BUF_WIDTH/6); localparam REMAINDER = WR_BUF_WIDTH % 6; localparam RAM_CNT = FULL_RAM_CNT + ((REMAINDER == 0 ) ? 0 : 1); localparam RAM_WIDTH = (RAM_CNT*6); wire [RAM_WIDTH-1:0] wr_buf_out_data_w; reg [RAM_WIDTH-1:0] wr_buf_out_data; generate begin : write_buffer wire [RAM_WIDTH-1:0] wr_buf_in_data; if (REMAINDER == 0) if (ECC_TEST == "OFF") assign wr_buf_in_data = {app_wdf_mask_ns1, app_wdf_data_ns1}; else assign wr_buf_in_data = {app_raw_not_ecc_r1, app_wdf_mask_ns1, app_wdf_data_ns1}; else if (ECC_TEST == "OFF") assign wr_buf_in_data = {{6-REMAINDER{1'b0}}, app_wdf_mask_ns1, app_wdf_data_ns1}; else assign wr_buf_in_data = {{6-REMAINDER{1'b0}}, app_raw_not_ecc_r1,//app_raw_not_ecc_r1 is not ff app_wdf_mask_ns1, app_wdf_data_ns1}; wire [4:0] rd_addr_w; assign rd_addr_w = {wr_data_addr, wr_data_offset}; always @(posedge clk) wr_buf_out_data <= #TCQ wr_buf_out_data_w; genvar i; for (i=0; i<RAM_CNT; i=i+1) begin : wr_buffer_ram RAM32M #(.INIT_A(64'h0000000000000000), .INIT_B(64'h0000000000000000), .INIT_C(64'h0000000000000000), .INIT_D(64'h0000000000000000) ) RAM32M0 ( .DOA(wr_buf_out_data_w[((i*6)+4)+:2]), .DOB(wr_buf_out_data_w[((i*6)+2)+:2]), .DOC(wr_buf_out_data_w[((i*6)+0)+:2]), .DOD(), .DIA(wr_buf_in_data[((i*6)+4)+:2]), .DIB(wr_buf_in_data[((i*6)+2)+:2]), .DIC(wr_buf_in_data[((i*6)+0)+:2]), .DID(2'b0), .ADDRA(rd_addr_w), .ADDRB(rd_addr_w), .ADDRC(rd_addr_w), .ADDRD(wb_wr_data_addr_w), .WE(wdf_rdy_ns), .WCLK(clk) ); end // block: wr_buffer_ram end endgenerate output [APP_DATA_WIDTH-1:0] wr_data; output [APP_MASK_WIDTH-1:0] wr_data_mask; assign {wr_data_mask, wr_data} = wr_buf_out_data[WR_BUF_WIDTH-1:0]; output [2*nCK_PER_CLK-1:0] raw_not_ecc; generate if (ECC_TEST == "OFF") assign raw_not_ecc = {2*nCK_PER_CLK{1'b0}}; else assign raw_not_ecc = wr_buf_out_data[WR_BUF_WIDTH-1-:(2*nCK_PER_CLK)]; endgenerate endmodule // ui_wr_data // Local Variables: // verilog-library-directories:(".") // End: